Massive refactoring of all code + audio skeleton.

This should make it easier to find files and (in the future) split things
up into separate libraries.
It also changes around emulator initialization to make it a little more
difficult to do things out of order and a little more sensible as to when
real init work happens.
Also adding a skeleton audio system/driver and reworking CPU register
access to be more extensible.
This commit is contained in:
Ben Vanik
2013-10-23 20:42:24 -07:00
parent c996a4bbaf
commit b7ffd46319
182 changed files with 3919 additions and 3286 deletions

View File

@@ -0,0 +1,42 @@
/**
******************************************************************************
* 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/xboxkrnl/async_request.h>
#include <xenia/kernel/xboxkrnl/xobject.h>
#include <xenia/kernel/xboxkrnl/objects/xevent.h>
using namespace std;
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl;
XAsyncRequest::XAsyncRequest(
KernelState* kernel_state, XObject* object,
CompletionCallback callback, void* callback_context) :
kernel_state_(kernel_state), object_(object),
callback_(callback), callback_context_(callback_context),
apc_routine_(0), apc_context_(0) {
object_->Retain();
}
XAsyncRequest::~XAsyncRequest() {
for (vector<XEvent*>::iterator it = wait_events_.begin();
it != wait_events_.end(); ++it) {
(*it)->Release();
}
object_->Release();
}
void XAsyncRequest::AddWaitEvent(XEvent* ev) {
ev->Retain();
wait_events_.push_back(ev);
}

View File

@@ -0,0 +1,61 @@
/**
******************************************************************************
* 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_ASYNC_REQUEST_H_
#define XENIA_KERNEL_XBOXKRNL_ASYNC_REQUEST_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/xbox.h>
namespace xe {
namespace kernel {
namespace xboxkrnl {
class KernelState;
class XEvent;
class XObject;
class XAsyncRequest {
public:
typedef void (*CompletionCallback)(XAsyncRequest* request, void* context);
XAsyncRequest(
KernelState* kernel_state, XObject* object,
CompletionCallback callback, void* callback_context);
virtual ~XAsyncRequest();
KernelState* kernel_state() const { return kernel_state_; }
XObject* object() const { return object_; }
void AddWaitEvent(XEvent* ev);
// Complete(result)
protected:
KernelState* kernel_state_;
XObject* object_;
CompletionCallback callback_;
void* callback_context_;
std::vector<XEvent*> wait_events_;
uint32_t apc_routine_;
uint32_t apc_context_;
};
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_ASYNC_REQUEST_H_

View File

@@ -0,0 +1,28 @@
/**
******************************************************************************
* 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/xboxkrnl/fs/device.h>
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl::fs;
Device::Device(const char* path) {
path_ = xestrdupa(path);
}
Device::~Device() {
xe_free(path_);
}
const char* Device::path() {
return path_;
}

View File

@@ -0,0 +1,45 @@
/**
******************************************************************************
* 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_FS_DEVICE_H_
#define XENIA_KERNEL_XBOXKRNL_FS_DEVICE_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/kernel/xboxkrnl/fs/entry.h>
namespace xe {
namespace kernel {
namespace xboxkrnl {
namespace fs {
class Device {
public:
Device(const char* path);
virtual ~Device();
const char* path();
virtual Entry* ResolvePath(const char* path) = 0;
protected:
char* path_;
};
} // namespace fs
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_FS_DEVICE_H_

View File

@@ -0,0 +1,98 @@
/**
******************************************************************************
* 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/xboxkrnl/fs/devices/disc_image_device.h>
#include <xenia/kernel/xboxkrnl/fs/gdfx.h>
#include <xenia/kernel/xboxkrnl/fs/devices/disc_image_entry.h>
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl::fs;
DiscImageDevice::DiscImageDevice(const char* path, const xechar_t* local_path) :
Device(path) {
local_path_ = xestrdup(local_path);
mmap_ = NULL;
gdfx_ = NULL;
}
DiscImageDevice::~DiscImageDevice() {
delete gdfx_;
xe_mmap_release(mmap_);
xe_free(local_path_);
}
int DiscImageDevice::Init() {
mmap_ = xe_mmap_open(kXEFileModeRead, local_path_, 0, 0);
if (!mmap_) {
XELOGE("Disc image could not be mapped");
return 1;
}
gdfx_ = new GDFX(mmap_);
GDFX::Error error = gdfx_->Load();
if (error != GDFX::kSuccess) {
XELOGE("GDFX init failed: %d", error);
return 1;
}
//gdfx_->Dump();
return 0;
}
Entry* DiscImageDevice::ResolvePath(const char* path) {
// The filesystem will have stripped our prefix off already, so the path will
// be in the form:
// some\PATH.foo
XELOGFS("DiscImageDevice::ResolvePath(%s)", path);
GDFXEntry* gdfx_entry = gdfx_->root_entry();
// Walk the path, one separator at a time.
// We copy it into the buffer and shift it left over and over.
char remaining[XE_MAX_PATH];
XEIGNORE(xestrcpya(remaining, XECOUNT(remaining), path));
while (remaining[0]) {
char* next_slash = xestrchra(remaining, '\\');
if (next_slash == remaining) {
// Leading slash - shift
XEIGNORE(xestrcpya(remaining, XECOUNT(remaining), remaining + 1));
continue;
}
// Make the buffer just the name.
if (next_slash) {
*next_slash = 0;
}
// Look up in the entry.
gdfx_entry = gdfx_entry->GetChild(remaining);
if (!gdfx_entry) {
// Not found.
return NULL;
}
// Shift the buffer down, unless we are at the end.
if (!next_slash) {
break;
}
XEIGNORE(xestrcpya(remaining, XECOUNT(remaining), next_slash + 1));
}
Entry::Type type = gdfx_entry->attributes & X_FILE_ATTRIBUTE_DIRECTORY ?
Entry::kTypeDirectory : Entry::kTypeFile;
return new DiscImageEntry(
type, this, path, mmap_, gdfx_entry);
}

View File

@@ -0,0 +1,50 @@
/**
******************************************************************************
* 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_FS_DEVICES_DISC_IMAGE_DEVICE_H_
#define XENIA_KERNEL_XBOXKRNL_FS_DEVICES_DISC_IMAGE_DEVICE_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/kernel/xboxkrnl/fs/device.h>
namespace xe {
namespace kernel {
namespace xboxkrnl {
namespace fs {
class GDFX;
class DiscImageDevice : public Device {
public:
DiscImageDevice(const char* path, const xechar_t* local_path);
virtual ~DiscImageDevice();
int Init();
virtual Entry* ResolvePath(const char* path);
private:
xechar_t* local_path_;
xe_mmap_ref mmap_;
GDFX* gdfx_;
};
} // namespace fs
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_FS_DEVICES_DISC_IMAGE_DEVICE_H_

View File

@@ -0,0 +1,89 @@
/**
******************************************************************************
* 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/xboxkrnl/fs/devices/disc_image_entry.h>
#include <xenia/kernel/xboxkrnl/fs/gdfx.h>
#include <xenia/kernel/xboxkrnl/fs/devices/disc_image_file.h>
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl;
using namespace xe::kernel::xboxkrnl::fs;
namespace {
class DiscImageMemoryMapping : public MemoryMapping {
public:
DiscImageMemoryMapping(uint8_t* address, size_t length, xe_mmap_ref mmap) :
MemoryMapping(address, length) {
mmap_ = xe_mmap_retain(mmap);
}
virtual ~DiscImageMemoryMapping() {
xe_mmap_release(mmap_);
}
private:
xe_mmap_ref mmap_;
};
}
DiscImageEntry::DiscImageEntry(Type type, Device* device, const char* path,
xe_mmap_ref mmap, GDFXEntry* gdfx_entry) :
gdfx_entry_(gdfx_entry),
Entry(type, device, path) {
mmap_ = xe_mmap_retain(mmap);
}
DiscImageEntry::~DiscImageEntry() {
xe_mmap_release(mmap_);
}
X_STATUS DiscImageEntry::QueryInfo(XFileInfo* out_info) {
XEASSERTNOTNULL(out_info);
out_info->creation_time = 0;
out_info->last_access_time = 0;
out_info->last_write_time = 0;
out_info->change_time = 0;
out_info->allocation_size = 2048;
out_info->file_length = gdfx_entry_->size;
out_info->attributes = gdfx_entry_->attributes;
return X_STATUS_SUCCESS;
}
MemoryMapping* DiscImageEntry::CreateMemoryMapping(
xe_file_mode file_mode, const size_t offset, const size_t length) {
if (file_mode & kXEFileModeWrite) {
// Only allow reads.
return NULL;
}
size_t real_offset = gdfx_entry_->offset + offset;
size_t real_length = length ?
MIN(length, gdfx_entry_->size) : gdfx_entry_->size;
return new DiscImageMemoryMapping(
xe_mmap_get_addr(mmap_) + real_offset,
real_length,
mmap_);
}
X_STATUS DiscImageEntry::Open(
KernelState* kernel_state,
uint32_t desired_access, bool async,
XFile** out_file) {
*out_file = new DiscImageFile(kernel_state, desired_access, this);
return X_STATUS_SUCCESS;
}

View File

@@ -0,0 +1,58 @@
/**
******************************************************************************
* 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_FS_DEVICES_DISC_IMAGE_ENTRY_H_
#define XENIA_KERNEL_XBOXKRNL_FS_DEVICES_DISC_IMAGE_ENTRY_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/kernel/xboxkrnl/fs/entry.h>
namespace xe {
namespace kernel {
namespace xboxkrnl {
namespace fs {
class GDFXEntry;
class DiscImageEntry : public Entry {
public:
DiscImageEntry(Type type, Device* device, const char* path,
xe_mmap_ref mmap, GDFXEntry* gdfx_entry);
virtual ~DiscImageEntry();
xe_mmap_ref mmap() const { return mmap_; }
GDFXEntry* gdfx_entry() const { return gdfx_entry_; }
virtual X_STATUS QueryInfo(XFileInfo* out_info);
virtual MemoryMapping* CreateMemoryMapping(
xe_file_mode file_mode, const size_t offset, const size_t length);
virtual X_STATUS Open(
KernelState* kernel_state,
uint32_t desired_access, bool async,
XFile** out_file);
private:
xe_mmap_ref mmap_;
GDFXEntry* gdfx_entry_;
};
} // namespace fs
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_FS_DEVICES_DISC_IMAGE_ENTRY_H_

View File

@@ -0,0 +1,48 @@
/**
******************************************************************************
* 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/xboxkrnl/fs/devices/disc_image_file.h>
#include <xenia/kernel/xboxkrnl/fs/gdfx.h>
#include <xenia/kernel/xboxkrnl/fs/devices/disc_image_entry.h>
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl;
using namespace xe::kernel::xboxkrnl::fs;
DiscImageFile::DiscImageFile(
KernelState* kernel_state, uint32_t desired_access,
DiscImageEntry* entry) :
entry_(entry),
XFile(kernel_state, desired_access) {
}
DiscImageFile::~DiscImageFile() {
}
X_STATUS DiscImageFile::QueryInfo(XFileInfo* out_info) {
return entry_->QueryInfo(out_info);
}
X_STATUS DiscImageFile::ReadSync(
void* buffer, size_t buffer_length, size_t byte_offset,
size_t* out_bytes_read) {
GDFXEntry* gdfx_entry = entry_->gdfx_entry();
xe_mmap_ref mmap = entry_->mmap();
size_t real_offset = gdfx_entry->offset + byte_offset;
size_t real_length = MIN(buffer_length, gdfx_entry->size - byte_offset);
xe_copy_memory(
buffer, buffer_length,
xe_mmap_get_addr(mmap) + real_offset, real_length);
*out_bytes_read = real_length;
return X_STATUS_SUCCESS;
}

View File

@@ -0,0 +1,51 @@
/**
******************************************************************************
* 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_FS_DEVICES_DISC_IMAGE_FILE_H_
#define XENIA_KERNEL_XBOXKRNL_FS_DEVICES_DISC_IMAGE_FILE_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/kernel/xboxkrnl/objects/xfile.h>
namespace xe {
namespace kernel {
namespace xboxkrnl {
namespace fs {
class DiscImageEntry;
class DiscImageFile : public XFile {
public:
DiscImageFile(KernelState* kernel_state, uint32_t desired_access,
DiscImageEntry* entry);
virtual ~DiscImageFile();
virtual X_STATUS QueryInfo(XFileInfo* out_info);
protected:
virtual X_STATUS ReadSync(
void* buffer, size_t buffer_length, size_t byte_offset,
size_t* out_bytes_read);
private:
DiscImageEntry* entry_;
};
} // namespace fs
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_FS_DEVICES_DISC_IMAGE_FILE_H_

View File

@@ -0,0 +1,65 @@
/**
******************************************************************************
* 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/xboxkrnl/fs/devices/host_path_device.h>
#include <xenia/kernel/xboxkrnl/fs/devices/host_path_entry.h>
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl::fs;
HostPathDevice::HostPathDevice(const char* path, const xechar_t* local_path) :
Device(path) {
local_path_ = xestrdup(local_path);
}
HostPathDevice::~HostPathDevice() {
xe_free(local_path_);
}
Entry* HostPathDevice::ResolvePath(const char* path) {
// The filesystem will have stripped our prefix off already, so the path will
// be in the form:
// some\PATH.foo
XELOGFS("HostPathDevice::ResolvePath(%s)", path);
#if XE_WCHAR
xechar_t rel_path[XE_MAX_PATH];
XEIGNORE(xestrwiden(rel_path, XECOUNT(rel_path), path));
#else
const xechar_t* rel_path = path;
#endif
xechar_t full_path[XE_MAX_PATH];
xe_path_join(local_path_, rel_path, full_path, XECOUNT(full_path));
// Swap around path separators.
if (XE_PATH_SEPARATOR != '\\') {
for (size_t n = 0; n < XECOUNT(full_path); n++) {
if (full_path[n] == 0) {
break;
}
if (full_path[n] == '\\') {
full_path[n] = XE_PATH_SEPARATOR;
}
}
}
// TODO(benvanik): get file info
// TODO(benvanik): fail if does not exit
// TODO(benvanik): switch based on type
Entry::Type type = Entry::kTypeFile;
HostPathEntry* entry = new HostPathEntry(type, this, path, full_path);
return entry;
}

View File

@@ -0,0 +1,43 @@
/**
******************************************************************************
* 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_FS_DEVICES_HOST_PATH_DEVICE_H_
#define XENIA_KERNEL_XBOXKRNL_FS_DEVICES_HOST_PATH_DEVICE_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/kernel/xboxkrnl/fs/device.h>
namespace xe {
namespace kernel {
namespace xboxkrnl {
namespace fs {
class HostPathDevice : public Device {
public:
HostPathDevice(const char* path, const xechar_t* local_path);
virtual ~HostPathDevice();
virtual Entry* ResolvePath(const char* path);
private:
xechar_t* local_path_;
};
} // namespace fs
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_FS_DEVICES_HOST_PATH_DEVICE_H_

View File

@@ -0,0 +1,108 @@
/**
******************************************************************************
* 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/xboxkrnl/fs/devices/host_path_entry.h>
#include <xenia/kernel/xboxkrnl/fs/devices/host_path_file.h>
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl;
using namespace xe::kernel::xboxkrnl::fs;
namespace {
class HostPathMemoryMapping : public MemoryMapping {
public:
HostPathMemoryMapping(uint8_t* address, size_t length, xe_mmap_ref mmap) :
MemoryMapping(address, length) {
mmap_ = xe_mmap_retain(mmap);
}
virtual ~HostPathMemoryMapping() {
xe_mmap_release(mmap_);
}
private:
xe_mmap_ref mmap_;
};
}
HostPathEntry::HostPathEntry(Type type, Device* device, const char* path,
const xechar_t* local_path) :
Entry(type, device, path) {
local_path_ = xestrdup(local_path);
}
HostPathEntry::~HostPathEntry() {
xe_free(local_path_);
}
X_STATUS HostPathEntry::QueryInfo(XFileInfo* out_info) {
XEASSERTNOTNULL(out_info);
WIN32_FILE_ATTRIBUTE_DATA data;
if (!GetFileAttributesEx(
local_path_, GetFileExInfoStandard, &data)) {
return X_STATUS_ACCESS_DENIED;
}
#define COMBINE_TIME(t) (((uint64_t)t.dwHighDateTime << 32) | t.dwLowDateTime)
out_info->creation_time = COMBINE_TIME(data.ftCreationTime);
out_info->last_access_time = COMBINE_TIME(data.ftLastAccessTime);
out_info->last_write_time = COMBINE_TIME(data.ftLastWriteTime);
out_info->change_time = COMBINE_TIME(data.ftLastWriteTime);
out_info->allocation_size = 4096;
out_info->file_length = ((uint64_t)data.nFileSizeHigh << 32) | data.nFileSizeLow;
out_info->attributes = (X_FILE_ATTRIBUTES)data.dwFileAttributes;
return X_STATUS_SUCCESS;
}
MemoryMapping* HostPathEntry::CreateMemoryMapping(
xe_file_mode file_mode, const size_t offset, const size_t length) {
xe_mmap_ref mmap = xe_mmap_open(file_mode, local_path_, offset, length);
if (!mmap) {
return NULL;
}
HostPathMemoryMapping* lfmm = new HostPathMemoryMapping(
(uint8_t*)xe_mmap_get_addr(mmap), xe_mmap_get_length(mmap),
mmap);
xe_mmap_release(mmap);
return lfmm;
}
X_STATUS HostPathEntry::Open(
KernelState* kernel_state,
uint32_t desired_access, bool async,
XFile** out_file) {
DWORD share_mode = FILE_SHARE_READ;
DWORD creation_disposition = OPEN_EXISTING;
DWORD flags_and_attributes = async ? FILE_FLAG_OVERLAPPED : 0;
HANDLE file = CreateFile(
local_path_,
desired_access,
share_mode,
NULL,
creation_disposition,
flags_and_attributes,
NULL);
if (!file) {
// TODO(benvanik): pick correct response.
return X_STATUS_ACCESS_DENIED;
}
*out_file = new HostPathFile(kernel_state, desired_access, this, file);
return X_STATUS_SUCCESS;
}

View File

@@ -0,0 +1,54 @@
/**
******************************************************************************
* 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_FS_DEVICES_HOST_PATH_ENTRY_H_
#define XENIA_KERNEL_XBOXKRNL_FS_DEVICES_HOST_PATH_ENTRY_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/kernel/xboxkrnl/fs/entry.h>
namespace xe {
namespace kernel {
namespace xboxkrnl {
namespace fs {
class HostPathEntry : public Entry {
public:
HostPathEntry(Type type, Device* device, const char* path,
const xechar_t* local_path);
virtual ~HostPathEntry();
const xechar_t* local_path() { return local_path_; }
virtual X_STATUS QueryInfo(XFileInfo* out_info);
virtual MemoryMapping* CreateMemoryMapping(
xe_file_mode file_mode, const size_t offset, const size_t length);
virtual X_STATUS Open(
KernelState* kernel_state,
uint32_t desired_access, bool async,
XFile** out_file);
private:
xechar_t* local_path_;
};
} // namespace fs
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_FS_DEVICES_HOST_PATH_ENTRY_H_

View File

@@ -0,0 +1,51 @@
/**
******************************************************************************
* 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/xboxkrnl/fs/devices/host_path_file.h>
#include <xenia/kernel/xboxkrnl/fs/devices/host_path_entry.h>
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl;
using namespace xe::kernel::xboxkrnl::fs;
HostPathFile::HostPathFile(
KernelState* kernel_state, uint32_t desired_access,
HostPathEntry* entry, HANDLE file_handle) :
entry_(entry), file_handle_(file_handle),
XFile(kernel_state, desired_access) {
}
HostPathFile::~HostPathFile() {
CloseHandle(file_handle_);
}
X_STATUS HostPathFile::QueryInfo(XFileInfo* out_info) {
return entry_->QueryInfo(out_info);
}
X_STATUS HostPathFile::ReadSync(
void* buffer, size_t buffer_length, size_t byte_offset,
size_t* out_bytes_read) {
OVERLAPPED overlapped;
overlapped.Pointer = (PVOID)byte_offset;
overlapped.hEvent = NULL;
DWORD bytes_read = 0;
BOOL read = ReadFile(
file_handle_, buffer, (DWORD)buffer_length, &bytes_read, &overlapped);
if (read) {
*out_bytes_read = bytes_read;
return X_STATUS_SUCCESS;
} else {
return X_STATUS_UNSUCCESSFUL;
}
}

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_FS_DEVICES_HOST_PATH_FILE_H_
#define XENIA_KERNEL_XBOXKRNL_FS_DEVICES_HOST_PATH_FILE_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/kernel/xboxkrnl/objects/xfile.h>
namespace xe {
namespace kernel {
namespace xboxkrnl {
namespace fs {
class HostPathEntry;
class HostPathFile : public XFile {
public:
HostPathFile(KernelState* kernel_state, uint32_t desired_access,
HostPathEntry* entry, HANDLE file_handle);
virtual ~HostPathFile();
virtual X_STATUS QueryInfo(XFileInfo* out_info);
protected:
virtual X_STATUS ReadSync(
void* buffer, size_t buffer_length, size_t byte_offset,
size_t* out_bytes_read);
private:
HostPathEntry* entry_;
HANDLE file_handle_;
};
} // namespace fs
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_FS_DEVICES_HOST_PATH_FILE_H_

View File

@@ -0,0 +1,17 @@
# Copyright 2013 Ben Vanik. All Rights Reserved.
{
'sources': [
'disc_image_device.cc',
'disc_image_device.h',
'disc_image_entry.cc',
'disc_image_entry.h',
'disc_image_file.cc',
'disc_image_file.h',
'host_path_device.cc',
'host_path_device.h',
'host_path_entry.cc',
'host_path_entry.h',
'host_path_file.cc',
'host_path_file.h',
],
}

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/xboxkrnl/fs/entry.h>
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl::fs;
MemoryMapping::MemoryMapping(uint8_t* address, size_t length) :
address_(address), length_(length) {
}
MemoryMapping::~MemoryMapping() {
}
Entry::Entry(Type type, Device* device, const char* path) :
type_(type),
device_(device) {
path_ = xestrdupa(path);
// TODO(benvanik): last index of \, unless \ at end, then before that
name_ = NULL;
}
Entry::~Entry() {
xe_free(path_);
xe_free(name_);
}

View File

@@ -0,0 +1,85 @@
/**
******************************************************************************
* 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_FS_ENTRY_H_
#define XENIA_KERNEL_XBOXKRNL_FS_ENTRY_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/xbox.h>
XEDECLARECLASS3(xe, kernel, xboxkrnl, KernelState);
XEDECLARECLASS3(xe, kernel, xboxkrnl, XFile);
XEDECLARECLASS3(xe, kernel, xboxkrnl, XFileInfo);
namespace xe {
namespace kernel {
namespace xboxkrnl {
namespace fs {
class Device;
class MemoryMapping {
public:
MemoryMapping(uint8_t* address, size_t length);
virtual ~MemoryMapping();
uint8_t* address() const { return address_; }
size_t length() const { return length_; }
private:
uint8_t* address_;
size_t length_;
};
class Entry {
public:
enum Type {
kTypeFile,
kTypeDirectory,
};
Entry(Type type, Device* device, const char* path);
virtual ~Entry();
Type type() const { return type_; }
Device* device() const { return device_; }
const char* path() const { return path_; }
const char* name() const { return name_; }
virtual X_STATUS QueryInfo(XFileInfo* out_info) = 0;
virtual MemoryMapping* CreateMemoryMapping(
xe_file_mode file_mode, const size_t offset, const size_t length) = 0;
virtual X_STATUS Open(
KernelState* kernel_state,
uint32_t desired_access, bool async,
XFile** out_file) = 0;
private:
Type type_;
Device* device_;
char* path_;
char* name_;
};
} // namespace fs
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_FS_ENTRY_H_

View File

@@ -0,0 +1,113 @@
/**
******************************************************************************
* 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/xboxkrnl/fs/filesystem.h>
#include <xenia/kernel/xboxkrnl/fs/devices/disc_image_device.h>
#include <xenia/kernel/xboxkrnl/fs/devices/host_path_device.h>
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl::fs;
FileSystem::FileSystem() {
}
FileSystem::~FileSystem() {
// Delete all devices.
// This will explode if anyone is still using data from them.
for (std::vector<Device*>::iterator it = devices_.begin();
it != devices_.end(); ++it) {
delete *it;
}
devices_.clear();
symlinks_.clear();
}
int FileSystem::RegisterDevice(const char* path, Device* device) {
devices_.push_back(device);
return 0;
}
int FileSystem::RegisterHostPathDevice(
const char* path, const xechar_t* local_path) {
Device* device = new HostPathDevice(path, local_path);
return RegisterDevice(path, device);
}
int FileSystem::RegisterDiscImageDevice(
const char* path, const xechar_t* local_path) {
DiscImageDevice* device = new DiscImageDevice(path, local_path);
if (device->Init()) {
return 1;
}
return RegisterDevice(path, device);
}
int FileSystem::CreateSymbolicLink(const char* path, const char* target) {
symlinks_.insert(std::pair<const char*, const char*>(
xestrdupa(path),
xestrdupa(target)));
return 0;
}
int FileSystem::DeleteSymbolicLink(const char* path) {
std::tr1::unordered_map<std::string, std::string>::iterator it =
symlinks_.find(std::string(path));
if (it != symlinks_.end()) {
symlinks_.erase(it);
return 0;
}
return 1;
}
Entry* FileSystem::ResolvePath(const char* path) {
// Strip off prefix and pass to device.
// e.g., d:\some\PATH.foo -> some\PATH.foo
// Support both symlinks and device specifiers, like:
// \\Device\Foo\some\PATH.foo, d:\some\PATH.foo, etc.
// TODO(benvanik): normalize path/etc
// e.g., remove ..'s and such
// Resolve symlinks.
// TODO(benvanik): more robust symlink handling - right now we assume simple
// drive path -> device mappings with nothing nested.
char full_path[XE_MAX_PATH];
XEIGNORE(xestrcpya(full_path, XECOUNT(full_path), path));
for (std::tr1::unordered_map<std::string, std::string>::iterator it =
symlinks_.begin(); it != symlinks_.end(); ++it) {
if (xestrcasestra(path, it->first.c_str()) == path) {
// Found symlink, fixup.
const char* after_path = path + it->first.size();
XEIGNORE(xesnprintfa(full_path, XECOUNT(full_path), "%s%s",
it->second.c_str(), after_path));
break;
}
}
// Scan all devices.
for (std::vector<Device*>::iterator it = devices_.begin();
it != devices_.end(); ++it) {
Device* device = *it;
if (xestrcasestra(full_path, device->path()) == full_path) {
// Found!
// Trim the device prefix off and pass down.
char device_path[XE_MAX_PATH];
XEIGNORE(xestrcpya(device_path, XECOUNT(device_path),
full_path + xestrlena(device->path())));
return device->ResolvePath(device_path);
}
}
XELOGE("ResolvePath(%s) failed - no root found", path);
return NULL;
}

View File

@@ -0,0 +1,56 @@
/**
******************************************************************************
* 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_FS_FILESYSTEM_H_
#define XENIA_KERNEL_XBOXKRNL_FS_FILESYSTEM_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <vector>
#include <xenia/kernel/xboxkrnl/fs/entry.h>
namespace xe {
namespace kernel {
namespace xboxkrnl {
namespace fs {
class Device;
class FileSystem {
public:
FileSystem();
~FileSystem();
int RegisterDevice(const char* path, Device* device);
int RegisterHostPathDevice(const char* path, const xechar_t* local_path);
int RegisterDiscImageDevice(const char* path, const xechar_t* local_path);
int CreateSymbolicLink(const char* path, const char* target);
int DeleteSymbolicLink(const char* path);
Entry* ResolvePath(const char* path);
private:
std::vector<Device*> devices_;
std::tr1::unordered_map<std::string, std::string> symlinks_;
};
} // namespace fs
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_FS_FILESYSTEM_H_

View File

@@ -0,0 +1,209 @@
/**
******************************************************************************
* 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. *
******************************************************************************
* Major contributions to this file from:
* - abgx360
*/
#include <xenia/kernel/xboxkrnl/fs/gdfx.h>
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl::fs;
namespace {
#define kXESectorSize 2048
}
GDFXEntry::GDFXEntry() :
attributes(X_FILE_ATTRIBUTE_NONE), offset(0), size(0) {
}
GDFXEntry::~GDFXEntry() {
for (std::vector<GDFXEntry*>::iterator it = children.begin();
it != children.end(); ++it) {
delete *it;
}
}
GDFXEntry* GDFXEntry::GetChild(const char* name) {
// TODO(benvanik): a faster search
for (std::vector<GDFXEntry*>::iterator it = children.begin();
it != children.end(); ++it) {
GDFXEntry* entry = *it;
if (xestrcasecmpa(entry->name.c_str(), name) == 0) {
return entry;
}
}
return NULL;
}
void GDFXEntry::Dump(int indent) {
printf("%s%s\n", std::string(indent, ' ').c_str(), name.c_str());
for (std::vector<GDFXEntry*>::iterator it = children.begin();
it != children.end(); ++it) {
GDFXEntry* entry = *it;
entry->Dump(indent + 2);
}
}
GDFX::GDFX(xe_mmap_ref mmap) {
mmap_ = xe_mmap_retain(mmap);
root_entry_ = NULL;
}
GDFX::~GDFX() {
delete root_entry_;
xe_mmap_release(mmap_);
}
GDFXEntry* GDFX::root_entry() {
return root_entry_;
}
GDFX::Error GDFX::Load() {
Error result = kErrorOutOfMemory;
ParseState state;
xe_zero_struct(&state, sizeof(state));
state.ptr = (uint8_t*)xe_mmap_get_addr(mmap_);
state.size = xe_mmap_get_length(mmap_);
result = Verify(state);
XEEXPECTZERO(result);
result = ReadAllEntries(state, state.ptr + state.root_offset);
XEEXPECTZERO(result);
result = kSuccess;
XECLEANUP:
return result;
}
void GDFX::Dump() {
if (root_entry_) {
root_entry_->Dump(0);
}
}
GDFX::Error GDFX::Verify(ParseState& state) {
// Find sector 32 of the game partition - try at a few points.
const static size_t likely_offsets[] = {
0x00000000, 0x0000FB20, 0x00020600, 0x0FD90000,
};
bool magic_found = false;
for (size_t n = 0; n < XECOUNT(likely_offsets); n++) {
state.game_offset = likely_offsets[n];
if (VerifyMagic(state, state.game_offset + (32 * kXESectorSize))) {
magic_found = true;
break;
}
}
if (!magic_found) {
// File doesn't have the magic values - likely not a real GDFX source.
return kErrorFileMismatch;
}
// Read sector 32 to get FS state.
if (state.size < state.game_offset + (32 * kXESectorSize)) {
return kErrorReadError;
}
uint8_t* fs_ptr = state.ptr + state.game_offset + (32 * kXESectorSize);
state.root_sector = XEGETUINT32LE(fs_ptr + 20);
state.root_size = XEGETUINT32LE(fs_ptr + 24);
state.root_offset = state.game_offset + (state.root_sector * kXESectorSize);
if (state.root_size < 13 ||
state.root_size > 32 * 1024 * 1024) {
return kErrorDamagedFile;
}
return kSuccess;
}
bool GDFX::VerifyMagic(ParseState& state, size_t offset) {
// Simple check to see if the given offset contains the magic value.
return memcmp(state.ptr + offset, "MICROSOFT*XBOX*MEDIA", 20) == 0;
}
GDFX::Error GDFX::ReadAllEntries(ParseState& state,
const uint8_t* root_buffer) {
root_entry_ = new GDFXEntry();
root_entry_->offset = 0;
root_entry_->size = 0;
root_entry_->name = "";
root_entry_->attributes = X_FILE_ATTRIBUTE_DIRECTORY;
if (!ReadEntry(state, root_buffer, 0, root_entry_)) {
return kErrorOutOfMemory;
}
return kSuccess;
}
bool GDFX::ReadEntry(ParseState& state, const uint8_t* buffer,
uint16_t entry_ordinal, GDFXEntry* parent) {
const uint8_t* p = buffer + (entry_ordinal * 4);
uint16_t node_l = XEGETUINT16LE(p + 0);
uint16_t node_r = XEGETUINT16LE(p + 2);
size_t sector = XEGETUINT32LE(p + 4);
size_t length = XEGETUINT32LE(p + 8);
uint8_t attributes = XEGETUINT8LE(p + 12);
uint8_t name_length = XEGETUINT8LE(p + 13);
char* name = (char*)(p + 14);
if (node_l && !ReadEntry(state, buffer, node_l, parent)) {
return false;
}
GDFXEntry* entry = new GDFXEntry();
entry->name = std::string(name, name_length);
entry->name.append(1, '\0');
entry->attributes = (X_FILE_ATTRIBUTES)attributes;
// Add to parent.
parent->children.push_back(entry);
if (attributes & X_FILE_ATTRIBUTE_DIRECTORY) {
// Folder.
entry->offset = 0;
entry->size = 0;
if (length) {
// Not a leaf - read in children.
if (state.size < state.game_offset + (sector * kXESectorSize)) {
// Out of bounds read.
return false;
}
// Read child list.
uint8_t* folder_ptr =
state.ptr + state.game_offset + (sector * kXESectorSize);
if (!ReadEntry(state, folder_ptr, 0, entry)) {
return false;
}
}
} else {
// File.
entry->offset = state.game_offset + (sector * kXESectorSize);
entry->size = length;
}
// Read next file in the list.
if (node_r && !ReadEntry(state, buffer, node_r, parent)) {
return false;
}
return true;
}

View File

@@ -0,0 +1,98 @@
/**
******************************************************************************
* 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_FS_GDFX_H_
#define XENIA_KERNEL_XBOXKRNL_FS_GDFX_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <vector>
#include <xenia/xbox.h>
#include <xenia/kernel/xboxkrnl/fs/entry.h>
namespace xe {
namespace kernel {
namespace xboxkrnl {
namespace fs {
class GDFX;
class GDFXEntry {
public:
GDFXEntry();
~GDFXEntry();
GDFXEntry* GetChild(const char* name);
void Dump(int indent);
std::string name;
X_FILE_ATTRIBUTES attributes;
size_t offset;
size_t size;
std::vector<GDFXEntry*> children;
};
class GDFX {
public:
enum Error {
kSuccess = 0,
kErrorOutOfMemory = -1,
kErrorReadError = -10,
kErrorFileMismatch = -30,
kErrorDamagedFile = -31,
};
GDFX(xe_mmap_ref mmap);
virtual ~GDFX();
GDFXEntry* root_entry();
Error Load();
void Dump();
private:
typedef struct {
uint8_t* ptr;
size_t size; // Size (bytes) of total image
size_t game_offset; // Offset (bytes) of game partition
size_t root_sector; // Offset (sector) of root
size_t root_offset; // Offset (bytes) of root
size_t root_size; // Size (bytes) of root
} ParseState;
Error Verify(ParseState& state);
bool VerifyMagic(ParseState& state, size_t offset);
Error ReadAllEntries(ParseState& state, const uint8_t* root_buffer);
bool ReadEntry(ParseState& state, const uint8_t* buffer,
uint16_t entry_ordinal, GDFXEntry* parent);
xe_mmap_ref mmap_;
GDFXEntry* root_entry_;
};
} // namespace fs
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_FS_GDFX_H_

View File

@@ -0,0 +1,17 @@
# Copyright 2013 Ben Vanik. All Rights Reserved.
{
'sources': [
'device.cc',
'device.h',
'entry.cc',
'entry.h',
'filesystem.cc',
'filesystem.h',
'gdfx.cc',
'gdfx.h',
],
'includes': [
'devices/sources.gypi',
],
}

View File

@@ -0,0 +1,76 @@
/**
******************************************************************************
* 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/xboxkrnl/kernel_state.h>
#include <xenia/emulator.h>
#include <xenia/kernel/xboxkrnl/xboxkrnl_private.h>
#include <xenia/kernel/xboxkrnl/xobject.h>
#include <xenia/kernel/xboxkrnl/objects/xmodule.h>
#include <xenia/kernel/xboxkrnl/objects/xthread.h>
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl;
KernelState::KernelState(Emulator* emulator) :
emulator_(emulator),
executable_module_(NULL) {
memory_ = xe_memory_retain(emulator->memory());
processor_ = emulator->processor();
file_system_ = emulator->file_system();
object_table_ = new ObjectTable();
object_mutex_ = xe_mutex_alloc(10000);
}
KernelState::~KernelState() {
SetExecutableModule(NULL);
// Delete all objects.
xe_mutex_free(object_mutex_);
delete object_table_;
xe_memory_release(memory_);
}
KernelState* KernelState::shared() {
return shared_kernel_state_;
}
XModule* KernelState::GetModule(const char* name) {
// TODO(benvanik): implement lookup. Most games seem to look for xam.xex/etc.
XEASSERTALWAYS();
return NULL;
}
XModule* KernelState::GetExecutableModule() {
if (!executable_module_) {
return NULL;
}
executable_module_->Retain();
return executable_module_;
}
void KernelState::SetExecutableModule(XModule* module) {
if (module == executable_module_) {
return;
}
if (executable_module_) {
executable_module_->Release();
}
executable_module_ = module;
if (executable_module_) {
executable_module_->Retain();
}
}

View File

@@ -0,0 +1,71 @@
/**
******************************************************************************
* 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_KERNEL_STATE_H_
#define XENIA_KERNEL_XBOXKRNL_KERNEL_STATE_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/export_resolver.h>
#include <xenia/xbox.h>
#include <xenia/kernel/kernel_module.h>
#include <xenia/kernel/xboxkrnl/object_table.h>
#include <xenia/kernel/xboxkrnl/fs/filesystem.h>
XEDECLARECLASS2(xe, cpu, Processor);
XEDECLARECLASS3(xe, kernel, fs, FileSystem);
XEDECLARECLASS3(xe, kernel, xboxkrnl, XModule);
namespace xe {
namespace kernel {
namespace xboxkrnl {
class KernelState {
public:
KernelState(Emulator* emulator);
~KernelState();
static KernelState* shared();
Emulator* emulator() const { return emulator_; }
xe_memory_ref memory() const { return memory_; }
cpu::Processor* processor() const { return processor_; }
fs::FileSystem* file_system() const { return file_system_; }
ObjectTable* object_table() const { return object_table_; }
XModule* GetModule(const char* name);
XModule* GetExecutableModule();
void SetExecutableModule(XModule* module);
private:
Emulator* emulator_;
xe_memory_ref memory_;
cpu::Processor* processor_;
fs::FileSystem* file_system_;
ObjectTable* object_table_;
xe_mutex_t* object_mutex_;
XModule* executable_module_;
friend class XObject;
};
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_KERNEL_STATE_H_

View File

@@ -0,0 +1,194 @@
/**
******************************************************************************
* 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/xboxkrnl/object_table.h>
#include <xenia/kernel/xboxkrnl/xobject.h>
#include <xenia/kernel/xboxkrnl/objects/xthread.h>
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl;
ObjectTable::ObjectTable() :
table_capacity_(0),
table_(NULL),
last_free_entry_(0) {
table_mutex_ = xe_mutex_alloc(0);
XEASSERTNOTNULL(table_mutex_);
}
ObjectTable::~ObjectTable() {
xe_mutex_lock(table_mutex_);
// Release all objects.
for (uint32_t n = 0; n < table_capacity_; n++) {
ObjectTableEntry& entry = table_[n];
if (entry.object) {
entry.object->ReleaseHandle();
entry.object->Release();
}
}
table_capacity_ = 0;
last_free_entry_ = 0;
xe_free(table_);
table_ = NULL;
xe_mutex_unlock(table_mutex_);
xe_mutex_free(table_mutex_);
table_mutex_ = NULL;
}
X_STATUS ObjectTable::FindFreeSlot(uint32_t* out_slot) {
// Find a free slot.
uint32_t slot = last_free_entry_;
uint32_t scan_count = 0;
while (scan_count < table_capacity_) {
ObjectTableEntry& entry = table_[slot];
if (!entry.object) {
*out_slot = slot;
return X_STATUS_SUCCESS;
}
scan_count++;
slot = (slot + 1) % table_capacity_;
if (slot == 0) {
// Never allow 0 handles.
scan_count++;
slot++;
}
}
// Table out of slots, expand.
uint32_t new_table_capacity = MAX(16 * 1024, table_capacity_ * 2);
ObjectTableEntry* new_table = (ObjectTableEntry*)xe_recalloc(
table_,
table_capacity_ * sizeof(ObjectTableEntry),
new_table_capacity * sizeof(ObjectTableEntry));
if (!new_table) {
return X_STATUS_NO_MEMORY;
}
last_free_entry_ = table_capacity_;
table_capacity_ = new_table_capacity;
table_ = new_table;
// Never allow 0 handles.
slot = ++last_free_entry_;
*out_slot = slot;
return X_STATUS_SUCCESS;
}
X_STATUS ObjectTable::AddHandle(XObject* object, X_HANDLE* out_handle) {
XEASSERTNOTNULL(out_handle);
X_STATUS result = X_STATUS_SUCCESS;
xe_mutex_lock(table_mutex_);
// Find a free slot.
uint32_t slot = 0;
result = FindFreeSlot(&slot);
// Stash.
if (XSUCCEEDED(result)) {
ObjectTableEntry& entry = table_[slot];
entry.object = object;
// Retain so long as the object is in the table.
object->RetainHandle();
object->Retain();
}
xe_mutex_unlock(table_mutex_);
if (XSUCCEEDED(result)) {
*out_handle = slot << 2;
}
return result;
}
X_STATUS ObjectTable::RemoveHandle(X_HANDLE handle) {
X_STATUS result = X_STATUS_SUCCESS;
xe_mutex_lock(table_mutex_);
// Lower 2 bits are ignored.
uint32_t slot = handle >> 2;
// Verify slot.
XObject* object = NULL;
if (slot > table_capacity_) {
result = X_STATUS_INVALID_HANDLE;
} else {
ObjectTableEntry& entry = table_[slot];
if (entry.object) {
// Release after we lose the lock.
object = entry.object;
} else {
result = X_STATUS_INVALID_HANDLE;
}
}
xe_mutex_unlock(table_mutex_);
if (object) {
// Release the object handle now that it is out of the table.
object->ReleaseHandle();
object->Release();
}
return result;
}
X_STATUS ObjectTable::GetObject(X_HANDLE handle, XObject** out_object) {
XEASSERTNOTNULL(out_object);
X_STATUS result = X_STATUS_SUCCESS;
if (handle == 0xFFFFFFFF) {
// CurrentProcess
XEASSERTALWAYS();
} else if (handle == 0xFFFFFFFE) {
// CurrentThread
handle = XThread::GetCurrentThreadHandle();
}
xe_mutex_lock(table_mutex_);
// Lower 2 bits are ignored.
uint32_t slot = handle >> 2;
// Verify slot.
XObject* object = NULL;
if (slot > table_capacity_) {
result = X_STATUS_INVALID_HANDLE;
} else {
ObjectTableEntry& entry = table_[slot];
if (entry.object) {
object = entry.object;
} else {
result = X_STATUS_INVALID_HANDLE;
}
}
// Retain the object pointer.
if (object) {
object->Retain();
}
xe_mutex_unlock(table_mutex_);
*out_object = object;
return result;
}

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_OBJECT_TABLE_H_
#define XENIA_KERNEL_XBOXKRNL_OBJECT_TABLE_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/xbox.h>
namespace xe {
namespace kernel {
namespace xboxkrnl {
class XObject;
class ObjectTable {
public:
ObjectTable();
~ObjectTable();
X_STATUS AddHandle(XObject* object, X_HANDLE* out_handle);
X_STATUS RemoveHandle(X_HANDLE handle);
X_STATUS GetObject(X_HANDLE handle, XObject** out_object);
private:
X_STATUS FindFreeSlot(uint32_t* out_slot);
typedef struct {
XObject* object;
} ObjectTableEntry;
xe_mutex_t* table_mutex_;
uint32_t table_capacity_;
ObjectTableEntry* table_;
uint32_t last_free_entry_;
};
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_OBJECT_TABLE_H_

View File

@@ -0,0 +1,13 @@
# Copyright 2013 Ben Vanik. All Rights Reserved.
{
'sources': [
'xevent.cc',
'xevent.h',
'xfile.cc',
'xfile.h',
'xmodule.cc',
'xmodule.h',
'xthread.cc',
'xthread.h',
],
}

View File

@@ -0,0 +1,99 @@
/**
******************************************************************************
* 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/xboxkrnl/objects/xevent.h>
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl;
XEvent::XEvent(KernelState* kernel_state) :
XObject(kernel_state, kTypeEvent),
handle_(NULL) {
}
XEvent::~XEvent() {
}
void XEvent::Initialize(bool manual_reset, bool initial_state) {
XEASSERTNULL(handle_);
handle_ = CreateEvent(NULL, manual_reset, initial_state, NULL);
}
void XEvent::InitializeNative(void* native_ptr, DISPATCH_HEADER& header) {
XEASSERTNULL(handle_);
bool manual_reset;
switch (header.type_flags >> 24) {
case 0x00: // EventNotificationObject (manual reset)
manual_reset = true;
break;
case 0x01: // EventSynchronizationObject (auto reset)
manual_reset = false;
break;
default:
XEASSERTALWAYS();
return;
}
bool initial_state = header.signal_state ? true : false;
handle_ = CreateEvent(NULL, manual_reset, initial_state, NULL);
}
int32_t XEvent::Set(uint32_t priority_increment, bool wait) {
return SetEvent(handle_) ? 1 : 0;
}
int32_t XEvent::Reset() {
return ResetEvent(handle_) ? 1 : 0;
}
void XEvent::Clear() {
ResetEvent(handle_);
}
X_STATUS XEvent::Wait(uint32_t wait_reason, uint32_t processor_mode,
uint32_t alertable, uint64_t* opt_timeout) {
DWORD timeout_ms;
if (opt_timeout) {
int64_t timeout_ticks = (int64_t)(*opt_timeout);
if (timeout_ticks > 0) {
// Absolute time, based on January 1, 1601.
// TODO(benvanik): convert time to relative time.
XEASSERTALWAYS();
timeout_ms = 0;
} else if (timeout_ticks < 0) {
// Relative time.
timeout_ms = (DWORD)(-timeout_ticks / 10000); // Ticks -> MS
} else {
timeout_ms = 0;
}
} else {
timeout_ms = INFINITE;
}
DWORD result = WaitForSingleObjectEx(handle_, timeout_ms, alertable);
switch (result) {
case WAIT_OBJECT_0:
return X_STATUS_SUCCESS;
case WAIT_IO_COMPLETION:
// Or X_STATUS_ALERTED?
return X_STATUS_USER_APC;
case WAIT_TIMEOUT:
return X_STATUS_TIMEOUT;
default:
case WAIT_FAILED:
case WAIT_ABANDONED:
return X_STATUS_ABANDONED_WAIT_0;
}
}

View File

@@ -0,0 +1,48 @@
/**
******************************************************************************
* 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_XEVENT_H_
#define XENIA_KERNEL_XBOXKRNL_XEVENT_H_
#include <xenia/kernel/xboxkrnl/xobject.h>
#include <xenia/xbox.h>
namespace xe {
namespace kernel {
namespace xboxkrnl {
class XEvent : public XObject {
public:
XEvent(KernelState* kernel_state);
virtual ~XEvent();
void Initialize(bool manual_reset, bool initial_state);
void InitializeNative(void* native_ptr, DISPATCH_HEADER& header);
int32_t Set(uint32_t priority_increment, bool wait);
int32_t Reset();
void Clear();
virtual X_STATUS Wait(uint32_t wait_reason, uint32_t processor_mode,
uint32_t alertable, uint64_t* opt_timeout);
private:
HANDLE handle_;
};
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_XEVENT_H_

View File

@@ -0,0 +1,62 @@
/**
******************************************************************************
* 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/xboxkrnl/objects/xfile.h>
#include <xenia/kernel/xboxkrnl/async_request.h>
#include <xenia/kernel/xboxkrnl/objects/xevent.h>
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl;
XFile::XFile(KernelState* kernel_state, uint32_t desired_access) :
desired_access_(desired_access), position_(0),
XObject(kernel_state, kTypeFile) {
async_event_ = new XEvent(kernel_state);
async_event_->Initialize(false, false);
}
XFile::~XFile() {
// TODO(benvanik): signal that the file is closing?
async_event_->Set(0, false);
async_event_->Delete();
}
X_STATUS XFile::Wait(uint32_t wait_reason, uint32_t processor_mode,
uint32_t alertable, uint64_t* opt_timeout) {
// Wait until some async operation completes.
return async_event_->Wait(
wait_reason, processor_mode, alertable, opt_timeout);
}
X_STATUS XFile::Read(void* buffer, size_t buffer_length, size_t byte_offset,
size_t* out_bytes_read) {
if (byte_offset == -1) {
// Read from current position.
byte_offset = position_;
}
X_STATUS result = ReadSync(buffer, buffer_length, byte_offset, out_bytes_read);
if (XSUCCEEDED(result)) {
position_ += *out_bytes_read;
}
return result;
}
X_STATUS XFile::Read(void* buffer, size_t buffer_length, size_t byte_offset,
XAsyncRequest* request) {
// Also tack on our event so that any waiters wake.
request->AddWaitEvent(async_event_);
position_ = byte_offset;
//return entry_->ReadAsync(buffer, buffer_length, byte_offset, request);
X_STATUS result = X_STATUS_NOT_IMPLEMENTED;
return result;
}

View File

@@ -0,0 +1,87 @@
/**
******************************************************************************
* 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_XFILE_H_
#define XENIA_KERNEL_XBOXKRNL_XFILE_H_
#include <xenia/kernel/xboxkrnl/xobject.h>
#include <xenia/xbox.h>
namespace xe {
namespace kernel {
namespace xboxkrnl {
class XAsyncRequest;
class XEvent;
class XFileInfo {
public:
// FILE_NETWORK_OPEN_INFORMATION
uint64_t creation_time;
uint64_t last_access_time;
uint64_t last_write_time;
uint64_t change_time;
uint64_t allocation_size;
uint64_t file_length;
X_FILE_ATTRIBUTES attributes;
void Write(uint8_t* base, uint32_t p) {
XESETUINT64BE(base + p, creation_time);
XESETUINT64BE(base + p + 8, last_access_time);
XESETUINT64BE(base + p + 16, last_write_time);
XESETUINT64BE(base + p + 24, change_time);
XESETUINT64BE(base + p + 32, allocation_size);
XESETUINT64BE(base + p + 40, file_length);
XESETUINT32BE(base + p + 48, attributes);
XESETUINT32BE(base + p + 52, 0); // pad
}
};
class XFile : public XObject {
public:
virtual ~XFile();
size_t position() const { return position_; }
void set_position(size_t value) { position_ = value; }
virtual X_STATUS Wait(uint32_t wait_reason, uint32_t processor_mode,
uint32_t alertable, uint64_t* opt_timeout);
virtual X_STATUS QueryInfo(XFileInfo* out_info) = 0;
X_STATUS Read(void* buffer, size_t buffer_length, size_t byte_offset,
size_t* out_bytes_read);
X_STATUS Read(void* buffer, size_t buffer_length, size_t byte_offset,
XAsyncRequest* request);
protected:
XFile(KernelState* kernel_state, uint32_t desired_access);
virtual X_STATUS ReadSync(
void* buffer, size_t buffer_length, size_t byte_offset,
size_t* out_bytes_read) = 0;
private:
uint32_t desired_access_;
XEvent* async_event_;
// TODO(benvanik): create flags, open state, etc.
size_t position_;
};
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_XFILE_H_

View File

@@ -0,0 +1,330 @@
/**
******************************************************************************
* 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/xboxkrnl/objects/xmodule.h>
#include <xenia/emulator.h>
#include <xenia/cpu/cpu.h>
#include <xenia/kernel/xboxkrnl/objects/xthread.h>
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl;
namespace {
}
XModule::XModule(KernelState* kernel_state, const char* path) :
XObject(kernel_state, kTypeModule),
xex_(NULL) {
XEIGNORE(xestrcpya(path_, XECOUNT(path_), path));
const char* slash = xestrrchra(path, '/');
if (!slash) {
slash = xestrrchra(path, '\\');
}
if (slash) {
XEIGNORE(xestrcpya(name_, XECOUNT(name_), slash + 1));
}
}
XModule::~XModule() {
xe_xex2_release(xex_);
}
const char* XModule::path() {
return path_;
}
const char* XModule::name() {
return name_;
}
xe_xex2_ref XModule::xex() {
return xe_xex2_retain(xex_);
}
const xe_xex2_header_t* XModule::xex_header() {
return xe_xex2_get_header(xex_);
}
X_STATUS XModule::LoadFromFile(const char* path) {
// Resolve the file to open.
// TODO(benvanik): make this code shared?
fs::Entry* fs_entry = kernel_state()->file_system()->ResolvePath(path);
if (!fs_entry) {
XELOGE("File not found: %s", path);
return X_STATUS_NO_SUCH_FILE;
}
if (fs_entry->type() != fs::Entry::kTypeFile) {
XELOGE("Invalid file type: %s", path);
return X_STATUS_NO_SUCH_FILE;
}
// Map into memory.
fs::MemoryMapping* mmap = fs_entry->CreateMemoryMapping(kXEFileModeRead, 0, 0);
if (!mmap) {
return X_STATUS_UNSUCCESSFUL;
}
// Load the module.
X_STATUS return_code = LoadFromMemory(mmap->address(), mmap->length());
// Unmap memory and cleanup.
delete mmap;
delete fs_entry;
return return_code;
}
X_STATUS XModule::LoadFromMemory(const void* addr, const size_t length) {
// Load the XEX into memory and decrypt.
xe_xex2_options_t xex_options;
xe_zero_struct(&xex_options, sizeof(xex_options));
xex_ = xe_xex2_load(kernel_state()->memory(), addr, length, xex_options);
XEEXPECTNOTNULL(xex_);
// Prepare the module for execution.
XEEXPECTZERO(kernel_state()->processor()->LoadXexModule(name_, path_, xex_));
return X_STATUS_SUCCESS;
XECLEANUP:
return X_STATUS_UNSUCCESSFUL;
}
X_STATUS XModule::GetSection(const char* name,
uint32_t* out_data, uint32_t* out_size) {
const PESection* section = xe_xex2_get_pe_section(xex_, name);
if (!section) {
return X_STATUS_UNSUCCESSFUL;
}
*out_data = section->address;
*out_size = section->size;
return X_STATUS_SUCCESS;
}
void* XModule::GetProcAddressByOrdinal(uint16_t ordinal) {
// TODO(benvanik): check export tables.
XELOGE("GetProcAddressByOrdinal not implemented");
return NULL;
}
X_STATUS XModule::Launch(uint32_t flags) {
const xe_xex2_header_t* header = xex_header();
XELOGI("Launching module...");
// Set as the main module, while running.
kernel_state()->SetExecutableModule(this);
Dump();
// Create a thread to run in.
XThread* thread = new XThread(
kernel_state(),
header->exe_stack_size,
0,
header->exe_entry_point, NULL,
0);
X_STATUS result = thread->Create();
if (XFAILED(result)) {
XELOGE("Could not create launch thread: %.8X", result);
return result;
}
// Wait until thread completes.
thread->Wait(0, 0, 0, NULL);
kernel_state()->SetExecutableModule(NULL);
thread->Release();
return X_STATUS_SUCCESS;
}
void XModule::Dump() {
ExportResolver* export_resolver =
kernel_state_->emulator()->export_resolver();
const xe_xex2_header_t* header = xe_xex2_get_header(xex_);
// XEX info.
printf("Module %s:\n\n", path_);
printf(" Module Flags: %.8X\n", header->module_flags);
printf(" System Flags: %.8X\n", header->system_flags);
printf("\n");
printf(" Address: %.8X\n", header->exe_address);
printf(" Entry Point: %.8X\n", header->exe_entry_point);
printf(" Stack Size: %.8X\n", header->exe_stack_size);
printf(" Heap Size: %.8X\n", header->exe_heap_size);
printf("\n");
printf(" Execution Info:\n");
printf(" Media ID: %.8X\n", header->execution_info.media_id);
printf(" Version: %d.%d.%d.%d\n",
header->execution_info.version.major,
header->execution_info.version.minor,
header->execution_info.version.build,
header->execution_info.version.qfe);
printf(" Base Version: %d.%d.%d.%d\n",
header->execution_info.base_version.major,
header->execution_info.base_version.minor,
header->execution_info.base_version.build,
header->execution_info.base_version.qfe);
printf(" Title ID: %.8X\n", header->execution_info.title_id);
printf(" Platform: %.8X\n", header->execution_info.platform);
printf(" Exec Table: %.8X\n", header->execution_info.executable_table);
printf(" Disc Number: %d\n", header->execution_info.disc_number);
printf(" Disc Count: %d\n", header->execution_info.disc_count);
printf(" Savegame ID: %.8X\n", header->execution_info.savegame_id);
printf("\n");
printf(" Loader Info:\n");
printf(" Image Flags: %.8X\n", header->loader_info.image_flags);
printf(" Game Regions: %.8X\n", header->loader_info.game_regions);
printf(" Media Flags: %.8X\n", header->loader_info.media_flags);
printf("\n");
printf(" TLS Info:\n");
printf(" Slot Count: %d\n", header->tls_info.slot_count);
printf(" Data Size: %db\n", header->tls_info.data_size);
printf(" Address: %.8X, %db\n", header->tls_info.raw_data_address,
header->tls_info.raw_data_size);
printf("\n");
printf(" Headers:\n");
for (size_t n = 0; n < header->header_count; n++) {
const xe_xex2_opt_header_t* opt_header = &header->headers[n];
printf(" %.8X (%.8X, %4db) %.8X = %11d\n",
opt_header->key, opt_header->offset, opt_header->length,
opt_header->value, opt_header->value);
}
printf("\n");
// Resources.
printf("Resources:\n");
printf(" %.8X, %db\n", header->resource_info.address,
header->resource_info.size);
printf(" TODO\n");
printf("\n");
// Section info.
printf("Sections:\n");
for (size_t n = 0, i = 0; n < header->section_count; n++) {
const xe_xex2_section_t* section = &header->sections[n];
const char* type = "UNKNOWN";
switch (section->info.type) {
case XEX_SECTION_CODE:
type = "CODE ";
break;
case XEX_SECTION_DATA:
type = "RWDATA ";
break;
case XEX_SECTION_READONLY_DATA:
type = "RODATA ";
break;
}
const size_t start_address =
header->exe_address + (i * xe_xex2_section_length);
const size_t end_address =
start_address + (section->info.page_count * xe_xex2_section_length);
printf(" %3d %s %3d pages %.8X - %.8X (%d bytes)\n",
(int)n, type, section->info.page_count, (int)start_address,
(int)end_address, section->info.page_count * xe_xex2_section_length);
i += section->info.page_count;
}
printf("\n");
// Static libraries.
printf("Static Libraries:\n");
for (size_t n = 0; n < header->static_library_count; n++) {
const xe_xex2_static_library_t *library = &header->static_libraries[n];
printf(" %-8s : %d.%d.%d.%d\n",
library->name, library->major,
library->minor, library->build, library->qfe);
}
printf("\n");
// Imports.
printf("Imports:\n");
for (size_t n = 0; n < header->import_library_count; n++) {
const xe_xex2_import_library_t* library = &header->import_libraries[n];
xe_xex2_import_info_t* import_infos;
size_t import_info_count;
if (!xe_xex2_get_import_infos(xex_, library,
&import_infos, &import_info_count)) {
printf(" %s - %d imports\n", library->name, (int)import_info_count);
printf(" Version: %d.%d.%d.%d\n",
library->version.major, library->version.minor,
library->version.build, library->version.qfe);
printf(" Min Version: %d.%d.%d.%d\n",
library->min_version.major, library->min_version.minor,
library->min_version.build, library->min_version.qfe);
printf("\n");
// Counts.
int known_count = 0;
int unknown_count = 0;
int impl_count = 0;
int unimpl_count = 0;
for (size_t m = 0; m < import_info_count; m++) {
const xe_xex2_import_info_t* info = &import_infos[m];
KernelExport* kernel_export =
export_resolver->GetExportByOrdinal(library->name, info->ordinal);
if (kernel_export) {
known_count++;
if (kernel_export->is_implemented) {
impl_count++;
}
} else {
unknown_count++;
unimpl_count++;
}
}
printf(" Total: %4u\n", import_info_count);
printf(" Known: %3d%% (%d known, %d unknown)\n",
(int)(known_count / (float)import_info_count * 100.0f),
known_count, unknown_count);
printf(" Implemented: %3d%% (%d implemented, %d unimplemented)\n",
(int)(impl_count / (float)import_info_count * 100.0f),
impl_count, unimpl_count);
printf("\n");
// Listing.
for (size_t m = 0; m < import_info_count; m++) {
const xe_xex2_import_info_t* info = &import_infos[m];
KernelExport* kernel_export = export_resolver->GetExportByOrdinal(
library->name, info->ordinal);
const char *name = "UNKNOWN";
bool implemented = false;
if (kernel_export) {
name = kernel_export->name;
implemented = kernel_export->is_implemented;
}
if (info->thunk_address) {
printf(" F %.8X %.8X %.3X (%3d) %s %s\n",
info->value_address, info->thunk_address, info->ordinal,
info->ordinal, implemented ? " " : "!!", name);
} else {
printf(" V %.8X %.3X (%3d) %s %s\n",
info->value_address, info->ordinal, info->ordinal,
implemented ? " " : "!!", name);
}
}
xe_free(import_infos);
}
printf("\n");
}
// Exports.
printf("Exports:\n");
printf(" TODO\n");
printf("\n");
}

View File

@@ -0,0 +1,62 @@
/**
******************************************************************************
* 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_XMODULE_H_
#define XENIA_KERNEL_XBOXKRNL_XMODULE_H_
#include <xenia/kernel/xboxkrnl/xobject.h>
#include <vector>
#include <xenia/export_resolver.h>
#include <xenia/xbox.h>
#include <xenia/kernel/xex2.h>
namespace xe {
namespace kernel {
namespace xboxkrnl {
class XModule : public XObject {
public:
XModule(KernelState* kernel_state, const char* path);
virtual ~XModule();
const char* path();
const char* name();
xe_xex2_ref xex();
const xe_xex2_header_t* xex_header();
X_STATUS LoadFromFile(const char* path);
X_STATUS LoadFromMemory(const void* addr, const size_t length);
X_STATUS GetSection(const char* name, uint32_t* out_data, uint32_t* out_size);
void* GetProcAddressByOrdinal(uint16_t ordinal);
X_STATUS Launch(uint32_t flags);
void Dump();
private:
int LoadPE();
char name_[256];
char path_[XE_MAX_PATH];
xe_xex2_ref xex_;
};
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_XMODULE_H_

View File

@@ -0,0 +1,376 @@
/**
******************************************************************************
* 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/xboxkrnl/objects/xthread.h>
#include <xenia/cpu/cpu.h>
#include <xenia/kernel/xboxkrnl/xboxkrnl_threading.h>
#include <xenia/kernel/xboxkrnl/objects/xevent.h>
#include <xenia/kernel/xboxkrnl/objects/xmodule.h>
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl;
namespace {
static uint32_t next_xthread_id = 0;
static uint32_t current_thread_tls = xeKeTlsAlloc();
static xe_mutex_t* critical_region_ = xe_mutex_alloc(10000);
static XThread* shared_kernel_thread_ = 0;
}
XThread::XThread(KernelState* kernel_state,
uint32_t stack_size,
uint32_t xapi_thread_startup,
uint32_t start_address, uint32_t start_context,
uint32_t creation_flags) :
XObject(kernel_state, kTypeThread),
thread_id_(++next_xthread_id),
thread_handle_(0),
thread_state_address_(0),
thread_state_(0),
event_(NULL),
irql_(0) {
creation_params_.stack_size = stack_size;
creation_params_.xapi_thread_startup = xapi_thread_startup;
creation_params_.start_address = start_address;
creation_params_.start_context = start_context;
creation_params_.creation_flags = creation_flags;
// Adjust stack size - min of 16k.
if (creation_params_.stack_size < 16 * 1024 * 1024) {
creation_params_.stack_size = 16 * 1024 * 1024;
}
event_ = new XEvent(kernel_state);
event_->Initialize(true, false);
}
XThread::~XThread() {
event_->Release();
PlatformDestroy();
if (thread_state_) {
kernel_state()->processor()->DeallocThread(thread_state_);
}
if (tls_address_) {
xe_memory_heap_free(kernel_state()->memory(), tls_address_, 0);
}
if (thread_state_address_) {
xe_memory_heap_free(kernel_state()->memory(), thread_state_address_, 0);
}
if (thread_handle_) {
// TODO(benvanik): platform kill
XELOGE("Thread disposed without exiting");
}
}
XThread* XThread::GetCurrentThread() {
XThread* thread = (XThread*)xeKeTlsGetValue(current_thread_tls);
if (!thread) {
// Assume this is some shared interrupt thread/etc.
XThread::EnterCriticalRegion();
thread = shared_kernel_thread_;
if (!thread) {
thread = new XThread(
KernelState::shared(), 32 * 1024, 0, 0, 0, 0);
shared_kernel_thread_ = thread;
xeKeTlsSetValue(current_thread_tls, (uint64_t)thread);
}
XThread::LeaveCriticalRegion();
}
return thread;
}
uint32_t XThread::GetCurrentThreadHandle() {
XThread* thread = XThread::GetCurrentThread();
return thread->handle();
}
uint32_t XThread::GetCurrentThreadId(const uint8_t* thread_state_block) {
return XEGETUINT32BE(thread_state_block + 0x14C);
}
uint32_t XThread::thread_state() {
return thread_state_address_;
}
uint32_t XThread::thread_id() {
return thread_id_;
}
uint32_t XThread::last_error() {
uint8_t *p = xe_memory_addr(memory(), thread_state_address_);
return XEGETUINT32BE(p + 0x160);
}
void XThread::set_last_error(uint32_t error_code) {
uint8_t *p = xe_memory_addr(memory(), thread_state_address_);
XESETUINT32BE(p + 0x160, error_code);
}
X_STATUS XThread::Create() {
// Allocate thread state block from heap.
// This is set as r13 for user code and some special inlined Win32 calls
// (like GetLastError/etc) will poke it directly.
// We try to use it as our primary store of data just to keep things all
// consistent.
// 0x000: pointer to tls data
// 0x100: pointer to self?
// 0x14C: thread id
// 0x150: if >0 then error states don't get set
// 0x160: last error
// So, at offset 0x100 we have a 4b pointer to offset 200, then have the
// structure.
thread_state_address_ = xe_memory_heap_alloc(
memory(), 0, 2048, XE_MEMORY_FLAG_ZERO);
if (!thread_state_address_) {
XELOGW("Unable to allocate thread state block");
return X_STATUS_NO_MEMORY;
}
// Set native info.
SetNativePointer(thread_state_address_);
XModule* module = kernel_state()->GetExecutableModule();
// Allocate TLS block.
const xe_xex2_header_t* header = module->xex_header();
uint32_t tls_size = header->tls_info.slot_count * header->tls_info.data_size;
tls_address_ = xe_memory_heap_alloc(
memory(), 0, tls_size, XE_MEMORY_FLAG_ZERO);
if (!tls_address_) {
XELOGW("Unable to allocate thread local storage block");
module->Release();
return X_STATUS_NO_MEMORY;
}
// Copy in default TLS info.
// TODO(benvanik): is this correct?
xe_memory_copy(memory(),
tls_address_, header->tls_info.raw_data_address, tls_size);
// Setup the thread state block (last error/etc).
uint8_t *p = xe_memory_addr(memory(), thread_state_address_);
XESETUINT32BE(p + 0x000, tls_address_);
XESETUINT32BE(p + 0x100, thread_state_address_);
XESETUINT32BE(p + 0x14C, thread_id_);
XESETUINT32BE(p + 0x150, 0); // ?
XESETUINT32BE(p + 0x160, 0); // last error
// Allocate processor thread state.
// This is thread safe.
thread_state_ = kernel_state()->processor()->AllocThread(
creation_params_.stack_size, thread_state_address_, thread_id_);
if (!thread_state_) {
XELOGW("Unable to allocate processor thread state");
module->Release();
return X_STATUS_NO_MEMORY;
}
X_STATUS return_code = PlatformCreate();
if (XFAILED(return_code)) {
XELOGW("Unable to create platform thread (%.8X)", return_code);
module->Release();
return return_code;
}
module->Release();
return X_STATUS_SUCCESS;
}
X_STATUS XThread::Exit(int exit_code) {
// TODO(benvanik): set exit code in thread state block
// TODO(benvanik); dispatch events? waiters? etc?
event_->Set(0, false);
// NOTE: unless PlatformExit fails, expect it to never return!
X_STATUS return_code = PlatformExit(exit_code);
if (XFAILED(return_code)) {
return return_code;
}
return X_STATUS_SUCCESS;
}
#if XE_PLATFORM(WIN32)
static uint32_t __stdcall XThreadStartCallbackWin32(void* param) {
XThread* thread = reinterpret_cast<XThread*>(param);
xeKeTlsSetValue(current_thread_tls, (uint64_t)thread);
thread->Execute();
xeKeTlsSetValue(current_thread_tls, NULL);
thread->Release();
return 0;
}
X_STATUS XThread::PlatformCreate() {
thread_handle_ = CreateThread(
NULL,
creation_params_.stack_size,
(LPTHREAD_START_ROUTINE)XThreadStartCallbackWin32,
this,
creation_params_.creation_flags,
NULL);
if (!thread_handle_) {
uint32_t last_error = GetLastError();
// TODO(benvanik): translate?
XELOGE("CreateThread failed with %d", last_error);
return last_error;
}
return X_STATUS_SUCCESS;
}
void XThread::PlatformDestroy() {
CloseHandle(reinterpret_cast<HANDLE>(thread_handle_));
thread_handle_ = NULL;
}
X_STATUS XThread::PlatformExit(int exit_code) {
// NOTE: does not return.
ExitThread(exit_code);
return X_STATUS_SUCCESS;
}
#else
static void* XThreadStartCallbackPthreads(void* param) {
XThread* thread = reinterpret_cast<XThread*>(param);
xeKeTlsSetValue(current_thread_tls, (uint64_t)thread);
thread->Execute();
xeKeTlsSetValue(current_thread_tls, NULL);
thread->Release();
return 0;
}
X_STATUS XThread::PlatformCreate() {
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, creation_params_.stack_size);
int result_code;
if (creation_params_.creation_flags & X_CREATE_SUSPENDED) {
#if XE_PLATFORM(OSX)
result_code = pthread_create_suspended_np(
reinterpret_cast<pthread_t*>(&thread_handle_),
&attr,
&XThreadStartCallbackPthreads,
this);
#else
// TODO(benvanik): pthread_create_suspended_np on linux
XEASSERTALWAYS();
#endif // OSX
} else {
result_code = pthread_create(
reinterpret_cast<pthread_t*>(&thread_handle_),
&attr,
&XThreadStartCallbackPthreads,
this);
}
pthread_attr_destroy(&attr);
switch (result_code) {
case 0:
// Succeeded!
return X_STATUS_SUCCESS;
default:
case EAGAIN:
return X_STATUS_NO_MEMORY;
case EINVAL:
case EPERM:
return X_STATUS_INVALID_PARAMETER;
}
}
void XThread::PlatformDestroy() {
// No-op?
}
X_STATUS XThread::PlatformExit(int exit_code) {
// NOTE: does not return.
pthread_exit((void*)exit_code);
return X_STATUS_SUCCESS;
}
#endif // WIN32
void XThread::Execute() {
// If a XapiThreadStartup value is present, we use that as a trampoline.
// Otherwise, we are a raw thread.
if (creation_params_.xapi_thread_startup) {
kernel_state()->processor()->Execute(
thread_state_,
creation_params_.xapi_thread_startup,
creation_params_.start_address, creation_params_.start_context);
} else {
// Run user code.
int exit_code = (int)kernel_state()->processor()->Execute(
thread_state_,
creation_params_.start_address, creation_params_.start_context);
// If we got here it means the execute completed without an exit being called.
// Treat the return code as an implicit exit code.
Exit(exit_code);
}
}
X_STATUS XThread::Wait(uint32_t wait_reason, uint32_t processor_mode,
uint32_t alertable, uint64_t* opt_timeout) {
return event_->Wait(wait_reason, processor_mode, alertable, opt_timeout);
}
void XThread::EnterCriticalRegion() {
// Global critical region. This isn't right, but is easy.
xe_mutex_lock(critical_region_);
}
void XThread::LeaveCriticalRegion() {
xe_mutex_unlock(critical_region_);
}
uint32_t XThread::RaiseIrql(uint32_t new_irql) {
return xe_atomic_exchange_32(new_irql, &irql_);
}
void XThread::LowerIrql(uint32_t new_irql) {
irql_ = new_irql;
}
X_STATUS XThread::Delay(
uint32_t processor_mode, uint32_t alertable, uint64_t interval) {
int64_t timeout_ticks = interval;
DWORD timeout_ms;
if (timeout_ticks > 0) {
// Absolute time, based on January 1, 1601.
// TODO(benvanik): convert time to relative time.
XEASSERTALWAYS();
timeout_ms = 0;
} else if (timeout_ticks < 0) {
// Relative time.
timeout_ms = (DWORD)(-timeout_ticks / 10000); // Ticks -> MS
} else {
timeout_ms = 0;
}
DWORD result = SleepEx(timeout_ms, alertable ? TRUE : FALSE);
switch (result) {
case 0:
return X_STATUS_SUCCESS;
case WAIT_IO_COMPLETION:
return X_STATUS_USER_APC;
default:
return X_STATUS_ALERTED;
}
}

View File

@@ -0,0 +1,97 @@
/**
******************************************************************************
* 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_XTHREAD_H_
#define XENIA_KERNEL_XBOXKRNL_XTHREAD_H_
#include <xenia/kernel/xboxkrnl/xobject.h>
#include <xenia/xbox.h>
namespace xe {
namespace cpu {
class ThreadState;
}
}
namespace xe {
namespace kernel {
namespace xboxkrnl {
class XEvent;
class XThread : public XObject {
public:
XThread(KernelState* kernel_state,
uint32_t stack_size,
uint32_t xapi_thread_startup,
uint32_t start_address, uint32_t start_context,
uint32_t creation_flags);
virtual ~XThread();
static XThread* GetCurrentThread();
static uint32_t GetCurrentThreadHandle();
static uint32_t GetCurrentThreadId(const uint8_t* thread_state_block);
uint32_t thread_state();
uint32_t thread_id();
uint32_t last_error();
void set_last_error(uint32_t error_code);
X_STATUS Create();
X_STATUS Exit(int exit_code);
void Execute();
virtual X_STATUS Wait(uint32_t wait_reason, uint32_t processor_mode,
uint32_t alertable, uint64_t* opt_timeout);
static void EnterCriticalRegion();
static void LeaveCriticalRegion();
uint32_t RaiseIrql(uint32_t new_irql);
void LowerIrql(uint32_t new_irql);
X_STATUS Delay(
uint32_t processor_mode, uint32_t alertable, uint64_t interval);
private:
X_STATUS PlatformCreate();
void PlatformDestroy();
X_STATUS PlatformExit(int exit_code);
struct {
uint32_t stack_size;
uint32_t xapi_thread_startup;
uint32_t start_address;
uint32_t start_context;
uint32_t creation_flags;
} creation_params_;
uint32_t thread_id_;
void* thread_handle_;
uint32_t tls_address_;
uint32_t thread_state_address_;
cpu::ThreadState* thread_state_;
uint32_t irql_;
XEvent* event_;
};
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_XTHREAD_H_

View File

@@ -0,0 +1,45 @@
# Copyright 2013 Ben Vanik. All Rights Reserved.
{
'sources': [
'async_request.cc',
'async_request.h',
'kernel_state.cc',
'kernel_state.h',
'object_table.cc',
'object_table.h',
'xboxkrnl_debug.cc',
'xboxkrnl_debug.h',
'xboxkrnl_hal.cc',
'xboxkrnl_hal.h',
'xboxkrnl_io.cc',
'xboxkrnl_io.h',
'xboxkrnl_memory.cc',
'xboxkrnl_memory.h',
'xboxkrnl_misc.cc',
'xboxkrnl_misc.h',
'xboxkrnl_module.cc',
'xboxkrnl_module.h',
'xboxkrnl_modules.cc',
'xboxkrnl_modules.h',
'xboxkrnl_nt.cc',
'xboxkrnl_nt.h',
'xboxkrnl_ob.cc',
'xboxkrnl_ob.h',
'xboxkrnl_ordinals.h',
'xboxkrnl_private.h',
'xboxkrnl_rtl.cc',
'xboxkrnl_rtl.h',
'xboxkrnl_table.inc',
'xboxkrnl_threading.cc',
'xboxkrnl_threading.h',
'xboxkrnl_video.cc',
'xboxkrnl_video.h',
'xobject.cc',
'xobject.h',
],
'includes': [
'fs/sources.gypi',
'objects/sources.gypi',
],
}

View File

@@ -0,0 +1,242 @@
/**
******************************************************************************
* 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/xboxkrnl/xboxkrnl_debug.h>
#include <xenia/kernel/shim_utils.h>
#include <xenia/kernel/xboxkrnl/kernel_state.h>
#include <xenia/kernel/xboxkrnl/xboxkrnl_private.h>
#include <xenia/kernel/xboxkrnl/objects/xthread.h>
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl;
namespace xe {
namespace kernel {
namespace xboxkrnl {
// TODO: clean me up!
SHIM_CALL DbgPrint_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t format_ptr = SHIM_GET_ARG_32(0);
if (format_ptr == 0) {
SHIM_SET_RETURN(-1);
return;
}
const char *format = (const char *)SHIM_MEM_ADDR(format_ptr);
int arg_index = 0;
char buffer[512]; // TODO: ensure it never writes past the end of the buffer...
char *b = buffer;
for (; *format != '\0'; ++format) {
const char *start = format;
if (*format != '%') {
*b++ = *format;
continue;
}
++format;
if (*format == '\0') {
break;
}
if (*format == '%') {
*b++ = *format;
continue;
}
const char *end;
end = format;
// skip flags
while (*end == '-' ||
*end == '+' ||
*end == ' ' ||
*end == '#' ||
*end == '0') {
++end;
}
if (*end == '\0') {
break;
}
int arg_extras = 0;
// skip width
if (*end == '*') {
++end;
arg_extras++;
}
else {
while (*end >= '0' && *end <= '9') {
++end;
}
}
if (*end == '\0') {
break;
}
// skip precision
if (*end == '.') {
++end;
if (*end == '*') {
++end;
++arg_extras;
}
else {
while (*end >= '0' && *end <= '9') {
++end;
}
}
}
if (*end == '\0') {
break;
}
// get length
int arg_size = 4;
if (*end == 'h') {
++end;
arg_size = 4;
if (*end == 'h') {
++end;
}
}
else if (*end == 'l') {
++end;
arg_size = 4;
if (*end == 'l') {
++end;
arg_size = 8;
}
}
else if (*end == 'j') {
arg_size = 8;
++end;
}
else if (*end == 'z') {
arg_size = 4;
++end;
}
else if (*end == 't') {
arg_size = 8;
++end;
}
else if (*end == 'L') {
arg_size = 8;
++end;
}
if (*end == '\0') {
break;
}
if (*end == 'd' ||
*end == 'i' ||
*end == 'u' ||
*end == 'o' ||
*end == 'x' ||
*end == 'X' ||
*end == 'f' ||
*end == 'F' ||
*end == 'e' ||
*end == 'E' ||
*end == 'g' ||
*end == 'G' ||
*end == 'a' ||
*end == 'A' ||
*end == 'c') {
char local[512];
local[0] = '\0';
strncat(local, start, end + 1 - start);
XEASSERT(arg_size == 8 || arg_size == 4);
if (arg_size == 8) {
if (arg_extras == 0) {
uint64_t value = arg_index < 7
? SHIM_GET_ARG_64(1 + arg_index)
: SHIM_MEM_32(SHIM_GPR_32(1) + 16 + ((1 + arg_index) * 8));
int result = sprintf(b, local, value);
b += result;
arg_index++;
}
else {
XEASSERT(false);
}
}
else if (arg_size == 4) {
if (arg_extras == 0) {
uint64_t value = arg_index < 7
? SHIM_GET_ARG_64(1 + arg_index)
: SHIM_MEM_32(SHIM_GPR_32(1) + 16 + ((1 + arg_index) * 8));
int result = sprintf(b, local, (uint32_t)value);
b += result;
arg_index++;
}
else {
XEASSERT(false);
}
}
}
else if (*end == 's' ||
*end == 'p' ||
*end == 'n') {
char local[512];
local[0] = '\0';
strncat(local, start, end + 1 - start);
XEASSERT(arg_size == 4);
if (arg_extras == 0) {
uint32_t value = arg_index < 7
? SHIM_GET_ARG_32(1 + arg_index)
: (uint32_t)SHIM_MEM_64(SHIM_GPR_32(1) + 16 + ((1 + arg_index) * 8));
const char *pointer = (const char *)SHIM_MEM_ADDR(value);
int result = sprintf(b, local, pointer);
b += result;
arg_index++;
}
else {
XEASSERT(false);
}
}
else {
XEASSERT(false);
break;
}
format = end;
}
*b++ = '\0';
XELOGD("(DbgPrint) %s", buffer);
}
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
void xe::kernel::xboxkrnl::RegisterDebugExports(
ExportResolver* export_resolver, KernelState* state) {
SHIM_SET_MAPPING("xboxkrnl.exe", DbgPrint, state);
}

View File

@@ -0,0 +1,29 @@
/**
******************************************************************************
* 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_DEBUG_H_
#define XENIA_KERNEL_XBOXKRNL_DEBUG_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/xbox.h>
namespace xe {
namespace kernel {
namespace xboxkrnl {
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_DEBUG_H_

View File

@@ -0,0 +1,64 @@
/**
******************************************************************************
* 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/xboxkrnl/xboxkrnl_hal.h>
#include <xenia/kernel/shim_utils.h>
#include <xenia/kernel/xboxkrnl/kernel_state.h>
#include <xenia/kernel/xboxkrnl/xboxkrnl_private.h>
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl;
namespace xe {
namespace kernel {
namespace xboxkrnl {
void xeHalReturnToFirmware(uint32_t routine) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
// void
// IN FIRMWARE_REENTRY Routine
// Routine must be 1 'HalRebootRoutine'
XEASSERT(routine == 1);
// TODO(benvank): diediedie much more gracefully
// Not sure how to blast back up the stack in LLVM without exceptions, though.
XELOGE("Game requested shutdown via HalReturnToFirmware");
exit(0);
}
SHIM_CALL HalReturnToFirmware_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t routine = SHIM_GET_ARG_32(0);
XELOGD(
"HalReturnToFirmware(%d)",
routine);
xeHalReturnToFirmware(routine);
}
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
void xe::kernel::xboxkrnl::RegisterHalExports(
ExportResolver* export_resolver, KernelState* state) {
SHIM_SET_MAPPING("xboxkrnl.exe", HalReturnToFirmware, state);
}

View File

@@ -0,0 +1,32 @@
/**
******************************************************************************
* 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_HAL_H_
#define XENIA_KERNEL_XBOXKRNL_HAL_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/xbox.h>
namespace xe {
namespace kernel {
namespace xboxkrnl {
void xeHalReturnToFirmware(uint32_t routine);
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_HAL_H_

View File

@@ -0,0 +1,406 @@
/**
******************************************************************************
* 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/xboxkrnl/xboxkrnl_io.h>
#include <xenia/kernel/shim_utils.h>
#include <xenia/kernel/xboxkrnl/async_request.h>
#include <xenia/kernel/xboxkrnl/kernel_state.h>
#include <xenia/kernel/xboxkrnl/xboxkrnl_private.h>
#include <xenia/kernel/xboxkrnl/objects/xevent.h>
#include <xenia/kernel/xboxkrnl/objects/xfile.h>
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl;
using namespace xe::kernel::xboxkrnl::fs;
namespace xe {
namespace kernel {
namespace xboxkrnl {
SHIM_CALL NtCreateFile_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t handle_ptr = SHIM_GET_ARG_32(0);
uint32_t desired_access = SHIM_GET_ARG_32(1);
uint32_t object_attributes_ptr = SHIM_GET_ARG_32(2);
uint32_t io_status_block_ptr = SHIM_GET_ARG_32(3);
uint32_t allocation_size_ptr = SHIM_GET_ARG_32(4);
uint32_t file_attributes = SHIM_GET_ARG_32(5);
uint32_t share_access = SHIM_GET_ARG_32(6);
uint32_t creation_disposition = SHIM_GET_ARG_32(7);
X_OBJECT_ATTRIBUTES attrs(SHIM_MEM_BASE, object_attributes_ptr);
XELOGD(
"NtCreateFile(%.8X, %.8X, %.8X(%s), %.8X, %.8X, %.8X, %d, %d)",
handle_ptr,
desired_access,
object_attributes_ptr,
attrs.object_name.buffer,
io_status_block_ptr,
allocation_size_ptr,
file_attributes,
share_access,
creation_disposition);
uint64_t allocation_size = 0; // is this correct???
if (allocation_size_ptr != 0) {
allocation_size = SHIM_MEM_64(allocation_size_ptr);
}
X_STATUS result = X_STATUS_NO_SUCH_FILE;
uint32_t info = X_FILE_DOES_NOT_EXIST;
uint32_t handle;
// Resolve the file using the virtual file system.
FileSystem* fs = state->file_system();
Entry* entry = fs->ResolvePath(attrs.object_name.buffer);
XFile* file = NULL;
if (entry && entry->type() == Entry::kTypeFile) {
// Open the file.
result = entry->Open(
state,
desired_access,
false, // TODO(benvanik): pick async mode, if needed.
&file);
} else {
result = X_STATUS_NO_SUCH_FILE;
info = X_FILE_DOES_NOT_EXIST;
}
if (XSUCCEEDED(result)) {
// Handle ref is incremented, so return that.
handle = file->handle();
file->Release();
result = X_STATUS_SUCCESS;
info = X_FILE_OPENED;
}
if (io_status_block_ptr) {
SHIM_SET_MEM_32(io_status_block_ptr, result); // Status
SHIM_SET_MEM_32(io_status_block_ptr + 4, info); // Information
}
if (XSUCCEEDED(result)) {
if (handle_ptr) {
SHIM_SET_MEM_32(handle_ptr, handle);
}
}
SHIM_SET_RETURN(result);
}
SHIM_CALL NtOpenFile_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
SHIM_SET_RETURN(X_STATUS_NO_SUCH_FILE);
}
class xeNtReadFileState {
public:
uint32_t x;
};
void xeNtReadFileCompleted(XAsyncRequest* request, xeNtReadFileState* state) {
// TODO(benvanik): set io_status_block_ptr
delete request;
delete state;
}
SHIM_CALL NtReadFile_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t file_handle = SHIM_GET_ARG_32(0);
uint32_t event_handle = SHIM_GET_ARG_32(1);
uint32_t apc_routine_ptr = SHIM_GET_ARG_32(2);
uint32_t apc_context = SHIM_GET_ARG_32(3);
uint32_t io_status_block_ptr = SHIM_GET_ARG_32(4);
uint32_t buffer = SHIM_GET_ARG_32(5);
uint32_t buffer_length = SHIM_GET_ARG_32(6);
uint32_t byte_offset_ptr = SHIM_GET_ARG_32(7);
size_t byte_offset = byte_offset_ptr ? SHIM_MEM_64(byte_offset_ptr) : 0;
XELOGD(
"NtReadFile(%.8X, %.8X, %.8X, %.8X, %.8X, %.8X, %d, %d)",
file_handle,
event_handle,
apc_routine_ptr,
apc_context,
io_status_block_ptr,
buffer,
buffer_length,
byte_offset_ptr);
// Async not supported yet.
XEASSERTNULL(apc_routine_ptr);
X_STATUS result = X_STATUS_SUCCESS;
uint32_t info = 0;
// Grab event to signal.
XEvent* ev = NULL;
bool signal_event = false;
if (event_handle) {
result = state->object_table()->GetObject(
event_handle, (XObject**)&ev);
}
// Grab file.
XFile* file = NULL;
if (XSUCCEEDED(result)) {
result = state->object_table()->GetObject(
file_handle, (XObject**)&file);
}
// Execute read.
if (XSUCCEEDED(result)) {
// Reset event before we begin.
if (ev) {
ev->Reset();
}
// TODO(benvanik): async path.
if (true) {
// Synchronous request.
if (!byte_offset_ptr ||
byte_offset == 0xFFFFFFFFfffffffe) {
// FILE_USE_FILE_POINTER_POSITION
byte_offset = -1;
}
// Read now.
size_t bytes_read = 0;
result = file->Read(
SHIM_MEM_ADDR(buffer), buffer_length, byte_offset,
&bytes_read);
if (XSUCCEEDED(result)) {
info = (int32_t)bytes_read;
}
// Mark that we should signal the event now. We do this after
// we have written the info out.
signal_event = true;
} else {
// X_STATUS_PENDING if not returning immediately.
// XFile is waitable and signalled after each async req completes.
// reset the input event (->Reset())
/*xeNtReadFileState* call_state = new xeNtReadFileState();
XAsyncRequest* request = new XAsyncRequest(
state, file,
(XAsyncRequest::CompletionCallback)xeNtReadFileCompleted,
call_state);*/
//result = file->Read(buffer, buffer_length, byte_offset, request);
result = X_STATUS_PENDING;
info = 0;
}
}
if (io_status_block_ptr) {
SHIM_SET_MEM_32(io_status_block_ptr, result); // Status
SHIM_SET_MEM_32(io_status_block_ptr + 4, info); // Information
}
if (file) {
file->Release();
}
if (ev) {
if (signal_event) {
ev->Set(0, false);
}
ev->Release();
}
SHIM_SET_RETURN(result);
}
SHIM_CALL NtSetInformationFile_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t file_handle = SHIM_GET_ARG_32(0);
uint32_t io_status_block_ptr = SHIM_GET_ARG_32(1);
uint32_t file_info_ptr = SHIM_GET_ARG_32(2);
uint32_t length = SHIM_GET_ARG_32(3);
uint32_t file_info_class = SHIM_GET_ARG_32(4);
XELOGD(
"NtSetInformationFile(%.8X, %.8X, %.8X, %.8X, %.8X)",
file_handle,
io_status_block_ptr,
file_info_ptr,
length,
file_info_class);
X_STATUS result = X_STATUS_SUCCESS;
uint32_t info = 0;
// Grab file.
XFile* file = NULL;
result = state->object_table()->GetObject(
file_handle, (XObject**)&file);
if (XSUCCEEDED(result)) {
result = X_STATUS_SUCCESS;
switch (file_info_class) {
case XFilePositionInformation:
// struct FILE_POSITION_INFORMATION {
// LARGE_INTEGER CurrentByteOffset;
// };
XEASSERT(length == 8);
info = 8;
file->set_position(SHIM_MEM_64(file_info_ptr));
break;
default:
// Unsupported, for now.
XEASSERTALWAYS();
info = 0;
break;
}
}
if (XFAILED(result)) {
info = 0;
}
if (io_status_block_ptr) {
SHIM_SET_MEM_32(io_status_block_ptr, result); // Status
SHIM_SET_MEM_32(io_status_block_ptr + 4, info); // Information
}
if (file) {
file->Release();
}
SHIM_SET_RETURN(result);
}
SHIM_CALL NtQueryInformationFile_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t file_handle = SHIM_GET_ARG_32(0);
uint32_t io_status_block_ptr = SHIM_GET_ARG_32(1);
uint32_t file_info_ptr = SHIM_GET_ARG_32(2);
uint32_t length = SHIM_GET_ARG_32(3);
uint32_t file_info_class = SHIM_GET_ARG_32(4);
XELOGD(
"NtQueryInformationFile(%.8X, %.8X, %.8X, %.8X, %.8X)",
file_handle,
io_status_block_ptr,
file_info_ptr,
length,
file_info_class);
X_STATUS result = X_STATUS_SUCCESS;
uint32_t info = 0;
// Grab file.
XFile* file = NULL;
result = state->object_table()->GetObject(
file_handle, (XObject**)&file);
if (XSUCCEEDED(result)) {
result = X_STATUS_SUCCESS;
switch (file_info_class) {
case XFilePositionInformation:
// struct FILE_POSITION_INFORMATION {
// LARGE_INTEGER CurrentByteOffset;
// };
XEASSERT(length == 8);
info = 8;
SHIM_SET_MEM_64(file_info_ptr, file->position());
break;
case XFileNetworkOpenInformation:
// struct FILE_NETWORK_OPEN_INFORMATION {
// LARGE_INTEGER CreationTime;
// LARGE_INTEGER LastAccessTime;
// LARGE_INTEGER LastWriteTime;
// LARGE_INTEGER ChangeTime;
// LARGE_INTEGER AllocationSize;
// LARGE_INTEGER EndOfFile;
// ULONG FileAttributes;
// ULONG Unknown;
// };
XEASSERT(length == 56);
XFileInfo file_info;
result = file->QueryInfo(&file_info);
if (XSUCCEEDED(result)) {
info = 56;
file_info.Write(SHIM_MEM_BASE, file_info_ptr);
}
break;
default:
// Unsupported, for now.
XEASSERTALWAYS();
info = 0;
break;
}
}
if (XFAILED(result)) {
info = 0;
}
if (io_status_block_ptr) {
SHIM_SET_MEM_32(io_status_block_ptr, result); // Status
SHIM_SET_MEM_32(io_status_block_ptr + 4, info); // Information
}
if (file) {
file->Release();
}
SHIM_SET_RETURN(result);
}
SHIM_CALL NtQueryFullAttributesFile_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t object_attributes_ptr = SHIM_GET_ARG_32(0);
uint32_t file_info_ptr = SHIM_GET_ARG_32(1);
X_OBJECT_ATTRIBUTES attrs(SHIM_MEM_BASE, object_attributes_ptr);
XELOGD(
"NtQueryFullAttributesFile(%.8X(%s), %.8X)",
object_attributes_ptr,
attrs.object_name.buffer,
file_info_ptr);
X_STATUS result = X_STATUS_NO_SUCH_FILE;
// Resolve the file using the virtual file system.
FileSystem* fs = state->file_system();
Entry* entry = fs->ResolvePath(attrs.object_name.buffer);
if (entry && entry->type() == Entry::kTypeFile) {
// Found.
XFileInfo file_info;
result = entry->QueryInfo(&file_info);
if (XSUCCEEDED(result)) {
file_info.Write(SHIM_MEM_BASE, file_info_ptr);
}
}
SHIM_SET_RETURN(result);
}
SHIM_CALL NtQueryVolumeInformationFile_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
SHIM_SET_RETURN(X_STATUS_NO_SUCH_FILE);
}
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
void xe::kernel::xboxkrnl::RegisterIoExports(
ExportResolver* export_resolver, KernelState* state) {
SHIM_SET_MAPPING("xboxkrnl.exe", NtCreateFile, state);
SHIM_SET_MAPPING("xboxkrnl.exe", NtOpenFile, state);
SHIM_SET_MAPPING("xboxkrnl.exe", NtReadFile, state);
SHIM_SET_MAPPING("xboxkrnl.exe", NtQueryInformationFile, state);
SHIM_SET_MAPPING("xboxkrnl.exe", NtSetInformationFile, state);
SHIM_SET_MAPPING("xboxkrnl.exe", NtQueryFullAttributesFile, state);
SHIM_SET_MAPPING("xboxkrnl.exe", NtQueryVolumeInformationFile, state);
}

View File

@@ -0,0 +1,29 @@
/**
******************************************************************************
* 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_IO_H_
#define XENIA_KERNEL_XBOXKRNL_IO_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/xbox.h>
namespace xe {
namespace kernel {
namespace xboxkrnl {
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_IO_H_

View File

@@ -0,0 +1,385 @@
/**
******************************************************************************
* 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/xboxkrnl/xboxkrnl_memory.h>
#include <xenia/kernel/shim_utils.h>
#include <xenia/kernel/xboxkrnl/kernel_state.h>
#include <xenia/kernel/xboxkrnl/xboxkrnl_private.h>
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl;
namespace xe {
namespace kernel {
namespace xboxkrnl {
X_STATUS xeNtAllocateVirtualMemory(
uint32_t* base_addr_ptr, uint32_t* region_size_ptr,
uint32_t allocation_type, uint32_t protect_bits,
uint32_t unknown) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
// NTSTATUS
// _Inout_ PVOID *BaseAddress,
// _Inout_ PSIZE_T RegionSize,
// _In_ ULONG AllocationType,
// _In_ ULONG Protect
// ? handle?
// I've only seen zero.
XEASSERT(unknown == 0);
// This allocates memory from the kernel heap, which is initialized on startup
// and shared by both the kernel implementation and user code.
// The xe_memory_ref object is used to actually get the memory, and although
// it's simple today we could extend it to do better things in the future.
// Must request a size.
if (!*region_size_ptr) {
return X_STATUS_INVALID_PARAMETER;
}
// Check allocation type.
if (!(allocation_type & (X_MEM_COMMIT | X_MEM_RESET | X_MEM_RESERVE))) {
return X_STATUS_INVALID_PARAMETER;
}
// If MEM_RESET is set only MEM_RESET can be set.
if (allocation_type & X_MEM_RESET && (allocation_type & ~X_MEM_RESET)) {
return X_STATUS_INVALID_PARAMETER;
}
// Don't allow games to set execute bits.
if (protect_bits & (X_PAGE_EXECUTE | X_PAGE_EXECUTE_READ |
X_PAGE_EXECUTE_READWRITE | X_PAGE_EXECUTE_WRITECOPY)) {
return X_STATUS_ACCESS_DENIED;
}
// Adjust size.
uint32_t adjusted_size = *region_size_ptr;
// TODO(benvanik): adjust based on page size flags/etc?
// TODO(benvanik): support different allocation types.
// Right now we treat everything as a commit and ignore allocations that have
// already happened.
if (*base_addr_ptr) {
// Having a pointer already means that this is likely a follow-on COMMIT.
return X_STATUS_SUCCESS;
}
// Allocate.
uint32_t flags = 0;
uint32_t addr = xe_memory_heap_alloc(
state->memory(), *base_addr_ptr, adjusted_size, flags);
if (!addr) {
// Failed - assume no memory available.
return X_STATUS_NO_MEMORY;
}
// Stash back.
// Maybe set X_STATUS_ALREADY_COMMITTED if MEM_COMMIT?
*base_addr_ptr = addr;
*region_size_ptr = adjusted_size;
return X_STATUS_SUCCESS;
}
SHIM_CALL NtAllocateVirtualMemory_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t base_addr_ptr = SHIM_GET_ARG_32(0);
uint32_t base_addr_value = SHIM_MEM_32(base_addr_ptr);
uint32_t region_size_ptr = SHIM_GET_ARG_32(1);
uint32_t region_size_value = SHIM_MEM_32(region_size_ptr);
uint32_t allocation_type = SHIM_GET_ARG_32(2); // X_MEM_* bitmask
uint32_t protect_bits = SHIM_GET_ARG_32(3); // X_PAGE_* bitmask
uint32_t unknown = SHIM_GET_ARG_32(4);
XELOGD(
"NtAllocateVirtualMemory(%.8X(%.8X), %.8X(%.8X), %.8X, %.8X, %.8X)",
base_addr_ptr, base_addr_value,
region_size_ptr, region_size_value,
allocation_type, protect_bits, unknown);
X_STATUS result = xeNtAllocateVirtualMemory(
&base_addr_value, &region_size_value,
allocation_type, protect_bits, unknown);
if (XSUCCEEDED(result)) {
SHIM_SET_MEM_32(base_addr_ptr, base_addr_value);
SHIM_SET_MEM_32(region_size_ptr, region_size_value);
}
SHIM_SET_RETURN(result);
}
X_STATUS xeNtFreeVirtualMemory(
uint32_t* base_addr_ptr, uint32_t* region_size_ptr,
uint32_t free_type, uint32_t unknown) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
// NTSTATUS
// _Inout_ PVOID *BaseAddress,
// _Inout_ PSIZE_T RegionSize,
// _In_ ULONG FreeType
// ? handle?
// I've only seen zero.
XEASSERT(unknown == 0);
if (!*base_addr_ptr) {
return X_STATUS_MEMORY_NOT_ALLOCATED;
}
// TODO(benvanik): ignore decommits for now.
if (free_type == X_MEM_DECOMMIT) {
return X_STATUS_SUCCESS;
}
// Free.
uint32_t flags = 0;
uint32_t freed_size = xe_memory_heap_free(state->memory(), *base_addr_ptr,
flags);
if (!freed_size) {
return X_STATUS_UNSUCCESSFUL;
}
// Stash back.
*region_size_ptr = freed_size;
return X_STATUS_SUCCESS;
}
SHIM_CALL NtFreeVirtualMemory_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t base_addr_ptr = SHIM_GET_ARG_32(0);
uint32_t base_addr_value = SHIM_MEM_32(base_addr_ptr);
uint32_t region_size_ptr = SHIM_GET_ARG_32(1);
uint32_t region_size_value = SHIM_MEM_32(region_size_ptr);
// X_MEM_DECOMMIT | X_MEM_RELEASE
uint32_t free_type = SHIM_GET_ARG_32(2);
uint32_t unknown = SHIM_GET_ARG_32(3);
XELOGD(
"NtFreeVirtualMemory(%.8X(%.8X), %.8X(%.8X), %.8X, %.8X)",
base_addr_ptr, base_addr_value,
region_size_ptr, region_size_value,
free_type, unknown);
X_STATUS result = xeNtFreeVirtualMemory(
&base_addr_value, &region_size_value,
free_type, unknown);
if (XSUCCEEDED(result)) {
SHIM_SET_MEM_32(base_addr_ptr, base_addr_value);
SHIM_SET_MEM_32(region_size_ptr, region_size_value);
}
SHIM_SET_RETURN(result);
}
uint32_t xeMmAllocatePhysicalMemoryEx(
uint32_t type, uint32_t region_size, uint32_t protect_bits,
uint32_t min_addr_range, uint32_t max_addr_range, uint32_t alignment) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
// Type will usually be 0 (user request?), where 1 and 2 are sometimes made
// by D3D/etc.
// Check protection bits.
if (!(protect_bits & (X_PAGE_READONLY | X_PAGE_READWRITE))) {
XELOGE("MmAllocatePhysicalMemoryEx: bad protection bits");
return 0;
}
// Either may be OR'ed into protect_bits:
// X_PAGE_NOCACHE
// X_PAGE_WRITECOMBINE
// We could use this to detect what's likely GPU-synchronized memory
// and let the GPU know we're messing with it (or even allocate from
// the GPU). At least the D3D command buffer is X_PAGE_WRITECOMBINE.
// Calculate page size.
// Default = 4KB
// X_MEM_LARGE_PAGES = 64KB
// X_MEM_16MB_PAGES = 16MB
uint32_t page_size = 4 * 1024;
if (protect_bits & X_MEM_LARGE_PAGES) {
page_size = 64 * 1024;
} else if (protect_bits & X_MEM_16MB_PAGES) {
page_size = 16 * 1024 * 1024;
}
// Round up the region size and alignment to the next page.
uint32_t adjusted_size = XEROUNDUP(region_size, page_size);
uint32_t adjusted_alignment = XEROUNDUP(alignment, page_size);
// Callers can pick an address to allocate with min_addr_range/max_addr_range
// and the memory must be allocated there. I haven't seen a game do this,
// and instead they all do min=0 / max=-1 to indicate the system should pick.
// If we have to suport arbitrary placement things will get nasty.
XEASSERT(min_addr_range == 0);
XEASSERT(max_addr_range == 0xFFFFFFFF);
// Allocate.
uint32_t flags = XE_MEMORY_FLAG_PHYSICAL;
uint32_t base_address = xe_memory_heap_alloc(
state->memory(), 0, adjusted_size, flags, adjusted_alignment);
if (!base_address) {
// Failed - assume no memory available.
return 0;
}
// Move the address into the right range.
//if (protect_bits & X_MEM_LARGE_PAGES) {
// base_address += 0xA0000000;
//} else if (protect_bits & X_MEM_16MB_PAGES) {
// base_address += 0xC0000000;
//} else {
// base_address += 0xE0000000;
//}
base_address += 0xA0000000;
return base_address;
}
SHIM_CALL MmAllocatePhysicalMemoryEx_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t type = SHIM_GET_ARG_32(0);
uint32_t region_size = SHIM_GET_ARG_32(1);
uint32_t protect_bits = SHIM_GET_ARG_32(2);
uint32_t min_addr_range = SHIM_GET_ARG_32(3);
uint32_t max_addr_range = SHIM_GET_ARG_32(4);
uint32_t alignment = SHIM_GET_ARG_32(5);
XELOGD(
"MmAllocatePhysicalMemoryEx(%d, %.8X, %.8X, %.8X, %.8X, %.8X)",
type, region_size, protect_bits,
min_addr_range, max_addr_range, alignment);
uint32_t base_address = xeMmAllocatePhysicalMemoryEx(
type, region_size, protect_bits,
min_addr_range, max_addr_range, alignment);
SHIM_SET_RETURN(base_address);
}
void xeMmFreePhysicalMemory(uint32_t type, uint32_t base_address) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
// base_address = result of MmAllocatePhysicalMemory.
// Strip off physical bits before passing down.
base_address &= ~0xE0000000;
// TODO(benvanik): free memory.
XELOGE("xeMmFreePhysicalMemory NOT IMPLEMENTED");
//uint32_t size = ?;
//xe_memory_heap_free(
// state->memory(), base_address, size);
}
SHIM_CALL MmFreePhysicalMemory_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t type = SHIM_GET_ARG_32(0);
uint32_t base_address = SHIM_GET_ARG_32(1);
XELOGD(
"MmFreePhysicalAddress(%d, %.8X)",
type, base_address);
xeMmFreePhysicalMemory(type, base_address);
}
uint32_t xeMmQueryAddressProtect(uint32_t base_address) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
uint32_t access = xe_memory_query_protect(
state->memory(), base_address);
return access;
}
SHIM_CALL MmQueryAddressProtect_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t base_address = SHIM_GET_ARG_32(0);
XELOGD(
"MmQueryAddressProtect(%.8X)",
base_address);
uint32_t result = xeMmQueryAddressProtect(base_address);
SHIM_SET_RETURN(result);
}
// http://msdn.microsoft.com/en-us/library/windows/hardware/ff554547(v=vs.85).aspx
uint32_t xeMmGetPhysicalAddress(uint32_t base_address) {
// PHYSICAL_ADDRESS MmGetPhysicalAddress(
// _In_ PVOID BaseAddress
// );
// base_address = result of MmAllocatePhysicalMemory.
// We are always using virtual addresses, right now, since we don't need
// physical ones. We could munge up the address here to another mapped view
// of memory.
/*if (protect_bits & X_MEM_LARGE_PAGES) {
base_address |= 0xA0000000;
} else if (protect_bits & X_MEM_16MB_PAGES) {
base_address |= 0xC0000000;
} else {
base_address |= 0xE0000000;
}*/
return base_address;
}
SHIM_CALL MmGetPhysicalAddress_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t base_address = SHIM_GET_ARG_32(0);
XELOGD(
"MmGetPhysicalAddress(%.8X)",
base_address);
uint32_t result = xeMmGetPhysicalAddress(base_address);
SHIM_SET_RETURN(result);
}
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
void xe::kernel::xboxkrnl::RegisterMemoryExports(
ExportResolver* export_resolver, KernelState* state) {
SHIM_SET_MAPPING("xboxkrnl.exe", NtAllocateVirtualMemory, state);
SHIM_SET_MAPPING("xboxkrnl.exe", NtFreeVirtualMemory, state);
//SHIM_SET_MAPPING("xboxkrnl.exe", MmAllocatePhysicalMemory, state);
SHIM_SET_MAPPING("xboxkrnl.exe", MmAllocatePhysicalMemoryEx, state);
SHIM_SET_MAPPING("xboxkrnl.exe", MmFreePhysicalMemory, state);
SHIM_SET_MAPPING("xboxkrnl.exe", MmQueryAddressProtect, state);
SHIM_SET_MAPPING("xboxkrnl.exe", MmGetPhysicalAddress, state);
}

View File

@@ -0,0 +1,45 @@
/**
******************************************************************************
* 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_MEMORY_H_
#define XENIA_KERNEL_XBOXKRNL_MEMORY_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/xbox.h>
namespace xe {
namespace kernel {
namespace xboxkrnl {
X_STATUS xeNtAllocateVirtualMemory(
uint32_t* base_addr_ptr, uint32_t* region_size_ptr,
uint32_t allocation_type, uint32_t protect_bits,
uint32_t unknown);
X_STATUS xeNtFreeVirtualMemory(
uint32_t* base_addr_ptr, uint32_t* region_size_ptr,
uint32_t free_type, uint32_t unknown);
uint32_t xeMmAllocatePhysicalMemoryEx(
uint32_t type, uint32_t region_size, uint32_t protect_bits,
uint32_t min_addr_range, uint32_t max_addr_range, uint32_t alignment);
void xeMmFreePhysicalMemory(uint32_t type, uint32_t base_address);
uint32_t xeMmQueryAddressProtect(uint32_t base_address);
uint32_t xeMmGetPhysicalAddress(uint32_t base_address);
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_MEMORY_H_

View File

@@ -0,0 +1,59 @@
/**
******************************************************************************
* 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/xboxkrnl/xboxkrnl_misc.h>
#include <xenia/kernel/shim_utils.h>
#include <xenia/kernel/xboxkrnl/kernel_state.h>
#include <xenia/kernel/xboxkrnl/xboxkrnl_private.h>
#include <xenia/kernel/xboxkrnl/objects/xthread.h>
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl;
namespace xe {
namespace kernel {
namespace xboxkrnl {
void xeKeBugCheckEx(uint32_t code, uint32_t param1, uint32_t param2, uint32_t param3, uint32_t param4) {
XELOGD("*** STOP: 0x%.8X (0x%.8X, 0x%.8X, 0x%.8X, 0x%.8X)", code, param1, param2, param3, param4);
XEASSERTALWAYS();
}
SHIM_CALL KeBugCheck_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t code = SHIM_GET_ARG_32(0);
xeKeBugCheckEx(code, 0, 0, 0, 0);
}
SHIM_CALL KeBugCheckEx_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t code = SHIM_GET_ARG_32(0);
uint32_t param1 = SHIM_GET_ARG_32(1);
uint32_t param2 = SHIM_GET_ARG_32(2);
uint32_t param3 = SHIM_GET_ARG_32(3);
uint32_t param4 = SHIM_GET_ARG_32(4);
xeKeBugCheckEx(code, param1, param2, param3, param4);
}
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
void xe::kernel::xboxkrnl::RegisterMiscExports(
ExportResolver* export_resolver, KernelState* state) {
SHIM_SET_MAPPING("xboxkrnl.exe", KeBugCheck, state);
SHIM_SET_MAPPING("xboxkrnl.exe", KeBugCheckEx, state);
}

View File

@@ -0,0 +1,29 @@
/**
******************************************************************************
* 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_MISC_H_
#define XENIA_KERNEL_XBOXKRNL_MISC_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/xbox.h>
namespace xe {
namespace kernel {
namespace xboxkrnl {
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_MISC_H_

View File

@@ -0,0 +1,188 @@
/**
******************************************************************************
* 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/xboxkrnl/xboxkrnl_module.h>
#include <gflags/gflags.h>
#include <xenia/export_resolver.h>
#include <xenia/kernel/xboxkrnl/kernel_state.h>
#include <xenia/kernel/xboxkrnl/xboxkrnl_private.h>
#include <xenia/kernel/xboxkrnl/objects/xmodule.h>
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl;
DEFINE_bool(abort_before_entry, false,
"Abort execution right before launching the module.");
KernelState* xe::kernel::xboxkrnl::shared_kernel_state_ = NULL;
XboxkrnlModule::XboxkrnlModule(Emulator* emulator) :
KernelModule(emulator) {
// Build the export table used for resolution.
#include <xenia/kernel/util/export_table_pre.inc>
static KernelExport xboxkrnl_export_table[] = {
#include <xenia/kernel/xboxkrnl/xboxkrnl_table.inc>
};
#include <xenia/kernel/util/export_table_post.inc>
export_resolver_->RegisterTable(
"xboxkrnl.exe", xboxkrnl_export_table, XECOUNT(xboxkrnl_export_table));
// Setup the kernel state instance.
// This is where all kernel objects are kept while running.
kernel_state_ = new KernelState(emulator);
// Setup the shared global state object.
XEASSERTNULL(shared_kernel_state_);
shared_kernel_state_ = kernel_state_;
// Register all exported functions.
RegisterDebugExports(export_resolver_, kernel_state_);
RegisterHalExports(export_resolver_, kernel_state_);
RegisterIoExports(export_resolver_, kernel_state_);
RegisterMemoryExports(export_resolver_, kernel_state_);
RegisterMiscExports(export_resolver_, kernel_state_);
RegisterModuleExports(export_resolver_, kernel_state_);
RegisterNtExports(export_resolver_, kernel_state_);
RegisterObExports(export_resolver_, kernel_state_);
RegisterRtlExports(export_resolver_, kernel_state_);
RegisterThreadingExports(export_resolver_, kernel_state_);
RegisterVideoExports(export_resolver_, kernel_state_);
uint8_t* mem = xe_memory_addr(memory_);
// KeDebugMonitorData (?*)
// Set to a valid value when a remote debugger is attached.
// Offset 0x18 is a 4b pointer to a handler function that seems to take two
// arguments. If we wanted to see what would happen we could fake that.
uint32_t pKeDebugMonitorData = xe_memory_heap_alloc(memory_, 0, 256, 0);
export_resolver_->SetVariableMapping(
"xboxkrnl.exe", ordinals::KeDebugMonitorData,
pKeDebugMonitorData);
XESETUINT32BE(mem + pKeDebugMonitorData, 0);
// KeCertMonitorData (?*)
// Always set to zero, ignored.
uint32_t pKeCertMonitorData = xe_memory_heap_alloc(memory_, 0, 4, 0);
export_resolver_->SetVariableMapping(
"xboxkrnl.exe", ordinals::KeCertMonitorData,
pKeCertMonitorData);
XESETUINT32BE(mem + pKeCertMonitorData, 0);
// XboxHardwareInfo (XboxHardwareInfo_t, 16b)
// flags cpu# ? ? ? ? ? ?
// 0x00000000, 0x06, 0x00, 0x00, 0x00, 0x00000000, 0x0000, 0x0000
// Games seem to check if bit 26 (0x20) is set, which at least for xbox1
// was whether an HDD was present. Not sure what the other flags are.
uint32_t pXboxHardwareInfo = xe_memory_heap_alloc(memory_, 0, 16, 0);
export_resolver_->SetVariableMapping(
"xboxkrnl.exe", ordinals::XboxHardwareInfo,
pXboxHardwareInfo);
XESETUINT32BE(mem + pXboxHardwareInfo + 0, 0x00000000); // flags
XESETUINT8BE (mem + pXboxHardwareInfo + 4, 0x06); // cpu count
// Remaining 11b are zeroes?
// XexExecutableModuleHandle (?**)
// Games try to dereference this to get a pointer to some module struct.
// So far it seems like it's just in loader code, and only used to look up
// the XexHeaderBase for use by RtlImageXexHeaderField.
// We fake it so that the address passed to that looks legit.
// 0x80100FFC <- pointer to structure
// 0x80101000 <- our module structure
// 0x80101058 <- pointer to xex header
// 0x80101100 <- xex header base
uint32_t ppXexExecutableModuleHandle =
xe_memory_heap_alloc(memory_, 0, 4, 0);
export_resolver_->SetVariableMapping(
"xboxkrnl.exe", ordinals::XexExecutableModuleHandle,
ppXexExecutableModuleHandle);
uint32_t pXexExecutableModuleHandle =
xe_memory_heap_alloc(memory_, 0, 256, 0);
XESETUINT32BE(mem + ppXexExecutableModuleHandle, pXexExecutableModuleHandle);
XESETUINT32BE(mem + pXexExecutableModuleHandle + 0x58, 0x80101100);
// ExLoadedCommandLine (char*)
// The name of the xex. Not sure this is ever really used on real devices.
// Perhaps it's how swap disc/etc data is sent?
// Always set to "default.xex" (with quotes) for now.
uint32_t pExLoadedCommandLine = xe_memory_heap_alloc(memory_, 0, 1024, 0);
export_resolver_->SetVariableMapping(
"xboxkrnl.exe", ordinals::ExLoadedCommandLine,
pExLoadedCommandLine);
char command_line[] = "\"default.xex\"";
xe_copy_memory(mem + pExLoadedCommandLine, 1024,
command_line, XECOUNT(command_line) + 1);
// XboxKrnlVersion (8b)
// Kernel version, looks like 2b.2b.2b.2b.
// I've only seen games check >=, so we just fake something here.
uint32_t pXboxKrnlVersion = xe_memory_heap_alloc(memory_, 0, 8, 0);
export_resolver_->SetVariableMapping(
"xboxkrnl.exe", ordinals::XboxKrnlVersion,
pXboxKrnlVersion);
XESETUINT16BE(mem + pXboxKrnlVersion + 0, 2);
XESETUINT16BE(mem + pXboxKrnlVersion + 2, 0xFFFF);
XESETUINT16BE(mem + pXboxKrnlVersion + 4, 0xFFFF);
XESETUINT16BE(mem + pXboxKrnlVersion + 6, 0xFFFF);
// KeTimeStampBundle (ad)
uint32_t pKeTimeStampBundle = xe_memory_heap_alloc(memory_, 0, 24, 0);
export_resolver_->SetVariableMapping(
"xboxkrnl.exe", ordinals::KeTimeStampBundle,
pKeTimeStampBundle);
XESETUINT64BE(mem + pKeTimeStampBundle + 0, 0);
XESETUINT64BE(mem + pKeTimeStampBundle + 8, 0);
XESETUINT32BE(mem + pKeTimeStampBundle + 12, 0);
}
XboxkrnlModule::~XboxkrnlModule() {
delete kernel_state_;
// Clear the shared kernel state.
shared_kernel_state_ = NULL;
}
int XboxkrnlModule::LaunchModule(const char* path) {
// Create and register the module. We keep it local to this function and
// dispose it on exit.
XModule* module = new XModule(kernel_state_, path);
// Load the module into memory from the filesystem.
X_STATUS result_code = module->LoadFromFile(path);
if (XFAILED(result_code)) {
XELOGE("Failed to load module %s: %.8X", path, result_code);
module->Release();
return 1;
}
if (FLAGS_abort_before_entry) {
XELOGI("--abort_before_entry causing an early exit");
module->Release();
return 0;
}
// Launch the module.
// NOTE: this won't return until the module exits.
result_code = module->Launch(0);
if (XFAILED(result_code)) {
XELOGE("Failed to launch module %s: %.8X", path, result_code);
module->Release();
return 2;
}
module->Release();
return 0;
}

View File

@@ -0,0 +1,54 @@
/**
******************************************************************************
* 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_MODULE_H_
#define XENIA_KERNEL_XBOXKRNL_MODULE_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/export_resolver.h>
#include <xenia/kernel/kernel_module.h>
#include <xenia/kernel/xboxkrnl/xboxkrnl_ordinals.h>
// All of the exported functions:
#include <xenia/kernel/xboxkrnl/xboxkrnl_debug.h>
#include <xenia/kernel/xboxkrnl/xboxkrnl_hal.h>
#include <xenia/kernel/xboxkrnl/xboxkrnl_memory.h>
#include <xenia/kernel/xboxkrnl/xboxkrnl_module.h>
#include <xenia/kernel/xboxkrnl/xboxkrnl_rtl.h>
#include <xenia/kernel/xboxkrnl/xboxkrnl_threading.h>
#include <xenia/kernel/xboxkrnl/xboxkrnl_video.h>
namespace xe {
namespace kernel {
namespace xboxkrnl {
class KernelState;
class XboxkrnlModule : public KernelModule {
public:
XboxkrnlModule(Emulator* emulator);
virtual ~XboxkrnlModule();
int LaunchModule(const char* path);
private:
KernelState* kernel_state_;
};
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_MODULE_H_

View File

@@ -0,0 +1,232 @@
/**
******************************************************************************
* 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/xboxkrnl/xboxkrnl_modules.h>
#include <xenia/kernel/shim_utils.h>
#include <xenia/kernel/xex2.h>
#include <xenia/kernel/xboxkrnl/kernel_state.h>
#include <xenia/kernel/xboxkrnl/xboxkrnl_private.h>
#include <xenia/kernel/xboxkrnl/objects/xmodule.h>
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl;
namespace xe {
namespace kernel {
namespace xboxkrnl {
X_STATUS xeExGetXConfigSetting(
uint16_t category, uint16_t setting, void* buffer, uint16_t buffer_size,
uint16_t* required_size) {
uint16_t setting_size = 0;
uint32_t value = 0;
// TODO(benvanik): have real structs here that just get copied from.
// http://free60.org/XConfig
// http://freestyledash.googlecode.com/svn/trunk/Freestyle/Tools/Generic/ExConfig.h
switch (category) {
case 0x0003:
// XCONFIG_USER_CATEGORY
switch (setting) {
case 0x0001: // XCONFIG_USER_TIME_ZONE_BIAS
case 0x0002: // XCONFIG_USER_TIME_ZONE_STD_NAME
case 0x0003: // XCONFIG_USER_TIME_ZONE_DLT_NAME
case 0x0004: // XCONFIG_USER_TIME_ZONE_STD_DATE
case 0x0005: // XCONFIG_USER_TIME_ZONE_DLT_DATE
case 0x0006: // XCONFIG_USER_TIME_ZONE_STD_BIAS
case 0x0007: // XCONFIG_USER_TIME_ZONE_DLT_BIAS
setting_size = 4;
// TODO(benvanik): get this value.
value = 0;
break;
case 0x0009: // XCONFIG_USER_LANGUAGE
setting_size = 4;
value = 0x00000001; // English
break;
case 0x000A: // XCONFIG_USER_VIDEO_FLAGS
setting_size = 4;
value = 0x00040000;
break;
case 0x000C: // XCONFIG_USER_RETAIL_FLAGS
setting_size = 4;
// TODO(benvanik): get this value.
value = 0;
break;
case 0x000E: // XCONFIG_USER_COUNTRY
setting_size = 4;
// TODO(benvanik): get this value.
value = 0;
break;
default:
XEASSERTALWAYS();
return X_STATUS_INVALID_PARAMETER_2;
}
break;
default:
XEASSERTALWAYS();
return X_STATUS_INVALID_PARAMETER_1;
}
if (buffer_size < setting_size) {
return X_STATUS_BUFFER_TOO_SMALL;
}
if (!buffer && buffer_size) {
return X_STATUS_INVALID_PARAMETER_3;
}
if (buffer) {
XESETUINT32BE(buffer, value);
}
if (required_size) {
*required_size = setting_size;
}
return X_STATUS_SUCCESS;
}
SHIM_CALL ExGetXConfigSetting_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint16_t category = SHIM_GET_ARG_16(0);
uint16_t setting = SHIM_GET_ARG_16(1);
uint32_t buffer_ptr = SHIM_GET_ARG_32(2);
uint16_t buffer_size = SHIM_GET_ARG_16(3);
uint32_t required_size_ptr = SHIM_GET_ARG_32(4);
XELOGD(
"ExGetXConfigSetting(%.4X, %.4X, %.8X, %.4X, %.8X)",
category, setting, buffer_ptr, buffer_size, required_size_ptr);
void* buffer = buffer_ptr ? SHIM_MEM_ADDR(buffer_ptr) : NULL;
uint16_t required_size = 0;
X_STATUS result = xeExGetXConfigSetting(
category, setting, buffer, buffer_size, &required_size);
if (required_size_ptr) {
SHIM_SET_MEM_16(required_size_ptr, required_size);
}
SHIM_SET_RETURN(result);
}
int xeXexCheckExecutablePriviledge(uint32_t privilege) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
// BOOL
// DWORD Privilege
// Privilege is bit position in xe_xex2_system_flags enum - so:
// Privilege=6 -> 0x00000040 -> XEX_SYSTEM_INSECURE_SOCKETS
uint32_t mask = 1 << privilege;
XModule* module = state->GetExecutableModule();
if (!module) {
return 0;
}
xe_xex2_ref xex = module->xex();
const xe_xex2_header_t* header = xe_xex2_get_header(xex);
uint32_t result = (header->system_flags & mask) > 0;
xe_xex2_release(xex);
module->Release();
return result;
}
SHIM_CALL XexCheckExecutablePrivilege_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t privilege = SHIM_GET_ARG_32(0);
XELOGD(
"XexCheckExecutablePrivilege(%.8X)",
privilege);
int result = xeXexCheckExecutablePriviledge(privilege);
SHIM_SET_RETURN(result);
}
int xeXexGetModuleHandle(const char* module_name,
X_HANDLE* module_handle_ptr) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
// BOOL
// LPCSZ ModuleName
// LPHMODULE ModuleHandle
XModule* module = state->GetModule(module_name);
if (!module) {
return 0;
}
// NOTE: we don't retain the handle for return.
*module_handle_ptr = module->handle();
module->Release();
return 1;
}
SHIM_CALL XexGetModuleHandle_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t module_name_ptr = SHIM_GET_ARG_32(0);
const char* module_name = (const char*)SHIM_MEM_ADDR(module_name_ptr);
uint32_t module_handle_ptr = SHIM_GET_ARG_32(1);
XELOGD(
"XexGetModuleHandle(%s, %.8X)",
module_name, module_handle_ptr);
X_HANDLE module_handle = 0;
int result = xeXexGetModuleHandle(module_name, &module_handle);
if (result) {
SHIM_SET_MEM_32(module_handle_ptr, module_handle);
}
SHIM_SET_RETURN(result);
}
// SHIM_CALL XexGetModuleSection_shim(
// xe_ppc_state_t* ppc_state, KernelState* state) {
// }
// SHIM_CALL XexGetProcedureAddress_shim(
// xe_ppc_state_t* ppc_state, KernelState* state) {
// }
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
void xe::kernel::xboxkrnl::RegisterModuleExports(
ExportResolver* export_resolver, KernelState* state) {
SHIM_SET_MAPPING("xboxkrnl.exe", ExGetXConfigSetting, state);
SHIM_SET_MAPPING("xboxkrnl.exe", XexCheckExecutablePrivilege, state);
SHIM_SET_MAPPING("xboxkrnl.exe", XexGetModuleHandle, state);
// SHIM_SET_MAPPING("xboxkrnl.exe", XexGetModuleSection, state);
// SHIM_SET_MAPPING("xboxkrnl.exe", XexGetProcedureAddress, state);
}

View File

@@ -0,0 +1,38 @@
/**
******************************************************************************
* 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_MODULES_IMPL_H_
#define XENIA_KERNEL_XBOXKRNL_MODULES_IMPL_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/xbox.h>
namespace xe {
namespace kernel {
namespace xboxkrnl {
X_STATUS xeExGetXConfigSetting(
uint16_t category, uint16_t setting, void* buffer, uint16_t buffer_size,
uint16_t* required_size);
int xeXexCheckExecutablePriviledge(uint32_t privilege);
int xeXexGetModuleHandle(const char* module_name,
X_HANDLE* module_handle_ptr);
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_MODULES_IMPL_H_

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. *
******************************************************************************
*/
#include <xenia/kernel/xboxkrnl/xboxkrnl_nt.h>
#include <xenia/kernel/shim_utils.h>
#include <xenia/kernel/xboxkrnl/kernel_state.h>
#include <xenia/kernel/xboxkrnl/xboxkrnl_private.h>
#include <xenia/kernel/xboxkrnl/xobject.h>
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl;
namespace xe {
namespace kernel {
namespace xboxkrnl {
SHIM_CALL NtClose_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t handle = SHIM_GET_ARG_32(0);
XELOGD(
"NtClose(%.8X)",
handle);
X_STATUS result = X_STATUS_INVALID_HANDLE;
result = state->object_table()->RemoveHandle(handle);
SHIM_SET_RETURN(result);
}
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
void xe::kernel::xboxkrnl::RegisterNtExports(
ExportResolver* export_resolver, KernelState* state) {
SHIM_SET_MAPPING("xboxkrnl.exe", NtClose, state);
}

View File

@@ -0,0 +1,29 @@
/**
******************************************************************************
* 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_NT_H_
#define XENIA_KERNEL_XBOXKRNL_NT_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/xbox.h>
namespace xe {
namespace kernel {
namespace xboxkrnl {
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_NT_H_

View File

@@ -0,0 +1,101 @@
/**
******************************************************************************
* 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/xboxkrnl/xboxkrnl_ob.h>
#include <xenia/kernel/shim_utils.h>
#include <xenia/kernel/xboxkrnl/kernel_state.h>
#include <xenia/kernel/xboxkrnl/xboxkrnl_private.h>
#include <xenia/kernel/xboxkrnl/xobject.h>
#include <xenia/kernel/xboxkrnl/objects/xthread.h>
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl;
namespace xe {
namespace kernel {
namespace xboxkrnl {
SHIM_CALL ObReferenceObjectByHandle_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t handle = SHIM_GET_ARG_32(0);
uint32_t object_type_ptr = SHIM_GET_ARG_32(1);
uint32_t out_object_ptr = SHIM_GET_ARG_32(2);
XELOGD(
"ObReferenceObjectByHandle(%.8X, %.8X, %.8X)",
handle,
object_type_ptr,
out_object_ptr);
X_STATUS result = X_STATUS_INVALID_HANDLE;
XObject* object = NULL;
result = state->object_table()->GetObject(handle, &object);
if (XSUCCEEDED(result)) {
// TODO(benvanik): verify type with object_type_ptr
// TODO(benvanik): get native value, if supported.
uint32_t native_ptr = 0xDEADF00D;
switch (object_type_ptr) {
case 0xD01BBEEF: // ExThreadObjectType
{
XThread* thread = (XThread*)object;
native_ptr = thread->thread_state();
}
break;
}
if (out_object_ptr) {
SHIM_SET_MEM_32(out_object_ptr, native_ptr);
}
}
SHIM_SET_RETURN(result);
}
SHIM_CALL ObDereferenceObject_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t native_ptr = SHIM_GET_ARG_32(0);
XELOGD(
"ObDereferenceObject(%.8X)",
native_ptr);
// Check if a dummy value from ObReferenceObjectByHandle.
if (native_ptr == 0xDEADF00D) {
SHIM_SET_RETURN(0);
return;
}
void* object_ptr = SHIM_MEM_ADDR(native_ptr);
XObject* object = XObject::GetObject(state, object_ptr);
if (object) {
object->Release();
}
SHIM_SET_RETURN(0);
}
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
void xe::kernel::xboxkrnl::RegisterObExports(
ExportResolver* export_resolver, KernelState* state) {
SHIM_SET_MAPPING("xboxkrnl.exe", ObReferenceObjectByHandle, state);
SHIM_SET_MAPPING("xboxkrnl.exe", ObDereferenceObject, state);
}

View File

@@ -0,0 +1,29 @@
/**
******************************************************************************
* 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_OB_H_
#define XENIA_KERNEL_XBOXKRNL_OB_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/xbox.h>
namespace xe {
namespace kernel {
namespace xboxkrnl {
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_OB_H_

View File

@@ -0,0 +1,29 @@
/**
******************************************************************************
* 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_ORDINALS_H_
#define XENIA_KERNEL_XBOXKRNL_ORDINALS_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/export_resolver.h>
// Build an ordinal enum to make it easy to lookup ordinals.
#include <xenia/kernel/util/ordinal_table_pre.inc>
namespace ordinals {
enum {
#include <xenia/kernel/xboxkrnl/xboxkrnl_table.inc>
};
} // namespace ordinals
#include <xenia/kernel/util/ordinal_table_post.inc>
#endif // XENIA_KERNEL_XBOXKRNL_ORDINALS_H_

View File

@@ -0,0 +1,51 @@
/**
******************************************************************************
* 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_PRIVATE_H_
#define XENIA_KERNEL_XBOXKRNL_PRIVATE_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/kernel/xboxkrnl/xboxkrnl_ordinals.h>
namespace xe {
namespace kernel {
namespace xboxkrnl {
class KernelState;
// This is a global object initialized with the XboxkrnlModule.
// It references the current kernel state object that all kernel methods should
// be using to stash their variables.
extern KernelState* shared_kernel_state_;
// Registration functions, one per file.
void RegisterDebugExports(ExportResolver* export_resolver, KernelState* state);
void RegisterHalExports(ExportResolver* export_resolver, KernelState* state);
void RegisterIoExports(ExportResolver* export_resolver, KernelState* state);
void RegisterMemoryExports(ExportResolver* export_resolver, KernelState* state);
void RegisterMiscExports(ExportResolver* export_resolver, KernelState* state);
void RegisterModuleExports(ExportResolver* export_resolver, KernelState* state);
void RegisterNtExports(ExportResolver* export_resolver, KernelState* state);
void RegisterObExports(ExportResolver* export_resolver, KernelState* state);
void RegisterRtlExports(ExportResolver* export_resolver, KernelState* state);
void RegisterThreadingExports(ExportResolver* export_resolver,
KernelState* state);
void RegisterVideoExports(ExportResolver* export_resolver, KernelState* state);
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_PRIVATE_H_

View File

@@ -0,0 +1,898 @@
/**
******************************************************************************
* 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/xboxkrnl/xboxkrnl_rtl.h>
#include <xenia/kernel/shim_utils.h>
#include <xenia/kernel/xex2.h>
#include <xenia/kernel/xboxkrnl/kernel_state.h>
#include <xenia/kernel/xboxkrnl/xboxkrnl_private.h>
#include <xenia/kernel/xboxkrnl/objects/xmodule.h>
#include <xenia/kernel/xboxkrnl/objects/xthread.h>
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl;
namespace xe {
namespace kernel {
namespace xboxkrnl {
// http://msdn.microsoft.com/en-us/library/ff561778
uint32_t xeRtlCompareMemory(uint32_t source1_ptr, uint32_t source2_ptr,
uint32_t length) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
// SIZE_T
// _In_ const VOID *Source1,
// _In_ const VOID *Source2,
// _In_ SIZE_T Length
uint8_t* p1 = IMPL_MEM_ADDR(source1_ptr);
uint8_t* p2 = IMPL_MEM_ADDR(source2_ptr);
// Note that the return value is the number of bytes that match, so it's best
// we just do this ourselves vs. using memcmp.
// On Windows we could use the builtin function.
uint32_t c = 0;
for (uint32_t n = 0; n < length; n++, p1++, p2++) {
if (*p1 == *p2) {
c++;
}
}
return c;
}
SHIM_CALL RtlCompareMemory_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t source1 = SHIM_GET_ARG_32(0);
uint32_t source2 = SHIM_GET_ARG_32(1);
uint32_t length = SHIM_GET_ARG_32(2);
XELOGD(
"RtlCompareMemory(%.8X, %.8X, %d)",
source1, source2, length);
uint32_t result = xeRtlCompareMemory(source1, source2, length);
SHIM_SET_RETURN(result);
}
// http://msdn.microsoft.com/en-us/library/ff552123
uint32_t xeRtlCompareMemoryUlong(uint32_t source_ptr, uint32_t length,
uint32_t pattern) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
// SIZE_T
// _In_ PVOID Source,
// _In_ SIZE_T Length,
// _In_ ULONG Pattern
if ((source_ptr % 4) || (length % 4)) {
return 0;
}
uint8_t* p = IMPL_MEM_ADDR(source_ptr);
// Swap pattern.
// TODO(benvanik): ensure byte order of pattern is correct.
// Since we are doing byte-by-byte comparison we may not want to swap.
// GET_ARG swaps, so this is a swap back. Ugly.
const uint32_t pb32 = XESWAP32BE(pattern);
const uint8_t* pb = (uint8_t*)&pb32;
uint32_t c = 0;
for (uint32_t n = 0; n < length; n++, p++) {
if (*p == pb[n % 4]) {
c++;
}
}
return c;
}
SHIM_CALL RtlCompareMemoryUlong_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t source = SHIM_GET_ARG_32(0);
uint32_t length = SHIM_GET_ARG_32(1);
uint32_t pattern = SHIM_GET_ARG_32(2);
XELOGD(
"RtlCompareMemoryUlong(%.8X, %d, %.8X)",
source, length, pattern);
uint32_t result = xeRtlCompareMemoryUlong(source, length, pattern);
SHIM_SET_RETURN(result);
}
// http://msdn.microsoft.com/en-us/library/ff552263
void xeRtlFillMemoryUlong(uint32_t destination_ptr, uint32_t length,
uint32_t pattern) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
// VOID
// _Out_ PVOID Destination,
// _In_ SIZE_T Length,
// _In_ ULONG Pattern
// NOTE: length must be % 4, so we can work on uint32s.
uint32_t* p = (uint32_t*)IMPL_MEM_ADDR(destination_ptr);
// TODO(benvanik): ensure byte order is correct - we're writing back the
// swapped arg value.
uint32_t count = length >> 2;
uint32_t native_pattern = XESWAP32BE(pattern);
// TODO: unroll loop?
for (uint32_t n = 0; n < count; n++, p++) {
*p = native_pattern;
}
}
SHIM_CALL RtlFillMemoryUlong_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t destination = SHIM_GET_ARG_32(0);
uint32_t length = SHIM_GET_ARG_32(1);
uint32_t pattern = SHIM_GET_ARG_32(2);
XELOGD(
"RtlFillMemoryUlong(%.8X, %d, %.8X)",
destination, length, pattern);
xeRtlFillMemoryUlong(destination, length, pattern);
}
// typedef struct _STRING {
// USHORT Length;
// USHORT MaximumLength;
// PCHAR Buffer;
// } ANSI_STRING, *PANSI_STRING;
// http://msdn.microsoft.com/en-us/library/ff561918
void xeRtlInitAnsiString(uint32_t destination_ptr, uint32_t source_ptr) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
// VOID
// _Out_ PANSI_STRING DestinationString,
// _In_opt_ PCSZ SourceString
const char* source = source_ptr ? (char*)IMPL_MEM_ADDR(source_ptr) : NULL;
if (source) {
uint16_t length = (uint16_t)xestrlena(source);
IMPL_SET_MEM_16(destination_ptr + 0, length);
IMPL_SET_MEM_16(destination_ptr + 2, length + 1);
IMPL_SET_MEM_32(destination_ptr + 4, source_ptr);
} else {
IMPL_SET_MEM_16(destination_ptr + 0, 0);
IMPL_SET_MEM_16(destination_ptr + 2, 0);
IMPL_SET_MEM_32(destination_ptr + 4, 0);
}
}
SHIM_CALL RtlInitAnsiString_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t destination_ptr = SHIM_GET_ARG_32(0);
uint32_t source_ptr = SHIM_GET_ARG_32(1);
const char* source = source_ptr ? (char*)SHIM_MEM_ADDR(source_ptr) : NULL;
XELOGD("RtlInitAnsiString(%.8X, %.8X = %s)",
destination_ptr, source_ptr, source ? source : "<null>");
xeRtlInitAnsiString(destination_ptr, source_ptr);
}
// http://msdn.microsoft.com/en-us/library/ff561899
void xeRtlFreeAnsiString(uint32_t string_ptr) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
// VOID
// _Inout_ PANSI_STRING AnsiString
//uint32_t buffer = SHIM_MEM_32(string_ptr + 4);
// TODO(benvanik): free the buffer
XELOGE("RtlFreeAnsiString leaking buffer");
IMPL_SET_MEM_16(string_ptr + 0, 0);
IMPL_SET_MEM_16(string_ptr + 2, 0);
IMPL_SET_MEM_32(string_ptr + 4, 0);
}
SHIM_CALL RtlFreeAnsiString_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t string_ptr = SHIM_GET_ARG_32(0);
XELOGD("RtlFreeAnsiString(%.8X)", string_ptr);
xeRtlFreeAnsiString(string_ptr);
}
// typedef struct _UNICODE_STRING {
// USHORT Length;
// USHORT MaximumLength;
// PWSTR Buffer;
// } UNICODE_STRING, *PUNICODE_STRING;
// http://msdn.microsoft.com/en-us/library/ff561934
void xeRtlInitUnicodeString(uint32_t destination_ptr, uint32_t source_ptr) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
// VOID
// _Out_ PUNICODE_STRING DestinationString,
// _In_opt_ PCWSTR SourceString
const wchar_t* source =
source_ptr ? (const wchar_t*)IMPL_MEM_ADDR(source_ptr) : NULL;
if (source) {
uint16_t length = (uint16_t)xestrlenw(source);
IMPL_SET_MEM_16(destination_ptr + 0, length * 2);
IMPL_SET_MEM_16(destination_ptr + 2, (length + 1) * 2);
IMPL_SET_MEM_32(destination_ptr + 4, source_ptr);
} else {
IMPL_SET_MEM_16(destination_ptr + 0, 0);
IMPL_SET_MEM_16(destination_ptr + 2, 0);
IMPL_SET_MEM_32(destination_ptr + 4, 0);
}
}
SHIM_CALL RtlInitUnicodeString_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t destination_ptr = SHIM_GET_ARG_32(0);
uint32_t source_ptr = SHIM_GET_ARG_32(1);
const wchar_t* source =
source_ptr ? (const wchar_t*)SHIM_MEM_ADDR(source_ptr) : NULL;
XELOGD("RtlInitUnicodeString(%.8X, %.8X = %ls)",
destination_ptr, source_ptr, source ? source : L"<null>");
xeRtlInitUnicodeString(destination_ptr, source_ptr);
}
// http://msdn.microsoft.com/en-us/library/ff561903
void xeRtlFreeUnicodeString(uint32_t string_ptr) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
// VOID
// _Inout_ PUNICODE_STRING UnicodeString
//uint32_t buffer = IMPL_MEM_32(string_ptr + 4);
// TODO(benvanik): free the buffer
XELOGE("RtlFreeUnicodeString leaking buffer");
IMPL_SET_MEM_16(string_ptr + 0, 0);
IMPL_SET_MEM_16(string_ptr + 2, 0);
IMPL_SET_MEM_32(string_ptr + 4, 0);
}
SHIM_CALL RtlFreeUnicodeString_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t string_ptr = SHIM_GET_ARG_32(0);
XELOGD("RtlFreeUnicodeString(%.8X)", string_ptr);
xeRtlFreeUnicodeString(string_ptr);
}
// http://msdn.microsoft.com/en-us/library/ff562969
X_STATUS xeRtlUnicodeStringToAnsiString(
uint32_t destination_ptr, uint32_t source_ptr, uint32_t alloc_dest) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
// NTSTATUS
// _Inout_ PANSI_STRING DestinationString,
// _In_ PCUNICODE_STRING SourceString,
// _In_ BOOLEAN AllocateDestinationString
XELOGE("RtlUnicodeStringToAnsiString not yet implemented");
XEASSERTALWAYS();
if (alloc_dest) {
// Allocate a new buffer to place the string into.
//IMPL_SET_MEM_32(destination_ptr + 4, buffer_ptr);
} else {
// Reuse the buffer in the target.
//uint32_t buffer_size = IMPL_MEM_16(destination_ptr + 2);
}
return X_STATUS_UNSUCCESSFUL;
}
SHIM_CALL RtlUnicodeStringToAnsiString_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t destination_ptr = SHIM_GET_ARG_32(0);
uint32_t source_ptr = SHIM_GET_ARG_32(1);
uint32_t alloc_dest = SHIM_GET_ARG_32(2);
XELOGD("RtlUnicodeStringToAnsiString(%.8X, %.8X, %d)",
destination_ptr, source_ptr, alloc_dest);
X_STATUS result = xeRtlUnicodeStringToAnsiString(
destination_ptr, source_ptr, alloc_dest);
SHIM_SET_RETURN(result);
}
// TODO: clean me up!
SHIM_CALL _vsnprintf_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t buffer_ptr = SHIM_GET_ARG_32(0);
uint32_t count = SHIM_GET_ARG_32(1);
uint32_t format_ptr = SHIM_GET_ARG_32(2);
uint32_t arg_ptr = SHIM_GET_ARG_32(3);
if (format_ptr == 0) {
SHIM_SET_RETURN(-1);
return;
}
char *buffer = (char *)SHIM_MEM_ADDR(buffer_ptr); // TODO: ensure it never writes past the end of the buffer (count)...
const char *format = (const char *)SHIM_MEM_ADDR(format_ptr);
int arg_index = 0;
char *b = buffer;
for (; *format != '\0'; ++format) {
const char *start = format;
if (*format != '%') {
*b++ = *format;
continue;
}
++format;
if (*format == '\0') {
break;
}
if (*format == '%') {
*b++ = *format;
continue;
}
const char *end;
end = format;
// skip flags
while (*end == '-' ||
*end == '+' ||
*end == ' ' ||
*end == '#' ||
*end == '0') {
++end;
}
if (*end == '\0') {
break;
}
int arg_extras = 0;
// skip width
if (*end == '*') {
++end;
arg_extras++;
}
else {
while (*end >= '0' && *end <= '9') {
++end;
}
}
if (*end == '\0') {
break;
}
// skip precision
if (*end == '.') {
++end;
if (*end == '*') {
++end;
++arg_extras;
}
else {
while (*end >= '0' && *end <= '9') {
++end;
}
}
}
if (*end == '\0') {
break;
}
// get length
int arg_size = 4;
if (*end == 'h') {
++end;
arg_size = 4;
if (*end == 'h') {
++end;
}
}
else if (*end == 'l') {
++end;
arg_size = 4;
if (*end == 'l') {
++end;
arg_size = 8;
}
}
else if (*end == 'j') {
arg_size = 8;
++end;
}
else if (*end == 'z') {
arg_size = 4;
++end;
}
else if (*end == 't') {
arg_size = 8;
++end;
}
else if (*end == 'L') {
arg_size = 8;
++end;
}
if (*end == '\0') {
break;
}
if (*end == 'd' ||
*end == 'i' ||
*end == 'u' ||
*end == 'o' ||
*end == 'x' ||
*end == 'X' ||
*end == 'f' ||
*end == 'F' ||
*end == 'e' ||
*end == 'E' ||
*end == 'g' ||
*end == 'G' ||
*end == 'a' ||
*end == 'A' ||
*end == 'c') {
char local[512];
local[0] = '\0';
strncat(local, start, end + 1 - start);
XEASSERT(arg_size == 8 || arg_size == 4);
if (arg_size == 8) {
if (arg_extras == 0) {
uint64_t value = SHIM_MEM_64(arg_ptr + (arg_index * 8)); // TODO: check if this is correct...
int result = sprintf(b, local, value);
b += result;
arg_index++;
}
else {
XEASSERT(false);
}
}
else if (arg_size == 4) {
if (arg_extras == 0) {
uint32_t value = (uint32_t)SHIM_MEM_64(arg_ptr + (arg_index * 8)); // TODO: check if this is correct...
int result = sprintf(b, local, value);
b += result;
arg_index++;
}
else {
XEASSERT(false);
}
}
}
else if (*end == 's' ||
*end == 'p' ||
*end == 'n') {
char local[512];
local[0] = '\0';
strncat(local, start, end + 1 - start);
XEASSERT(arg_size == 4);
if (arg_extras == 0) {
uint32_t value = (uint32_t)SHIM_MEM_64(arg_ptr + (arg_index * 8)); // TODO: check if this is correct...
const char *pointer = (const char *)SHIM_MEM_ADDR(value);
int result = sprintf(b, local, pointer);
b += result;
arg_index++;
}
else {
XEASSERT(false);
}
}
else {
XEASSERT(false);
break;
}
format = end;
}
*b++ = '\0';
SHIM_SET_RETURN((uint32_t)(b - buffer));
}
uint32_t xeRtlNtStatusToDosError(X_STATUS status) {
if (!status || (status & 0x20000000)) {
// Success.
return status;
} else if ((status & 0xF0000000) == 0xD0000000) {
// High bit doesn't matter.
status &= ~0x10000000;
}
// TODO(benvanik): implement lookup table.
XELOGE("RtlNtStatusToDosError lookup NOT IMPLEMENTED");
return 317; // ERROR_MR_MID_NOT_FOUND
}
SHIM_CALL RtlNtStatusToDosError_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t status = SHIM_GET_ARG_32(0);
XELOGD(
"RtlNtStatusToDosError(%.4X)",
status);
uint32_t result = xeRtlNtStatusToDosError(status);
SHIM_SET_RETURN(result);
}
uint32_t xeRtlImageXexHeaderField(uint32_t xex_header_base_ptr,
uint32_t image_field) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
// PVOID
// PVOID XexHeaderBase
// DWORD ImageField
// NOTE: this is totally faked!
// We set the XexExecutableModuleHandle pointer to a block that has at offset
// 0x58 a pointer to our XexHeaderBase. If the value passed doesn't match
// then die.
// The only ImageField I've seen in the wild is
// 0x20401 (XEX_HEADER_DEFAULT_HEAP_SIZE), so that's all we'll support.
XModule* module = NULL;
// TODO(benvanik): use xex_header_base to dereference this.
// Right now we are only concerned with games making this call on their main
// module, so this hack is fine.
module = state->GetExecutableModule();
const xe_xex2_header_t* xex_header = module->xex_header();
for (size_t n = 0; n < xex_header->header_count; n++) {
if (xex_header->headers[n].key == image_field) {
module->Release();
return xex_header->headers[n].value;
}
}
module->Release();
return 0;
}
SHIM_CALL RtlImageXexHeaderField_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t xex_header_base = SHIM_GET_ARG_32(0);
uint32_t image_field = SHIM_GET_ARG_32(1);
// NOTE: this is totally faked!
// We set the XexExecutableModuleHandle pointer to a block that has at offset
// 0x58 a pointer to our XexHeaderBase. If the value passed doesn't match
// then die.
// The only ImageField I've seen in the wild is
// 0x20401 (XEX_HEADER_DEFAULT_HEAP_SIZE), so that's all we'll support.
XELOGD(
"RtlImageXexHeaderField(%.8X, %.8X)",
xex_header_base, image_field);
uint32_t result = xeRtlImageXexHeaderField(xex_header_base, image_field);
SHIM_SET_RETURN(result);
}
// Unfortunately the Windows RTL_CRITICAL_SECTION object is bigger than the one
// on the 360 (32b vs. 28b). This means that we can't do in-place splatting of
// the critical sections. Also, the 360 never calls RtlDeleteCriticalSection
// so we can't clean up the native handles.
//
// Because of this, we reimplement it poorly. Hooray.
// We have 28b to work with so we need to be careful. We map our struct directly
// into guest memory, as it should be opaque and so long as our size is right
// the user code will never know.
//
// Ref: http://msdn.microsoft.com/en-us/magazine/cc164040.aspx
// Ref: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/rtl/critical.c?view=markup
// This structure tries to match the one on the 360 as best I can figure out.
// Unfortunately some games have the critical sections pre-initialized in
// their embedded data and InitializeCriticalSection will never be called.
namespace {
#pragma pack(push, 1)
typedef struct {
uint8_t unknown00;
uint8_t spin_count_div_256; // * 256
uint8_t __padding[6];
//uint32_t unknown04; // maybe the handle to the event?
uint32_t unknown08; // head of queue, pointing to this offset
uint32_t unknown0C; // tail of queue?
int32_t lock_count; // -1 -> 0 on first lock 0x10
uint32_t recursion_count; // 0 -> 1 on first lock 0x14
uint32_t owning_thread_id; // 0 unless locked 0x18
} X_RTL_CRITICAL_SECTION;
#pragma pack(pop)
}
XEASSERTSTRUCTSIZE(X_RTL_CRITICAL_SECTION, 28);
void xeRtlInitializeCriticalSection(uint32_t cs_ptr) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
// VOID
// _Out_ LPCRITICAL_SECTION lpCriticalSection
X_RTL_CRITICAL_SECTION* cs = (X_RTL_CRITICAL_SECTION*)IMPL_MEM_ADDR(cs_ptr);
cs->unknown00 = 1;
cs->spin_count_div_256 = 0;
cs->lock_count = -1;
cs->recursion_count = 0;
cs->owning_thread_id = 0;
}
SHIM_CALL RtlInitializeCriticalSection_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t cs_ptr = SHIM_GET_ARG_32(0);
XELOGD("RtlInitializeCriticalSection(%.8X)", cs_ptr);
xeRtlInitializeCriticalSection(cs_ptr);
}
X_STATUS xeRtlInitializeCriticalSectionAndSpinCount(
uint32_t cs_ptr, uint32_t spin_count) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
// NTSTATUS
// _Out_ LPCRITICAL_SECTION lpCriticalSection,
// _In_ DWORD dwSpinCount
// Spin count is rouned up to 256 intervals then packed in.
//uint32_t spin_count_div_256 = (uint32_t)floor(spin_count / 256.0f + 0.5f);
uint32_t spin_count_div_256 = (spin_count + 255) >> 8;
if (spin_count_div_256 > 255) {
spin_count_div_256 = 255;
}
X_RTL_CRITICAL_SECTION* cs = (X_RTL_CRITICAL_SECTION*)IMPL_MEM_ADDR(cs_ptr);
cs->unknown00 = 1;
cs->spin_count_div_256 = spin_count_div_256;
cs->lock_count = -1;
cs->recursion_count = 0;
cs->owning_thread_id = 0;
return X_STATUS_SUCCESS;
}
SHIM_CALL RtlInitializeCriticalSectionAndSpinCount_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t cs_ptr = SHIM_GET_ARG_32(0);
uint32_t spin_count = SHIM_GET_ARG_32(1);
XELOGD("RtlInitializeCriticalSectionAndSpinCount(%.8X, %d)",
cs_ptr, spin_count);
X_STATUS result = xeRtlInitializeCriticalSectionAndSpinCount(
cs_ptr, spin_count);
SHIM_SET_RETURN(result);
}
// TODO(benvanik): remove the need for passing in thread_id.
void xeRtlEnterCriticalSection(uint32_t cs_ptr, uint32_t thread_id) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
// VOID
// _Inout_ LPCRITICAL_SECTION lpCriticalSection
X_RTL_CRITICAL_SECTION* cs = (X_RTL_CRITICAL_SECTION*)IMPL_MEM_ADDR(cs_ptr);
uint32_t spin_wait_remaining = cs->spin_count_div_256 * 256;
spin:
if (xe_atomic_inc_32(&cs->lock_count)) {
// If this thread already owns the CS increment the recursion count.
if (cs->owning_thread_id == thread_id) {
cs->recursion_count++;
return;
}
// Thread was locked - spin wait.
if (spin_wait_remaining) {
spin_wait_remaining--;
goto spin;
}
// All out of spin waits, create a full waiter.
// TODO(benvanik): contention - do a real wait!
//XELOGE("RtlEnterCriticalSection tried to really lock!");
spin_wait_remaining = 1; // HACK: spin forever
Sleep(1);
goto spin;
}
// Now own the lock.
cs->owning_thread_id = thread_id;
cs->recursion_count = 1;
}
SHIM_CALL RtlEnterCriticalSection_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t cs_ptr = SHIM_GET_ARG_32(0);
XELOGD("RtlEnterCriticalSection(%.8X)", cs_ptr);
const uint8_t* thread_state_block = ppc_state->membase + ppc_state->r[13];
uint32_t thread_id = XThread::GetCurrentThreadId(thread_state_block);
xeRtlEnterCriticalSection(cs_ptr, thread_id);
}
// TODO(benvanik): remove the need for passing in thread_id.
uint32_t xeRtlTryEnterCriticalSection(uint32_t cs_ptr, uint32_t thread_id) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
// DWORD
// _Inout_ LPCRITICAL_SECTION lpCriticalSection
X_RTL_CRITICAL_SECTION* cs = (X_RTL_CRITICAL_SECTION*)IMPL_MEM_ADDR(cs_ptr);
if (xe_atomic_cas_32(-1, 0, &cs->lock_count)) {
// Able to steal the lock right away.
cs->owning_thread_id = thread_id;
cs->recursion_count = 1;
return 1;
} else if (cs->owning_thread_id == thread_id) {
xe_atomic_inc_32(&cs->lock_count);
++cs->recursion_count;
return 1;
}
return 0;
}
SHIM_CALL RtlTryEnterCriticalSection_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t cs_ptr = SHIM_GET_ARG_32(0);
XELOGD("RtlTryEnterCriticalSection(%.8X)", cs_ptr);
const uint8_t* thread_state_block = ppc_state->membase + ppc_state->r[13];
uint32_t thread_id = XThread::GetCurrentThreadId(thread_state_block);
uint32_t result = xeRtlTryEnterCriticalSection(cs_ptr, thread_id);
SHIM_SET_RETURN(result);
}
void xeRtlLeaveCriticalSection(uint32_t cs_ptr) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
// VOID
// _Inout_ LPCRITICAL_SECTION lpCriticalSection
X_RTL_CRITICAL_SECTION* cs = (X_RTL_CRITICAL_SECTION*)IMPL_MEM_ADDR(cs_ptr);
// Drop recursion count - if we are still not zero'ed return.
uint32_t recursion_count = --cs->recursion_count;
if (recursion_count) {
xe_atomic_dec_32(&cs->lock_count);
return;
}
// Unlock!
cs->owning_thread_id = 0;
if (xe_atomic_dec_32(&cs->lock_count) != -1) {
// There were waiters - wake one of them.
// TODO(benvanik): wake a waiter.
XELOGE("RtlLeaveCriticalSection would have woken a waiter");
}
}
SHIM_CALL RtlLeaveCriticalSection_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t cs_ptr = SHIM_GET_ARG_32(0);
XELOGD("RtlLeaveCriticalSection(%.8X)", cs_ptr);
xeRtlLeaveCriticalSection(cs_ptr);
}
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
void xe::kernel::xboxkrnl::RegisterRtlExports(
ExportResolver* export_resolver, KernelState* state) {
SHIM_SET_MAPPING("xboxkrnl.exe", RtlCompareMemory, state);
SHIM_SET_MAPPING("xboxkrnl.exe", RtlCompareMemoryUlong, state);
SHIM_SET_MAPPING("xboxkrnl.exe", RtlFillMemoryUlong, state);
SHIM_SET_MAPPING("xboxkrnl.exe", RtlInitAnsiString, state);
SHIM_SET_MAPPING("xboxkrnl.exe", RtlFreeAnsiString, state);
SHIM_SET_MAPPING("xboxkrnl.exe", RtlInitUnicodeString, state);
SHIM_SET_MAPPING("xboxkrnl.exe", RtlFreeUnicodeString, state);
SHIM_SET_MAPPING("xboxkrnl.exe", RtlUnicodeStringToAnsiString, state);
SHIM_SET_MAPPING("xboxkrnl.exe", _vsnprintf, state);
SHIM_SET_MAPPING("xboxkrnl.exe", RtlNtStatusToDosError, state);
SHIM_SET_MAPPING("xboxkrnl.exe", RtlImageXexHeaderField, state);
SHIM_SET_MAPPING("xboxkrnl.exe", RtlInitializeCriticalSection, state);
SHIM_SET_MAPPING("xboxkrnl.exe", RtlInitializeCriticalSectionAndSpinCount, state);
SHIM_SET_MAPPING("xboxkrnl.exe", RtlEnterCriticalSection, state);
SHIM_SET_MAPPING("xboxkrnl.exe", RtlTryEnterCriticalSection, state);
SHIM_SET_MAPPING("xboxkrnl.exe", RtlLeaveCriticalSection, state);
}

View File

@@ -0,0 +1,57 @@
/**
******************************************************************************
* 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_RTL_H_
#define XENIA_KERNEL_XBOXKRNL_RTL_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/xbox.h>
namespace xe {
namespace kernel {
namespace xboxkrnl {
uint32_t xeRtlCompareMemory(uint32_t source1_ptr, uint32_t source2_ptr,
uint32_t length);
uint32_t xeRtlCompareMemoryUlong(uint32_t source_ptr, uint32_t length,
uint32_t pattern);
void xeRtlFillMemoryUlong(uint32_t destination_ptr, uint32_t length,
uint32_t pattern);
void xeRtlInitAnsiString(uint32_t destination_ptr, uint32_t source_ptr);
void xeRtlFreeAnsiString(uint32_t string_ptr);
void xeRtlInitUnicodeString(uint32_t destination_ptr, uint32_t source_ptr);
void xeRtlFreeUnicodeString(uint32_t string_ptr);
X_STATUS xeRtlUnicodeStringToAnsiString(
uint32_t destination_ptr, uint32_t source_ptr, uint32_t alloc_dest);
uint32_t xeRtlNtStatusToDosError(X_STATUS status);
uint32_t xeRtlImageXexHeaderField(uint32_t xex_header_base_ptr,
uint32_t image_field);
void xeRtlInitializeCriticalSection(uint32_t cs_ptr);
X_STATUS xeRtlInitializeCriticalSectionAndSpinCount(
uint32_t cs_ptr, uint32_t spin_count);
void xeRtlEnterCriticalSection(uint32_t cs_ptr, uint32_t thread_id);
uint32_t xeRtlTryEnterCriticalSection(uint32_t cs_ptr, uint32_t thread_id);
void xeRtlLeaveCriticalSection(uint32_t cs_ptr);
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_RTL_H_

View File

@@ -0,0 +1,872 @@
/**
******************************************************************************
* 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. *
******************************************************************************
*/
// This is a partial file designed to be included by other files when
// constructing various tables.
XE_EXPORT(xboxkrnl, 0x00000001, DbgBreakPoint, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000002, DbgBreakPointWithStatus, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000003, DbgPrint, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000004, DbgPrompt, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000005, DumpGetRawDumpInfo, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000006, DumpWriteDump, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000007, ExAcquireReadWriteLockExclusive, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000008, ExAcquireReadWriteLockShared, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000009, ExAllocatePool, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000000A, ExAllocatePoolWithTag, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000000B, ExAllocatePoolTypeWithTag, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000000C, ExConsoleGameRegion, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x0000000D, ExCreateThread, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000000E, ExEventObjectType, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x0000000F, ExFreePool, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000010, ExGetXConfigSetting, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000011, ExInitializeReadWriteLock, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000012, ExMutantObjectType, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x00000013, ExQueryPoolBlockSize, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000014, ExRegisterThreadNotification, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000015, ExRegisterTitleTerminateNotification, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000016, ExReleaseReadWriteLock, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000017, ExSemaphoreObjectType, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x00000018, ExSetXConfigSetting, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000019, ExTerminateThread, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000001A, ExTerminateTitleProcess, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000001B, ExThreadObjectType, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x0000001C, ExTimerObjectType, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x0000001D, MmDoubleMapMemory, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000001E, MmUnmapMemory, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000001F, XeKeysGetConsoleCertificate, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000020, FscGetCacheElementCount, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000021, FscSetCacheElementCount, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000022, HalGetCurrentAVPack, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000023, HalGpioControl, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000024, HalOpenCloseODDTray, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000025, HalReadWritePCISpace, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000026, HalRegisterPowerDownNotification, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000027, HalRegisterSMCNotification, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000028, HalReturnToFirmware, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000029, HalSendSMCMessage, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000002A, HalSetAudioEnable, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000002B, InterlockedFlushSList, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000002C, InterlockedPopEntrySList, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000002D, InterlockedPushEntrySList, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000002E, IoAcquireDeviceObjectLock, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000002F, IoAllocateIrp, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000030, IoBuildAsynchronousFsdRequest, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000031, IoBuildDeviceIoControlRequest, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000032, IoBuildSynchronousFsdRequest, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000033, IoCallDriver, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000034, IoCheckShareAccess, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000035, IoCompleteRequest, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000036, IoCompletionObjectType, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x00000037, IoCreateDevice, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000038, IoCreateFile, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000039, IoDeleteDevice, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000003A, IoDeviceObjectType, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x0000003B, IoDismountVolume, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000003C, IoDismountVolumeByFileHandle, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000003D, IoDismountVolumeByName, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000003E, IoFileObjectType, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x0000003F, IoFreeIrp, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000040, IoInitializeIrp, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000041, IoInvalidDeviceRequest, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000042, ExSetBetaFeaturesEnabled, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000043, IoQueueThreadIrp, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000044, IoReleaseDeviceObjectLock, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000045, IoRemoveShareAccess, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000046, IoSetIoCompletion, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000047, IoSetShareAccess, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000048, IoStartNextPacket, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000049, IoStartNextPacketByKey, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000004A, IoStartPacket, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000004B, IoSynchronousDeviceIoControlRequest, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000004C, IoSynchronousFsdRequest, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000004D, KeAcquireSpinLockAtRaisedIrql, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000004E, KeAlertResumeThread, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000004F, KeAlertThread, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000050, KeBlowFuses, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000051, KeBoostPriorityThread, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000052, KeBugCheck, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000053, KeBugCheckEx, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000054, KeCancelTimer, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000055, KeConnectInterrupt, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000056, KeContextFromKframes, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000057, KeContextToKframes, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000058, KeCreateUserMode, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000059, KeDebugMonitorData, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x0000005A, KeDelayExecutionThread, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000005B, KeDeleteUserMode, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000005C, KeDisconnectInterrupt, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000005D, KeEnableFpuExceptions, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000005E, KeEnablePPUPerformanceMonitor, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000005F, KeEnterCriticalRegion, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000060, KeEnterUserMode, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000061, KeFlushCacheRange, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000062, KeFlushCurrentEntireTb, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000063, KeFlushEntireTb, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000064, KeFlushUserModeCurrentTb, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000065, KeFlushUserModeTb, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000066, KeGetCurrentProcessType, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000067, KeGetPMWRegister, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000068, KeGetPRVRegister, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000069, KeGetSocRegister, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000006A, KeGetSpecialPurposeRegister, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000006B, KeLockL2, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000006C, KeUnlockL2, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000006D, KeInitializeApc, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000006E, KeInitializeDeviceQueue, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000006F, KeInitializeDpc, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000070, KeInitializeEvent, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000071, KeInitializeInterrupt, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000072, KeInitializeMutant, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000073, KeInitializeQueue, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000074, KeInitializeSemaphore, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000075, KeInitializeTimerEx, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000076, KeInsertByKeyDeviceQueue, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000077, KeInsertDeviceQueue, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000078, KeInsertHeadQueue, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000079, KeInsertQueue, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000007A, KeInsertQueueApc, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000007B, KeInsertQueueDpc, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000007C, KeIpiGenericCall, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000007D, KeLeaveCriticalRegion, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000007E, KeLeaveUserMode, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000007F, KePulseEvent, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000080, KeQueryBackgroundProcessors, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000081, KeQueryBasePriorityThread, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000082, KeQueryInterruptTime, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000083, KeQueryPerformanceFrequency, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000084, KeQuerySystemTime, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000085, KeRaiseIrqlToDpcLevel, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000086, KeRegisterDriverNotification, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000087, KeReleaseMutant, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000088, KeReleaseSemaphore, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000089, KeReleaseSpinLockFromRaisedIrql, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000008A, KeRemoveByKeyDeviceQueue, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000008B, KeRemoveDeviceQueue, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000008C, KeRemoveEntryDeviceQueue, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000008D, KeRemoveQueue, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000008E, KeRemoveQueueDpc, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000008F, KeResetEvent, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000090, KeRestoreFloatingPointState, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000091, KeRestoreVectorUnitState, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000092, KeResumeThread, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000093, KeRetireDpcList, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000094, KeRundownQueue, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000095, KeSaveFloatingPointState, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000096, KeSaveVectorUnitState, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000097, KeSetAffinityThread, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000098, KeSetBackgroundProcessors, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000099, KeSetBasePriorityThread, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000009A, KeSetCurrentProcessType, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000009B, KeSetCurrentStackPointers, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000009C, KeSetDisableBoostThread, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000009D, KeSetEvent, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000009E, KeSetEventBoostPriority, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000009F, KeSetPMWRegister, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000A0, KeSetPowerMode, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000A1, KeSetPRVRegister, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000A2, KeSetPriorityClassThread, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000A3, KeSetPriorityThread, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000A4, KeSetSocRegister, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000A5, KeSetSpecialPurposeRegister, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000A6, KeSetTimer, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000A7, KeSetTimerEx, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000A8, KeStallExecutionProcessor, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000A9, KeSuspendThread, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000AA, KeSweepDcacheRange, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000AB, KeSweepIcacheRange, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000AC, KeTestAlertThread, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000AD, KeTimeStampBundle, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x000000AE, KeTryToAcquireSpinLockAtRaisedIrql, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000AF, KeWaitForMultipleObjects, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000B0, KeWaitForSingleObject, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000B1, KfAcquireSpinLock, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000B2, KfRaiseIrql, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000B3, KfLowerIrql, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000B4, KfReleaseSpinLock, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000B5, KiBugCheckData, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x000000B6, LDICreateDecompression, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000B7, LDIDecompress, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000B8, LDIDestroyDecompression, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000B9, MmAllocatePhysicalMemory, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000BA, MmAllocatePhysicalMemoryEx, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000BB, MmCreateKernelStack, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000BC, MmDeleteKernelStack, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000BD, MmFreePhysicalMemory, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000BE, MmGetPhysicalAddress, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000BF, MmIsAddressValid, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000C0, MmLockAndMapSegmentArray, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000C1, MmLockUnlockBufferPages, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000C2, MmMapIoSpace, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000C3, MmPersistPhysicalMemoryAllocation, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000C4, MmQueryAddressProtect, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000C5, MmQueryAllocationSize, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000C6, MmQueryStatistics, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000C7, MmSetAddressProtect, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000C8, MmSplitPhysicalMemoryAllocation, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000C9, MmUnlockAndUnmapSegmentArray, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000CA, MmUnmapIoSpace, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000CB, Nls844UnicodeCaseTable, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x000000CC, NtAllocateVirtualMemory, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000CD, NtCancelTimer, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000CE, NtClearEvent, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000CF, NtClose, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000D0, NtCreateDirectoryObject, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000D1, NtCreateEvent, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000D2, NtCreateFile, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000D3, NtCreateIoCompletion, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000D4, NtCreateMutant, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000D5, NtCreateSemaphore, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000D6, NtCreateSymbolicLinkObject, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000D7, NtCreateTimer, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000D8, NtDeleteFile, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000D9, NtDeviceIoControlFile, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000DA, NtDuplicateObject, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000DB, NtFlushBuffersFile, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000DC, NtFreeVirtualMemory, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000DD, NtMakeTemporaryObject, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000DE, NtOpenDirectoryObject, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000DF, NtOpenFile, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000E0, NtOpenSymbolicLinkObject, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000E1, NtProtectVirtualMemory, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000E2, NtPulseEvent, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000E3, NtQueueApcThread, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000E4, NtQueryDirectoryFile, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000E5, NtQueryDirectoryObject, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000E6, NtQueryEvent, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000E7, NtQueryFullAttributesFile, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000E8, NtQueryInformationFile, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000E9, NtQueryIoCompletion, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000EA, NtQueryMutant, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000EB, NtQuerySemaphore, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000EC, NtQuerySymbolicLinkObject, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000ED, NtQueryTimer, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000EE, NtQueryVirtualMemory, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000EF, NtQueryVolumeInformationFile, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000F0, NtReadFile, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000F1, NtReadFileScatter, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000F2, NtReleaseMutant, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000F3, NtReleaseSemaphore, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000F4, NtRemoveIoCompletion, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000F5, NtResumeThread, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000F6, NtSetEvent, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000F7, NtSetInformationFile, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000F8, NtSetIoCompletion, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000F9, NtSetSystemTime, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000FA, NtSetTimerEx, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000FB, NtSignalAndWaitForSingleObjectEx, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000FC, NtSuspendThread, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000FD, NtWaitForSingleObjectEx, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000FE, NtWaitForMultipleObjectsEx, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000000FF, NtWriteFile, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000100, NtWriteFileGather, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000101, NtYieldExecution, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000102, ObCreateObject, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000103, ObCreateSymbolicLink, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000104, ObDeleteSymbolicLink, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000105, ObDereferenceObject, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000106, ObDirectoryObjectType, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x00000107, ObGetWaitableObject, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000108, ObInsertObject, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000109, ObIsTitleObject, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000010A, ObLookupAnyThreadByThreadId, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000010B, ObLookupThreadByThreadId, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000010C, ObMakeTemporaryObject, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000010D, ObOpenObjectByName, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000010E, ObOpenObjectByPointer, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000010F, ObReferenceObject, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000110, ObReferenceObjectByHandle, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000111, ObReferenceObjectByName, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000112, ObSymbolicLinkObjectType, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x00000113, ObTranslateSymbolicLink, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000114, RtlAnsiStringToUnicodeString, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000115, RtlAppendStringToString, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000116, RtlAppendUnicodeStringToString, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000117, RtlAppendUnicodeToString, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000118, RtlAssert, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000119, RtlCaptureContext, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000011A, RtlCompareMemory, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000011B, RtlCompareMemoryUlong, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000011C, RtlCompareString, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000011D, RtlCompareStringN, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000011E, RtlCompareUnicodeString, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000011F, RtlCompareUnicodeStringN, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000120, RtlCompareUtf8ToUnicode, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000121, RtlCopyString, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000122, RtlCopyUnicodeString, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000123, RtlCreateUnicodeString, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000124, RtlDowncaseUnicodeChar, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000125, RtlEnterCriticalSection, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000126, RtlFillMemoryUlong, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000127, RtlFreeAnsiString, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000128, RtlFreeUnicodeString, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000129, RtlGetCallersAddress, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000012A, RtlGetStackLimits, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000012B, RtlImageXexHeaderField, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000012C, RtlInitAnsiString, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000012D, RtlInitUnicodeString, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000012E, RtlInitializeCriticalSection, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000012F, RtlInitializeCriticalSectionAndSpinCount, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000130, RtlLeaveCriticalSection, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000131, RtlLookupFunctionEntry, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000132, RtlLowerChar, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000133, RtlMultiByteToUnicodeN, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000134, RtlMultiByteToUnicodeSize, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000135, RtlNtStatusToDosError, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000136, RtlRaiseException, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000137, RtlRaiseStatus, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000138, RtlRip, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000139, _scprintf, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000013A, _snprintf, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000013B, sprintf, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000013C, _scwprintf, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000013D, _snwprintf, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000013E, _swprintf, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000013F, RtlTimeFieldsToTime, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000140, RtlTimeToTimeFields, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000141, RtlTryEnterCriticalSection, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000142, RtlUnicodeStringToAnsiString, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000143, RtlUnicodeToMultiByteN, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000144, RtlUnicodeToMultiByteSize, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000145, RtlUnicodeToUtf8, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000146, RtlUnicodeToUtf8Size, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000147, RtlUnwind, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000148, RtlUnwind2, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000149, RtlUpcaseUnicodeChar, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000014A, RtlUpperChar, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000014B, RtlVirtualUnwind, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000014C, _vscprintf, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000014D, _vsnprintf, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000014E, vsprintf, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000014F, _vscwprintf, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000150, _vsnwprintf, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000151, _vswprintf, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000152, KeTlsAlloc, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000153, KeTlsFree, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000154, KeTlsGetValue, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000155, KeTlsSetValue, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000156, XboxHardwareInfo, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x00000157, XboxKrnlBaseVersion, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x00000158, XboxKrnlVersion, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x00000159, XeCryptAesKey, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000015A, XeCryptAesEcb, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000015B, XeCryptAesCbc, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000015C, XeCryptBnDwLeDhEqualBase, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000015D, XeCryptBnDwLeDhInvalBase, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000015E, XeCryptBnDwLeDhModExp, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000015F, XeCryptBnDw_Copy, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000160, XeCryptBnDw_SwapLeBe, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000161, XeCryptBnDw_Zero, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000162, XeCryptBnDwLePkcs1Format, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000163, XeCryptBnDwLePkcs1Verify, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000164, XeCryptBnQwBeSigCreate, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000165, XeCryptBnQwBeSigFormat, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000166, XeCryptBnQwBeSigVerify, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000167, XeCryptBnQwNeModExp, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000168, XeCryptBnQwNeModExpRoot, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000169, XeCryptBnQwNeModInv, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000016A, XeCryptBnQwNeModMul, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000016B, XeCryptBnQwNeRsaKeyGen, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000016C, XeCryptBnQwNeRsaPrvCrypt, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000016D, XeCryptBnQwNeRsaPubCrypt, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000016E, XeCryptBnQw_Copy, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000016F, XeCryptBnQw_SwapDwQw, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000170, XeCryptBnQw_SwapDwQwLeBe, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000171, XeCryptBnQw_SwapLeBe, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000172, XeCryptBnQw_Zero, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000173, XeCryptChainAndSumMac, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000174, XeCryptDesParity, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000175, XeCryptDesKey, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000176, XeCryptDesEcb, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000177, XeCryptDesCbc, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000178, XeCryptDes3Key, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000179, XeCryptDes3Ecb, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000017A, XeCryptDes3Cbc, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000017B, XeCryptHmacMd5Init, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000017C, XeCryptHmacMd5Update, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000017D, XeCryptHmacMd5Final, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000017E, XeCryptHmacMd5, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000017F, XeCryptHmacShaInit, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000180, XeCryptHmacShaUpdate, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000181, XeCryptHmacShaFinal, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000182, XeCryptHmacSha, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000183, XeCryptHmacShaVerify, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000184, XeCryptMd5Init, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000185, XeCryptMd5Update, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000186, XeCryptMd5Final, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000187, XeCryptMd5, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000188, XeCryptParveEcb, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000189, XeCryptParveCbcMac, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000018A, XeCryptRandom, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000018B, XeCryptRc4Key, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000018C, XeCryptRc4Ecb, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000018D, XeCryptRc4, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000018E, XeCryptRotSumSha, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000018F, XeCryptShaInit, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000190, XeCryptShaUpdate, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000191, XeCryptShaFinal, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000192, XeCryptSha, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000193, XexExecutableModuleHandle, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x00000194, XexCheckExecutablePrivilege, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000195, XexGetModuleHandle, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000196, XexGetModuleSection, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000197, XexGetProcedureAddress, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000198, XexLoadExecutable, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000199, XexLoadImage, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000019A, XexLoadImageFromMemory, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000019B, XexLoadImageHeaders, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000019C, XexPcToFileHeader, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000019D, KiApcNormalRoutineNop_, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000019E, XexRegisterPatchDescriptor, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000019F, XexSendDeferredNotifications, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001A0, XexStartExecutable, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001A1, XexUnloadImage, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001A2, XexUnloadImageAndExitThread, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001A3, XexUnloadTitleModules, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001A4, XexVerifyImageHeaders, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001A5, __C_specific_handler, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001A6, DbgLoadImageSymbols, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001A7, DbgUnLoadImageSymbols, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001A8, RtlImageDirectoryEntryToData, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001A9, RtlImageNtHeader, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001AA, ExDebugMonitorService, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001AB, MmDbgReadCheck, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001AC, MmDbgReleaseAddress, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001AD, MmDbgWriteCheck, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001AE, ExLoadedCommandLine, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x000001AF, ExLoadedImageName, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x000001B0, VdBlockUntilGUIIdle, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001B1, VdCallGraphicsNotificationRoutines, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001B2, VdDisplayFatalError, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001B3, VdEnableClosedCaption, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001B4, VdEnableDisableClockGating, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001B5, VdEnableDisablePowerSavingMode, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001B6, VdEnableRingBufferRPtrWriteBack, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001B7, VdGenerateGPUCSCCoefficients, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001B8, VdGetClosedCaptionReadyStatus, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001B9, VdGetCurrentDisplayGamma, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001BA, VdGetCurrentDisplayInformation, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001BB, VdGetDisplayModeOverride, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001BC, VdGetGraphicsAsicID, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001BD, VdGetSystemCommandBuffer, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001BE, VdGlobalDevice, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x000001BF, VdGlobalXamDevice, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x000001C0, VdGpuClockInMHz, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x000001C1, VdHSIOCalibrationLock, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x000001C2, VdInitializeEngines, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001C3, VdInitializeRingBuffer, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001C4, VdInitializeScaler, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001C5, VdInitializeScalerCommandBuffer, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001C6, VdIsHSIOTrainingSucceeded, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001C7, VdPersistDisplay, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001C8, VdQuerySystemCommandBuffer, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001C9, VdQueryVideoFlags, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001CA, VdQueryVideoMode, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001CB, VdReadDVERegisterUlong, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001CC, VdReadWriteHSIOCalibrationFlag, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001CD, VdRegisterGraphicsNotification, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001CE, VdRegisterXamGraphicsNotification, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001CF, VdSendClosedCaptionData, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001D0, VdSetCGMSOption, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001D1, VdSetColorProfileAdjustment, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001D2, VdSetCscMatricesOverride, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001D3, VdSetDisplayMode, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001D4, VdSetDisplayModeOverride, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001D5, VdSetGraphicsInterruptCallback, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001D6, VdSetHDCPOption, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001D7, VdSetMacrovisionOption, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001D8, VdSetSystemCommandBuffer, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001D9, VdSetSystemCommandBufferGpuIdentifierAddress, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001DA, VdSetWSSData, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001DB, VdSetWSSOption, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001DC, VdShutdownEngines, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001DD, VdTurnDisplayOff, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001DE, VdTurnDisplayOn, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001DF, KiApcNormalRoutineNop, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001E0, VdWriteDVERegisterUlong, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001E1, XVoicedHeadsetPresent, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001E2, XVoicedSubmitPacket, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001E3, XVoicedClose, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001E4, XVoicedActivate, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001E5, XInputdGetCapabilities, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001E6, XInputdReadState, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001E7, XInputdWriteState, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001E8, XInputdNotify, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001E9, XInputdRawState, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001EA, HidGetCapabilities, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001EB, HidReadKeys, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001EC, XInputdGetDeviceStats, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001ED, XInputdResetDevice, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001EE, XInputdSetRingOfLight, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001EF, XInputdSetRFPowerMode, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001F0, XInputdSetRadioFrequency, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001F1, HidGetLastInputTime, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001F2, XAudioRenderDriverInitialize, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001F3, XAudioRegisterRenderDriverClient, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001F4, XAudioUnregisterRenderDriverClient, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001F5, XAudioSubmitRenderDriverFrame, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001F6, XAudioRenderDriverLock, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001F7, XAudioGetVoiceCategoryVolumeChangeMask, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001F8, XAudioGetVoiceCategoryVolume, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001F9, XAudioSetVoiceCategoryVolume, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001FA, XAudioBeginDigitalBypassMode, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001FB, XAudioEndDigitalBypassMode, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001FC, XAudioSubmitDigitalPacket, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001FD, XAudioQueryDriverPerformance, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001FE, XAudioGetRenderDriverThread, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000001FF, XAudioGetSpeakerConfig, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000200, XAudioSetSpeakerConfig, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000201, NicSetUnicastAddress, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000202, NicAttach, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000203, NicDetach, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000204, NicXmit, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000205, NicUpdateMcastMembership, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000206, NicFlushXmitQueue, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000207, NicShutdown, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000208, NicGetLinkState, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000209, NicGetStats, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000020A, NicGetOpt, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000020B, NicSetOpt, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000020C, DrvSetSysReqCallback, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000020D, DrvSetUserBindingCallback, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000020E, DrvSetContentStorageCallback, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000020F, DrvSetAutobind, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000210, DrvGetContentStorageNotification, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000211, MtpdBeginTransaction, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000212, MtpdCancelTransaction, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000213, MtpdEndTransaction, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000214, MtpdGetCurrentDevices, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000215, MtpdReadData, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000216, MtpdReadEvent, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000217, MtpdResetDevice, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000218, MtpdSendData, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000219, MtpdVerifyProximity, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000021A, XUsbcamSetCaptureMode, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000021B, XUsbcamGetConfig, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000021C, XUsbcamSetConfig, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000021D, XUsbcamGetState, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000021E, XUsbcamReadFrame, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000021F, XUsbcamSnapshot, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000220, XUsbcamSetView, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000221, XUsbcamGetView, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000222, XUsbcamCreate, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000223, XUsbcamDestroy, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000224, XMACreateContext, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000225, XMAInitializeContext, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000226, XMAReleaseContext, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000227, XMAEnableContext, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000228, XMADisableContext, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000229, XMAGetOutputBufferWriteOffset, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000022A, XMASetOutputBufferReadOffset, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000022B, XMAGetOutputBufferReadOffset, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000022C, XMASetOutputBufferValid, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000022D, XMAIsOutputBufferValid, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000022E, XMASetInputBuffer0Valid, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000022F, XMAIsInputBuffer0Valid, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000230, XMASetInputBuffer1Valid, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000231, XMAIsInputBuffer1Valid, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000232, XMASetInputBuffer0, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000233, XMASetInputBuffer1, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000234, XMAGetPacketMetadata, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000235, XMABlockWhileInUse, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000236, XMASetLoopData, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000237, XMASetInputBufferReadOffset, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000238, XMAGetInputBufferReadOffset, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000239, ExIsBetaFeatureEnabled, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000023A, XeKeysGetFactoryChallenge, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000023B, XeKeysSetFactoryResponse, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000023C, XeKeysInitializeFuses, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000023D, XeKeysSaveBootLoader, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000023E, XeKeysSaveKeyVault, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000023F, XeKeysGetStatus, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000240, XeKeysGeneratePrivateKey, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000241, XeKeysGetKeyProperties, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000242, XeKeysSetKey, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000243, XeKeysGenerateRandomKey, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000244, XeKeysGetKey, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000245, XeKeysGetDigest, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000246, XeKeysGetConsoleID, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000247, XeKeysGetConsoleType, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000248, XeKeysQwNeRsaPrvCrypt, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000249, XeKeysHmacSha, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000024A, XInputdPassThroughRFCommand, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000024B, XeKeysAesCbc, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000024C, XeKeysDes2Cbc, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000024D, XeKeysDesCbc, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000024E, XeKeysObscureKey, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000024F, XeKeysHmacShaUsingKey, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000250, XeKeysSaveBootLoaderEx, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000251, XeKeysAesCbcUsingKey, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000252, XeKeysDes2CbcUsingKey, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000253, XeKeysDesCbcUsingKey, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000254, XeKeysObfuscate, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000255, XeKeysUnObfuscate, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000256, XeKeysConsolePrivateKeySign, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000257, XeKeysConsoleSignatureVerification, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000258, XeKeysVerifyRSASignature, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000259, StfsCreateDevice, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000025A, StfsControlDevice, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000025B, VdSwap, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000025C, HalFsbInterruptCount, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x0000025D, XeKeysSaveSystemUpdate, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000025E, XeKeysLockSystemUpdate, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000025F, XeKeysExecute, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000260, XeKeysGetVersions, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000261, XInputdPowerDownDevice, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000262, AniBlockOnAnimation, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000263, AniTerminateAnimation, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000264, XUsbcamReset, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000265, AniSetLogo, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000266, KeCertMonitorData, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x00000267, HalIsExecutingPowerDownDpc, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000268, VdInitializeEDRAM, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000269, VdRetrainEDRAM, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000026A, VdRetrainEDRAMWorker, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000026B, VdHSIOTrainCount, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x0000026C, HalGetPowerUpCause, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000026D, VdHSIOTrainingStatus, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x0000026E, RgcBindInfo, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x0000026F, VdReadEEDIDBlock, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000270, VdEnumerateVideoModes, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000271, VdEnableHDCP, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000272, VdRegisterHDCPNotification, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000273, HidReadMouseChanges, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000274, DumpSetCollectionFacility, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000275, XexTransformImageKey, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000276, XAudioOverrideSpeakerConfig, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000277, XInputdReadTextKeystroke, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000278, DrvXenonButtonPressed, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000279, DrvBindToUser, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000027A, XexGetModuleImportVersions, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000027B, RtlComputeCrc32, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000027C, XeKeysSetRevocationList, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000027D, HalRegisterPowerDownCallback, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000027E, VdGetDisplayDiscoveryData, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000027F, XInputdSendStayAliveRequest, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000280, XVoicedSendVPort, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000281, XVoicedGetBatteryStatus, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000282, XInputdFFGetDeviceInfo, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000283, XInputdFFSetEffect, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000284, XInputdFFUpdateEffect, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000285, XInputdFFEffectOperation, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000286, XInputdFFDeviceControl, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000287, XInputdFFSetDeviceGain, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000288, XInputdFFCancelIo, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000289, XInputdFFSetRumble, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000028A, NtAllocateEncryptedMemory, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000028B, NtFreeEncryptedMemory, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000028C, XeKeysExSaveKeyVault, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000028D, XeKeysExSetKey, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000028E, XeKeysExGetKey, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000028F, DrvSetDeviceConfigChangeCallback, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000290, DrvDeviceConfigChange, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000291, HalRegisterHdDvdRomNotification, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000292, XeKeysSecurityInitialize, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000293, XeKeysSecurityLoadSettings, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000294, XeKeysSecuritySaveSettings, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000295, XeKeysSecuritySetDetected, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000296, XeKeysSecurityGetDetected, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000297, XeKeysSecuritySetActivated, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000298, XeKeysSecurityGetActivated, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000299, XeKeysDvdAuthAP25InstallTable, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000029A, XeKeysDvdAuthAP25GetTableVersion, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000029B, XeKeysGetProtectedFlag, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000029C, XeKeysSetProtectedFlag, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000029D, KeEnablePFMInterrupt, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000029E, KeDisablePFMInterrupt, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000029F, KeSetProfilerISR, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002A0, VdStartDisplayDiscovery, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002A1, VdSetHDCPRevocationList, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002A2, XeKeysGetUpdateSequence, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002A3, XeKeysDvdAuthExActivate, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002A4, KeGetImagePageTableEntry, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002A5, HalRegisterBackgroundModeTransitionCallback, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002A6, AniStartBootAnimation, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002A7, HalClampUnclampOutputDACs, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002A8, HalPowerDownToBackgroundMode, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002A9, HalNotifyAddRemoveBackgroundTask, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002AA, HalCallBackgroundModeNotificationRoutines, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002AB, HalFsbResetCount, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x000002AC, HalGetMemoryInformation, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002AD, XInputdGetLastTextInputTime, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002AE, VdEnableWMAProOverHDMI, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002AF, XeKeysRevokeSaveSettings, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002B0, XInputdSetTextMessengerIndicator, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002B1, MicDeviceRequest, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002B2, XeKeysGetMediaID, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002B3, XeKeysLoadKeyVault, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002B4, KeGetVidInfo, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002B5, HalNotifyBackgroundModeTransitionComplete, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002B6, IoAcquireCancelSpinLock, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002B7, IoReleaseCancelSpinLock, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002B8, NtCancelIoFile, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002B9, NtCancelIoFileEx, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002BA, HalFinalizePowerLossRecovery, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002BB, HalSetPowerLossRecovery, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002BC, ExReadModifyWriteXConfigSettingUlong, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002BD, HalRegisterXamPowerDownCallback, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002BE, ExCancelAlarm, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002BF, ExInitializeAlarm, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002C0, ExSetAlarm, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002C1, XexActivationGetNonce, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002C2, XexActivationSetLicense, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002C3, IptvSetBoundaryKey, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002C4, IptvSetSessionKey, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002C5, IptvVerifyOmac1Signature, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002C6, IptvGetAesCtrTransform, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002C7, SataCdRomRecordReset, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002C8, XInputdSetTextDeviceKeyLocks, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002C9, XInputdGetTextDeviceKeyLocks, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002CA, XexActivationVerifyOwnership, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002CB, XexDisableVerboseDbgPrint, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002CC, SvodCreateDevice, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002CD, RtlCaptureStackBackTrace, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002CE, XeKeysRevokeUpdateDynamic, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002CF, XexImportTraceEnable, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002D0, ExRegisterXConfigNotification, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002D1, XeKeysSecuritySetStat, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002D2, VdQueryRealVideoMode, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002D3, XexSetExecutablePrivilege, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002D4, XAudioSuspendRenderDriverClients, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002D5, IptvGetSessionKeyHash, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002D6, VdSetCGMSState, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002D7, VdSetSCMSState, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002D8, KeFlushMultipleTb, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002D9, VdGetOption, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002DA, VdSetOption, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002DB, UsbdBootEnumerationDoneEvent, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x000002DC, StfsDeviceErrorEvent, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x000002DD, ExTryToAcquireReadWriteLockExclusive, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002DE, ExTryToAcquireReadWriteLockShared, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002DF, XexSetLastKdcTime, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002E0, XInputdControl, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002E1, RmcDeviceRequest, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002E2, LDIResetDecompression, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002E3, NicRegisterDevice, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002E4, UsbdAddDeviceComplete, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002E5, UsbdCancelAsyncTransfer, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002E6, UsbdGetDeviceSpeed, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002E7, UsbdGetDeviceTopology, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002E8, UsbdGetEndpointDescriptor, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002E9, UsbdIsDeviceAuthenticated, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002EA, UsbdOpenDefaultEndpoint, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002EB, UsbdOpenEndpoint, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002EC, UsbdQueueAsyncTransfer, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002ED, UsbdQueueCloseDefaultEndpoint, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002EE, UsbdQueueCloseEndpoint, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002EF, UsbdRemoveDeviceComplete, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002F0, KeRemoveQueueApc, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002F1, UsbdDriverLoadRequiredEvent, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x000002F2, UsbdGetRequiredDrivers, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002F3, UsbdRegisterDriverObject, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002F4, UsbdUnregisterDriverObject, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002F5, UsbdCallAndBlockOnDpcRoutine, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002F6, UsbdResetDevice, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002F7, UsbdGetDeviceDescriptor, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002F8, NomnilGetExtension, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002F9, NomnilStartCloseDevice, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002FA, WifiBeginAuthentication, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002FB, WifiCheckCounterMeasures, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002FC, WifiChooseAuthenCipherSetFromBSSID, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002FD, WifiCompleteAuthentication, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002FE, WifiGetAssociationIE, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x000002FF, WifiOnMICError, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000300, WifiPrepareAuthenticationContext, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000301, WifiRecvEAPOLPacket, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000302, WifiDeduceNetworkType, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000303, NicUnregisterDevice, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000304, DumpXitThread, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000305, XInputdSetWifiChannel, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000306, NomnilSetLed, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000307, WifiCalculateRegulatoryDomain, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000308, WifiSelectAdHocChannel, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000309, WifiChannelToFrequency, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000030A, MmGetPoolPagesType, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000030B, ExExpansionInstall, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000030C, ExExpansionCall, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000030D, PsCamDeviceRequest, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000030E, McaDeviceRequest, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000030F, DetroitDeviceRequest, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000310, XeCryptSha256Init, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000311, XeCryptSha256Update, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000312, XeCryptSha256Final, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000313, XeCryptSha256, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000314, XeCryptSha384Init, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000315, XeCryptSha384Update, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000316, XInputdGetDevicePid, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000317, HalGetNotedArgonErrors, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000318, XeCryptSha384Final, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000319, HalReadArgonEeprom, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000031A, HalWriteArgonEeprom, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000031B, XeKeysFcrtLoad, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000031C, XeKeysFcrtSave, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000031D, XeKeysFcrtSet, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000031E, XeCryptSha384, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000031F, XeCryptSha512Init, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000320, XAudioRegisterRenderDriverMECClient, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000321, XAudioUnregisterRenderDriverMECClient, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000322, XAudioCaptureRenderDriverFrame, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000323, XeCryptSha512Update, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000324, XeCryptSha512Final, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000325, XeCryptSha512, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000326, XeCryptBnQwNeCompare, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000327, XVoicedGetDirectionalData, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000328, DrvSetMicArrayStartCallback, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000329, DevAuthGetStatistics, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000032A, NullCableRequest, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000032B, XeKeysRevokeIsDeviceRevoked, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000032C, DumpUpdateDumpSettings, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000032D, EtxConsumerDisableEventType, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000032E, EtxConsumerEnableEventType, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000032F, EtxConsumerProcessLogs, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000330, EtxConsumerRegister, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000331, EtxConsumerUnregister, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000332, EtxProducerLog, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000333, EtxProducerLogV, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000334, EtxProducerRegister, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000335, EtxProducerUnregister, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000336, EtxConsumerFlushBuffers, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000337, EtxProducerLogXwpp, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000338, EtxProducerLogXwppV, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000339, UsbdEnableDisableRootHubPort, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000033A, EtxBufferRegister, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000033B, EtxBufferUnregister, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000033C, DumpRegisterDedicatedDataBlock, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000033D, XeKeysDvdAuthExSave, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000033E, XeKeysDvdAuthExInstall, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000033F, XexShimDisable, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000340, XexShimEnable, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000341, XexShimEntryDisable, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000342, XexShimEntryEnable, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000343, XexShimEntryRegister, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000344, XexShimLock, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000345, XboxKrnlVersion4Digit, ? , Variable, 0),
XE_EXPORT(xboxkrnl, 0x00000346, XeKeysObfuscateEx, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000347, XeKeysUnObfuscateEx, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000348, XexTitleHash, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000349, XexTitleHashClose, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000034A, XexTitleHashContinue, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000034B, XexTitleHashOpen, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000034C, XAudioGetRenderDriverTic, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000034D, XAudioEnableDucker, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000034E, XAudioSetDuckerLevel, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000034F, XAudioIsDuckerEnabled, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000350, XAudioGetDuckerLevel, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000351, XAudioGetDuckerThreshold, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000352, XAudioSetDuckerThreshold, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000353, XAudioGetDuckerAttackTime, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000354, XAudioSetDuckerAttackTime, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000355, XAudioGetDuckerReleaseTime, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000356, XAudioSetDuckerReleaseTime, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000357, XAudioGetDuckerHoldTime, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000358, XAudioSetDuckerHoldTime, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x00000359, DevAuthShouldAlwaysEnforce, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000035A, XAudioGetUnderrunCount, ? , Function, 0),
XE_EXPORT(xboxkrnl, 0x0000035C, XVoicedIsActiveProcess, ? , Function, 0),

View File

@@ -0,0 +1,703 @@
/**
******************************************************************************
* 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/xboxkrnl/xboxkrnl_threading.h>
#include <xenia/kernel/shim_utils.h>
#include <xenia/kernel/xboxkrnl/kernel_state.h>
#include <xenia/kernel/xboxkrnl/xboxkrnl_private.h>
#include <xenia/kernel/xboxkrnl/objects/xevent.h>
#include <xenia/kernel/xboxkrnl/objects/xthread.h>
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl;
namespace xe {
namespace kernel {
namespace xboxkrnl {
// r13 + 0x100: pointer to thread local state
// Thread local state:
// 0x058: kernel time
// 0x14C: thread id
// 0x150: if >0 then error states don't get set
// 0x160: last error
// GetCurrentThreadId:
// lwz r11, 0x100(r13)
// lwz r3, 0x14C(r11)
// RtlGetLastError:
// lwz r11, 0x150(r13)
// if (r11 != 0) {
// lwz r11, 0x100(r13)
// stw r3, 0x160(r11)
// }
// RtlSetLastError:
// lwz r11, 0x150(r13)
// if (r11 != 0) {
// lwz r11, 0x100(r13)
// stw r3, 0x160(r11)
// }
// RtlSetLastNTError:
// r3 = RtlNtStatusToDosError(r3)
// lwz r11, 0x150(r13)
// if (r11 != 0) {
// lwz r11, 0x100(r13)
// stw r3, 0x160(r11)
// }
X_STATUS xeExCreateThread(
uint32_t* handle_ptr, uint32_t stack_size, uint32_t* thread_id_ptr,
uint32_t xapi_thread_startup,
uint32_t start_address, uint32_t start_context, uint32_t creation_flags) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
// DWORD
// LPHANDLE Handle,
// DWORD StackSize,
// LPDWORD ThreadId,
// LPVOID XapiThreadStartup, ?? often 0
// LPVOID StartAddress,
// LPVOID StartContext,
// DWORD CreationFlags // 0x80?
XThread* thread = new XThread(
state, stack_size, xapi_thread_startup, start_address, start_context,
creation_flags);
X_STATUS result_code = thread->Create();
if (XFAILED(result_code)) {
// Failed!
thread->Release();
XELOGE("Thread creation failed: %.8X", result_code);
return result_code;
}
if (handle_ptr) {
*handle_ptr = thread->handle();
}
if (thread_id_ptr) {
*thread_id_ptr = thread->thread_id();
}
return result_code;
}
SHIM_CALL ExCreateThread_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t handle_ptr = SHIM_GET_ARG_32(0);
uint32_t stack_size = SHIM_GET_ARG_32(1);
uint32_t thread_id_ptr = SHIM_GET_ARG_32(2);
uint32_t xapi_thread_startup = SHIM_GET_ARG_32(3);
uint32_t start_address = SHIM_GET_ARG_32(4);
uint32_t start_context = SHIM_GET_ARG_32(5);
uint32_t creation_flags = SHIM_GET_ARG_32(6);
XELOGD(
"ExCreateThread(%.8X, %d, %.8X, %.8X, %.8X, %.8X, %.8X)",
handle_ptr,
stack_size,
thread_id_ptr,
xapi_thread_startup,
start_address,
start_context,
creation_flags);
uint32_t handle;
uint32_t thread_id;
X_STATUS result = xeExCreateThread(
&handle, stack_size, &thread_id, xapi_thread_startup,
start_address, start_context, creation_flags);
if (XSUCCEEDED(result)) {
if (handle_ptr) {
SHIM_SET_MEM_32(handle_ptr, handle);
}
if (thread_id_ptr) {
SHIM_SET_MEM_32(thread_id_ptr, thread_id);
}
}
SHIM_SET_RETURN(result);
}
uint32_t xeKeSetAffinityThread(void* thread_ptr, uint32_t affinity) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
XThread* thread = (XThread*)XObject::GetObject(state, thread_ptr);
if (thread) {
// TODO(benvanik): implement.
}
return affinity;
}
SHIM_CALL KeSetAffinityThread_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t thread = SHIM_GET_ARG_32(0);
uint32_t affinity = SHIM_GET_ARG_32(1);
XELOGD(
"KeSetAffinityThread(%.8X, %.8X)",
thread,
affinity);
void* thread_ptr = SHIM_MEM_ADDR(thread);
uint32_t result = xeKeSetAffinityThread(thread_ptr, affinity);
SHIM_SET_RETURN(result);
}
uint32_t xeKeGetCurrentProcessType() {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
// DWORD
return X_PROCTYPE_USER;
}
SHIM_CALL KeGetCurrentProcessType_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
XELOGD(
"KeGetCurrentProcessType()");
int result = xeKeGetCurrentProcessType();
SHIM_SET_RETURN(result);
}
uint64_t xeKeQueryPerformanceFrequency() {
LARGE_INTEGER frequency;
if (QueryPerformanceFrequency(&frequency)) {
return frequency.QuadPart;
} else {
return 0;
}
}
SHIM_CALL KeQueryPerformanceFrequency_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
XELOGD(
"KeQueryPerformanceFrequency()");
uint64_t result = xeKeQueryPerformanceFrequency();
SHIM_SET_RETURN(result);
}
X_STATUS xeKeDelayExecutionThread(
uint32_t processor_mode, uint32_t alertable, uint64_t interval) {
XThread* thread = XThread::GetCurrentThread();
return thread->Delay(processor_mode, alertable, interval);
}
SHIM_CALL KeDelayExecutionThread_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t processor_mode = SHIM_GET_ARG_32(0);
uint32_t alertable = SHIM_GET_ARG_32(1);
uint32_t interval_ptr = SHIM_GET_ARG_32(2);
uint64_t interval = SHIM_MEM_64(interval_ptr);
XELOGD(
"KeDelayExecutionThread(%.8X, %d, %.8X(%.16llX)",
processor_mode, alertable, interval_ptr, interval);
X_STATUS result = xeKeDelayExecutionThread(
processor_mode, alertable, interval);
SHIM_SET_RETURN(result);
}
void xeKeQuerySystemTime(uint64_t* time_ptr) {
FILETIME t;
GetSystemTimeAsFileTime(&t);
*time_ptr = ((uint64_t)t.dwHighDateTime << 32) | t.dwLowDateTime;
}
SHIM_CALL KeQuerySystemTime_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t time_ptr = SHIM_GET_ARG_32(0);
XELOGD(
"KeQuerySystemTime(%.8X)",
time_ptr);
uint64_t time;
xeKeQuerySystemTime(&time);
if (time_ptr) {
SHIM_SET_MEM_64(time_ptr, time);
}
}
// The TLS system used here is a bit hacky, but seems to work.
// Both Win32 and pthreads use unsigned longs as TLS indices, so we can map
// right into the system for these calls. We're just round tripping the IDs and
// hoping for the best.
// http://msdn.microsoft.com/en-us/library/ms686801
uint32_t xeKeTlsAlloc() {
// DWORD
uint32_t tls_index;
#if XE_PLATFORM(WIN32)
tls_index = TlsAlloc();
#else
pthread_key_t key;
if (pthread_key_create(&key, NULL)) {
tls_index = X_TLS_OUT_OF_INDEXES;
} else {
tls_index = (uint32_t)key;
}
#endif // WIN32
return tls_index;
}
SHIM_CALL KeTlsAlloc_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
XELOGD(
"KeTlsAlloc()");
uint32_t result = xeKeTlsAlloc();
SHIM_SET_RETURN(result);
}
// http://msdn.microsoft.com/en-us/library/ms686804
int KeTlsFree(uint32_t tls_index) {
// BOOL
// _In_ DWORD dwTlsIndex
if (tls_index == X_TLS_OUT_OF_INDEXES) {
return 0;
}
int result_code = 0;
#if XE_PLATFORM(WIN32)
result_code = TlsFree(tls_index);
#else
result_code = pthread_key_delete(tls_index) == 0;
#endif // WIN32
return result_code;
}
SHIM_CALL KeTlsFree_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t tls_index = SHIM_GET_ARG_32(0);
XELOGD(
"KeTlsFree(%.8X)",
tls_index);
int result = xeKeTlsAlloc();
SHIM_SET_RETURN(result);
}
// http://msdn.microsoft.com/en-us/library/ms686812
uint64_t xeKeTlsGetValue(uint32_t tls_index) {
// LPVOID
// _In_ DWORD dwTlsIndex
uint64_t value = 0;
#if XE_PLATFORM(WIN32)
value = (uint64_t)TlsGetValue(tls_index);
#else
value = (uint64_t)pthread_getspecific(tls_index);
#endif // WIN32
if (!value) {
XELOGW("KeTlsGetValue should SetLastError if result is NULL");
// TODO(benvanik): SetLastError
}
return value;
}
SHIM_CALL KeTlsGetValue_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t tls_index = SHIM_GET_ARG_32(0);
XELOGD(
"KeTlsGetValue(%.8X)",
tls_index);
uint64_t result = xeKeTlsGetValue(tls_index);
SHIM_SET_RETURN(result);
}
// http://msdn.microsoft.com/en-us/library/ms686818
int xeKeTlsSetValue(uint32_t tls_index, uint64_t tls_value) {
// BOOL
// _In_ DWORD dwTlsIndex,
// _In_opt_ LPVOID lpTlsValue
int result_code = 0;
#if XE_PLATFORM(WIN32)
result_code = TlsSetValue(tls_index, (LPVOID)tls_value);
#else
result_code = pthread_setspecific(tls_index, (void*)tls_value) == 0;
#endif // WIN32
return result_code;
}
SHIM_CALL KeTlsSetValue_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t tls_index = SHIM_GET_ARG_32(0);
uint32_t tls_value = SHIM_GET_ARG_32(1);
XELOGD(
"KeTlsSetValue(%.8X, %.8X)",
tls_index, tls_value);
int result = xeKeTlsSetValue(tls_index, tls_value);
SHIM_SET_RETURN(result);
}
X_STATUS xeNtCreateEvent(uint32_t* handle_ptr, void* obj_attributes,
uint32_t event_type, uint32_t initial_state) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
XEvent* ev = new XEvent(state);
ev->Initialize(!event_type, !!initial_state);
// obj_attributes may have a name inside of it, if != NULL.
if (obj_attributes) {
//ev->SetName(...);
}
*handle_ptr = ev->handle();
return X_STATUS_SUCCESS;
}
SHIM_CALL NtCreateEvent_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t handle_ptr = SHIM_GET_ARG_32(0);
uint32_t obj_attributes_ptr = SHIM_GET_ARG_32(1);
uint32_t event_type = SHIM_GET_ARG_32(2);
uint32_t initial_state = SHIM_GET_ARG_32(3);
XELOGD(
"NtCreateEvent(%.8X, %.8X, %d, %d)",
handle_ptr, obj_attributes_ptr, event_type, initial_state);
uint32_t handle;
X_STATUS result = xeNtCreateEvent(
&handle, SHIM_MEM_ADDR(obj_attributes_ptr),
event_type, initial_state);
if (XSUCCEEDED(result)) {
if (handle_ptr) {
SHIM_SET_MEM_32(handle_ptr, handle);
}
}
SHIM_SET_RETURN(result);
}
int32_t xeKeSetEvent(void* event_ptr, uint32_t increment, uint32_t wait) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
XEvent* ev = (XEvent*)XObject::GetObject(state, event_ptr);
XEASSERTNOTNULL(ev);
if (!ev) {
return 0;
}
return ev->Set(increment, !!wait);
}
SHIM_CALL KeSetEvent_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t event_ref = SHIM_GET_ARG_32(0);
uint32_t increment = SHIM_GET_ARG_32(1);
uint32_t wait = SHIM_GET_ARG_32(2);
XELOGD(
"KeSetEvent(%.8X, %.8X, %.8X)",
event_ref, increment, wait);
void* event_ptr = SHIM_MEM_ADDR(event_ref);
int32_t result = xeKeSetEvent(event_ptr, increment, wait);
SHIM_SET_RETURN(result);
}
SHIM_CALL NtSetEvent_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t event_handle = SHIM_GET_ARG_32(0);
uint32_t previous_state_ptr = SHIM_GET_ARG_32(1);
XELOGD(
"NtSetEvent(%.8X, %.8X)",
event_handle, previous_state_ptr);
X_STATUS result = X_STATUS_SUCCESS;
XEvent* ev = NULL;
result = state->object_table()->GetObject(
event_handle, (XObject**)&ev);
if (XSUCCEEDED(result)) {
int32_t was_signalled = ev->Set(0, false);
if (previous_state_ptr) {
SHIM_SET_MEM_32(previous_state_ptr, was_signalled);
}
ev->Release();
}
SHIM_SET_RETURN(result);
}
int32_t xeKeResetEvent(void* event_ptr) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
XEvent* ev = (XEvent*)XEvent::GetObject(state, event_ptr);
XEASSERTNOTNULL(ev);
if (!ev) {
return 0;
}
return ev->Reset();
}
SHIM_CALL KeResetEvent_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t event_ref = SHIM_GET_ARG_32(0);
XELOGD(
"KeResetEvent(%.8X)",
event_ref);
void* event_ptr = SHIM_MEM_ADDR(event_ref);
int32_t result = xeKeResetEvent(event_ptr);
SHIM_SET_RETURN(result);
}
X_STATUS xeKeWaitForSingleObject(
void* object_ptr, uint32_t wait_reason, uint32_t processor_mode,
uint32_t alertable, uint64_t* opt_timeout) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
XObject* object = XObject::GetObject(state, object_ptr);
if (!object) {
// The only kind-of failure code.
return X_STATUS_ABANDONED_WAIT_0;
}
return object->Wait(wait_reason, processor_mode, alertable, opt_timeout);
}
SHIM_CALL KeWaitForSingleObject_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t object = SHIM_GET_ARG_32(0);
uint32_t wait_reason = SHIM_GET_ARG_32(1);
uint32_t processor_mode = SHIM_GET_ARG_32(2);
uint32_t alertable = SHIM_GET_ARG_32(3);
uint32_t timeout_ptr = SHIM_GET_ARG_32(4);
XELOGD(
"KeWaitForSingleObject(%.8X, %.8X, %.8X, %.1X, %.8X)",
object, wait_reason, processor_mode, alertable, timeout_ptr);
void* object_ptr = SHIM_MEM_ADDR(object);
uint64_t timeout = timeout_ptr ? SHIM_MEM_64(timeout_ptr) : 0;
X_STATUS result = xeKeWaitForSingleObject(
object_ptr, wait_reason, processor_mode, alertable,
timeout_ptr ? &timeout : NULL);
SHIM_SET_RETURN(result);
}
SHIM_CALL NtWaitForSingleObjectEx_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t object_handle = SHIM_GET_ARG_32(0);
uint32_t timeout = SHIM_GET_ARG_32(1);
uint32_t alertable = SHIM_GET_ARG_32(2);
XELOGD(
"NtWaitForSingleObjectEx(%.8X, %.8X, %.1X)",
object_handle, timeout, alertable);
X_STATUS result = X_STATUS_SUCCESS;
XObject* object = NULL;
result = state->object_table()->GetObject(
object_handle, &object);
if (XSUCCEEDED(result)) {
uint64_t timeout_ns = timeout * 1000000 / 100;
timeout_ns = ~timeout_ns; // Relative.
result = object->Wait(
3, 1, alertable,
timeout == 0xFFFFFFFF ? 0 : &timeout_ns);
object->Release();
}
SHIM_SET_RETURN(result);
}
uint32_t xeKfAcquireSpinLock(void* lock_ptr) {
// Lock.
while (!xe_atomic_cas_32(0, 1, lock_ptr)) {
// Spin!
// TODO(benvanik): error on deadlock?
}
// Raise IRQL to DISPATCH.
XThread* thread = XThread::GetCurrentThread();
return thread->RaiseIrql(2);
}
SHIM_CALL KfAcquireSpinLock_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t lock_ptr = SHIM_GET_ARG_32(0);
XELOGD(
"KfAcquireSpinLock(%.8X)",
lock_ptr);
uint32_t old_irql = xeKfAcquireSpinLock(SHIM_MEM_ADDR(lock_ptr));
SHIM_SET_RETURN(old_irql);
}
void xeKfReleaseSpinLock(void* lock_ptr, uint32_t old_irql) {
// Restore IRQL.
XThread* thread = XThread::GetCurrentThread();
thread->LowerIrql(old_irql);
// Unlock.
xe_atomic_dec_32(lock_ptr);
}
SHIM_CALL KfReleaseSpinLock_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t lock_ptr = SHIM_GET_ARG_32(0);
uint32_t old_irql = SHIM_GET_ARG_32(1);
XELOGD(
"KfReleaseSpinLock(%.8X, %d)",
lock_ptr,
old_irql);
xeKfReleaseSpinLock(SHIM_MEM_ADDR(lock_ptr), old_irql);
}
void xeKeEnterCriticalRegion() {
XThread::EnterCriticalRegion();
}
SHIM_CALL KeEnterCriticalRegion_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
XELOGD(
"KeEnterCriticalRegion()");
xeKeEnterCriticalRegion();
}
void xeKeLeaveCriticalRegion() {
XThread::LeaveCriticalRegion();
}
SHIM_CALL KeLeaveCriticalRegion_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
XELOGD(
"KeLeaveCriticalRegion()");
xeKeLeaveCriticalRegion();
}
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
void xe::kernel::xboxkrnl::RegisterThreadingExports(
ExportResolver* export_resolver, KernelState* state) {
SHIM_SET_MAPPING("xboxkrnl.exe", ExCreateThread, state);
SHIM_SET_MAPPING("xboxkrnl.exe", KeSetAffinityThread, state);
SHIM_SET_MAPPING("xboxkrnl.exe", KeGetCurrentProcessType, state);
SHIM_SET_MAPPING("xboxkrnl.exe", KeQueryPerformanceFrequency, state);
SHIM_SET_MAPPING("xboxkrnl.exe", KeDelayExecutionThread, state);
SHIM_SET_MAPPING("xboxkrnl.exe", KeQuerySystemTime, state);
SHIM_SET_MAPPING("xboxkrnl.exe", KeTlsAlloc, state);
SHIM_SET_MAPPING("xboxkrnl.exe", KeTlsFree, state);
SHIM_SET_MAPPING("xboxkrnl.exe", KeTlsGetValue, state);
SHIM_SET_MAPPING("xboxkrnl.exe", KeTlsSetValue, state);
SHIM_SET_MAPPING("xboxkrnl.exe", NtCreateEvent, state);
SHIM_SET_MAPPING("xboxkrnl.exe", KeSetEvent, state);
SHIM_SET_MAPPING("xboxkrnl.exe", NtSetEvent, state);
SHIM_SET_MAPPING("xboxkrnl.exe", KeResetEvent, state);
SHIM_SET_MAPPING("xboxkrnl.exe", KeWaitForSingleObject, state);
SHIM_SET_MAPPING("xboxkrnl.exe", NtWaitForSingleObjectEx, state);
SHIM_SET_MAPPING("xboxkrnl.exe", KfAcquireSpinLock, state);
SHIM_SET_MAPPING("xboxkrnl.exe", KfReleaseSpinLock, state);
SHIM_SET_MAPPING("xboxkrnl.exe", KeEnterCriticalRegion, state);
SHIM_SET_MAPPING("xboxkrnl.exe", KeLeaveCriticalRegion, state);
}

View File

@@ -0,0 +1,65 @@
/**
******************************************************************************
* 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_THREADING_H_
#define XENIA_KERNEL_XBOXKRNL_THREADING_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/xbox.h>
namespace xe {
namespace kernel {
namespace xboxkrnl {
X_STATUS xeExCreateThread(
uint32_t* handle_ptr, uint32_t stack_size, uint32_t* thread_id_ptr,
uint32_t xapi_thread_startup,
uint32_t start_address, uint32_t start_context, uint32_t creation_flags);
uint32_t xeKeSetAffinityThread(void* thread_ptr, uint32_t affinity);
uint32_t xeKeGetCurrentProcessType();
uint64_t xeKeQueryPerformanceFrequency();
void xeKeQuerySystemTime(uint64_t* time_ptr);
X_STATUS xeKeDelayExecutionThread(
uint32_t processor_mode, uint32_t alertable, uint64_t interval);
uint32_t xeKeTlsAlloc();
int KeTlsFree(uint32_t tls_index);
uint64_t xeKeTlsGetValue(uint32_t tls_index);
int xeKeTlsSetValue(uint32_t tls_index, uint64_t tls_value);
X_STATUS xeNtCreateEvent(uint32_t* handle_ptr, void* obj_attributes,
uint32_t event_type, uint32_t initial_state);
int32_t xeKeSetEvent(void* event_ptr, uint32_t increment, uint32_t wait);
int32_t xeKeResetEvent(void* event_ptr);
X_STATUS xeKeWaitForSingleObject(
void* object_ptr, uint32_t wait_reason, uint32_t processor_mode,
uint32_t alertable, uint64_t* opt_timeout);
uint32_t xeKfAcquireSpinLock(void* lock_ptr);
void xeKfReleaseSpinLock(void* lock_ptr, uint32_t old_irql);
void xeKeEnterCriticalRegion();
void xeKeLeaveCriticalRegion();
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_THREADING_H_

View File

@@ -0,0 +1,487 @@
/**
******************************************************************************
* 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/xboxkrnl/xboxkrnl_video.h>
#include <xenia/emulator.h>
#include <xenia/cpu/cpu.h>
#include <xenia/gpu/gpu.h>
#include <xenia/kernel/shim_utils.h>
#include <xenia/kernel/xboxkrnl/kernel_state.h>
#include <xenia/kernel/xboxkrnl/xboxkrnl_private.h>
#include <xenia/kernel/xboxkrnl/xboxkrnl_rtl.h>
using namespace xe;
using namespace xe::gpu;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl;
namespace xe {
namespace kernel {
namespace xboxkrnl {
// http://www.tweakoz.com/orkid/
// http://www.tweakoz.com/orkid/dox/d3/d52/xb360init_8cpp_source.html
// https://github.com/Free60Project/xenosfb/
// https://github.com/Free60Project/xenosfb/blob/master/src/xe.h
// https://github.com/gligli/libxemit
// http://web.archive.org/web/20090428095215/http://msdn.microsoft.com/en-us/library/bb313877.aspx
// http://web.archive.org/web/20100423054747/http://msdn.microsoft.com/en-us/library/bb313961.aspx
// http://web.archive.org/web/20100423054747/http://msdn.microsoft.com/en-us/library/bb313878.aspx
// http://web.archive.org/web/20090510235238/http://msdn.microsoft.com/en-us/library/bb313942.aspx
// http://svn.dd-wrt.com/browser/src/linux/universal/linux-3.8/drivers/gpu/drm/radeon/radeon_ring.c
// http://www.microsoft.com/en-za/download/details.aspx?id=5313 -- "Stripped Down Direct3D: Xbox 360 Command Buffer and Resource Management"
void xeVdGetCurrentDisplayGamma(uint32_t* arg0, float* arg1) {
*arg0 = 2;
*arg1 = 2.22222233f;
}
SHIM_CALL VdGetCurrentDisplayGamma_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t arg0_ptr = SHIM_GET_ARG_32(0);
uint32_t arg1_ptr = SHIM_GET_ARG_32(1);
XELOGD(
"VdGetCurrentDisplayGamma(%.8X, %.8X)",
arg0_ptr, arg1_ptr);
uint32_t arg0 = 0;
union {
float float_value;
uint32_t uint_value;
} arg1;
xeVdGetCurrentDisplayGamma(&arg0, &arg1.float_value);
SHIM_SET_MEM_32(arg0_ptr, arg0);
SHIM_SET_MEM_32(arg1_ptr, arg1.uint_value);
}
SHIM_CALL VdGetCurrentDisplayInformation_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t ptr = SHIM_GET_ARG_32(0);
XELOGD(
"VdGetCurrentDisplayInformation(%.8X)",
ptr);
// Expecting a length 0x58 struct of stuff.
SHIM_SET_MEM_32(ptr + 0x10, 1280);
SHIM_SET_MEM_32(ptr + 0x14, 720);
SHIM_SET_MEM_16(ptr + 0x48, 1280);
SHIM_SET_MEM_16(ptr + 0x4A, 720);
SHIM_SET_MEM_16(ptr + 0x56, 1280);
}
uint32_t xeVdQueryVideoFlags() {
// ?
return 0x00000007;
}
SHIM_CALL VdQueryVideoFlags_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
XELOGD(
"VdQueryVideoFlags()");
SHIM_SET_RETURN(xeVdQueryVideoFlags());
}
void xeVdQueryVideoMode(X_VIDEO_MODE *video_mode, bool swap) {
if (video_mode == NULL) {
return;
}
// TODO: get info from actual display
video_mode->display_width = 1280;
video_mode->display_height = 720;
video_mode->is_interlaced = 0;
video_mode->is_widescreen = 1;
video_mode->is_hi_def = 1;
video_mode->refresh_rate = 60.0f;
video_mode->video_standard = 1; // NTSC
video_mode->unknown_0x8a = 0x8A;
video_mode->unknown_0x01 = 0x01;
if (swap) {
video_mode->display_width = XESWAP32BE(video_mode->display_width);
video_mode->display_height = XESWAP32BE(video_mode->display_height);
video_mode->is_interlaced = XESWAP32BE(video_mode->is_interlaced);
video_mode->is_widescreen = XESWAP32BE(video_mode->is_widescreen);
video_mode->is_hi_def = XESWAP32BE(video_mode->is_hi_def);
video_mode->refresh_rate = XESWAPF32BE(video_mode->refresh_rate);
video_mode->video_standard = XESWAP32BE(video_mode->video_standard);
video_mode->unknown_0x8a = XESWAP32BE(video_mode->unknown_0x8a);
video_mode->unknown_0x01 = XESWAP32BE(video_mode->unknown_0x01);
}
}
SHIM_CALL VdQueryVideoMode_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t video_mode_ptr = SHIM_GET_ARG_32(0);
X_VIDEO_MODE *video_mode = (X_VIDEO_MODE*)SHIM_MEM_ADDR(video_mode_ptr);
XELOGD(
"VdQueryVideoMode(%.8X)",
video_mode_ptr);
xeVdQueryVideoMode(video_mode, true);
}
void xeVdInitializeEngines(uint32_t unk0, uint32_t callback, uint32_t unk1,
uint32_t unk2_ptr, uint32_t unk3_ptr) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
GraphicsSystem* gs = state->emulator()->graphics_system();
if (!gs) {
return;
}
// r3 = 0x4F810000
// r4 = function ptr (cleanup callback?)
// r5 = 0
// r6/r7 = some binary data in .data
}
SHIM_CALL VdInitializeEngines_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t unk0 = SHIM_GET_ARG_32(0);
uint32_t callback = SHIM_GET_ARG_32(1);
uint32_t unk1 = SHIM_GET_ARG_32(2);
uint32_t unk2_ptr = SHIM_GET_ARG_32(3);
uint32_t unk3_ptr = SHIM_GET_ARG_32(4);
XELOGD(
"VdInitializeEngines(%.8X, %.8X, %.8X, %.8X, %.8X)",
unk0, callback, unk1, unk2_ptr, unk3_ptr);
xeVdInitializeEngines(unk0, callback, unk1, unk2_ptr, unk3_ptr);
}
void xeVdSetGraphicsInterruptCallback(uint32_t callback, uint32_t user_data) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
GraphicsSystem* gs = state->emulator()->graphics_system();
if (!gs) {
return;
}
// callback takes 2 params
// r3 = bool 0/1 - 0 is normal interrupt, 1 is some acquire/lock mumble
// r4 = user_data (r4 of VdSetGraphicsInterruptCallback)
gs->SetInterruptCallback(callback, user_data);
}
SHIM_CALL VdSetGraphicsInterruptCallback_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t callback = SHIM_GET_ARG_32(0);
uint32_t user_data = SHIM_GET_ARG_32(1);
XELOGD(
"VdSetGraphicsInterruptCallback(%.8X, %.8X)",
callback, user_data);
xeVdSetGraphicsInterruptCallback(callback, user_data);
}
void xeVdInitializeRingBuffer(uint32_t ptr, uint32_t page_count) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
GraphicsSystem* gs = state->emulator()->graphics_system();
if (!gs) {
return;
}
// r3 = result of MmGetPhysicalAddress
// r4 = number of pages? page size?
// 0x8000 -> cntlzw=16 -> 0x1C - 16 = 12
// Buffer pointers are from MmAllocatePhysicalMemory with WRITE_COMBINE.
// Sizes could be zero? XBLA games seem to do this. Default sizes?
// D3D does size / region_count - must be > 1024
gs->InitializeRingBuffer(ptr, page_count);
}
SHIM_CALL VdInitializeRingBuffer_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t ptr = SHIM_GET_ARG_32(0);
uint32_t page_count = SHIM_GET_ARG_32(1);
XELOGD(
"VdInitializeRingBuffer(%.8X, %.8X)",
ptr, page_count);
xeVdInitializeRingBuffer(ptr, page_count);
}
void xeVdEnableRingBufferRPtrWriteBack(uint32_t ptr, uint32_t block_size) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
GraphicsSystem* gs = state->emulator()->graphics_system();
if (!gs) {
return;
}
// r4 = 6, usually --- <=19
gs->EnableReadPointerWriteBack(ptr, block_size);
ptr += 0x20000000;
printf("%.8X", ptr);
// 0x0110343c
// r3 = 0x2B10(d3d?) + 0x3C
//((p + 0x3C) & 0x1FFFFFFF) + ((((p + 0x3C) >> 20) + 0x200) & 0x1000)
//also 0x3C offset into WriteBacks is PrimaryRingBufferReadIndex
//(1:17:38 AM) Rick: .text:8201B348 lwz r11, 0x2B10(r31)
//(1:17:38 AM) Rick: .text:8201B34C addi r11, r11, 0x3C
//(1:17:38 AM) Rick: .text:8201B350 srwi r10, r11, 20 # r10 = r11 >> 20
//(1:17:38 AM) Rick: .text:8201B354 clrlwi r11, r11, 3 # r11 = r11 & 0x1FFFFFFF
//(1:17:38 AM) Rick: .text:8201B358 addi r10, r10, 0x200
//(1:17:39 AM) Rick: .text:8201B35C rlwinm r10, r10, 0,19,19 # r10 = r10 & 0x1000
//(1:17:39 AM) Rick: .text:8201B360 add r3, r10, r11
//(1:17:39 AM) Rick: .text:8201B364 bl VdEnableRingBufferRPtrWriteBack
// TODO(benvanik): something?
}
SHIM_CALL VdEnableRingBufferRPtrWriteBack_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t ptr = SHIM_GET_ARG_32(0);
uint32_t block_size = SHIM_GET_ARG_32(1);
XELOGD(
"VdEnableRingBufferRPtrWriteBack(%.8X, %.8X)",
ptr, block_size);
xeVdEnableRingBufferRPtrWriteBack(ptr, block_size);
}
void xeVdGetSystemCommandBuffer(uint32_t* p0, uint32_t* p1) {
*p0 = 0xBEEF0000;
*p1 = 0xBEEF0001;
}
SHIM_CALL VdGetSystemCommandBuffer_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t p0_ptr = SHIM_GET_ARG_32(0);
uint32_t p1_ptr = SHIM_GET_ARG_32(1);
XELOGD(
"VdGetSystemCommandBuffer(%.8X, %.8X)",
p0_ptr,
p1_ptr);
uint32_t p0 = 0;
uint32_t p1 = 0;
xeVdGetSystemCommandBuffer(&p0, &p1);
SHIM_SET_MEM_32(p0_ptr, p0);
SHIM_SET_MEM_32(p1_ptr, p1);
}
void xeVdSetSystemCommandBufferGpuIdentifierAddress(uint32_t unk) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
GraphicsSystem* gs = state->emulator()->graphics_system();
if (!gs) {
return;
}
// r3 = 0x2B10(d3d?) + 8
}
SHIM_CALL VdSetSystemCommandBufferGpuIdentifierAddress_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t unk = SHIM_GET_ARG_32(0);
XELOGD(
"VdSetSystemCommandBufferGpuIdentifierAddress(%.8X)",
unk);
xeVdSetSystemCommandBufferGpuIdentifierAddress(unk);
}
// VdVerifyMEInitCommand
// r3
// r4 = 19
// no op?
// VdCallGraphicsNotificationRoutines
// r3 = 1
// r4 = ?
// callbacks get 0, r3, r4
SHIM_CALL VdIsHSIOTrainingSucceeded_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
XELOGD(
"VdIsHSIOTrainingSucceeded()");
// Not really sure what this should be - code does weird stuff here:
// (cntlzw r11, r3 / extrwi r11, r11, 1, 26)
SHIM_SET_RETURN(1);
}
SHIM_CALL VdPersistDisplay_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
XELOGD(
"VdPersistDisplay(?)");
// ?
SHIM_SET_RETURN(1);
}
SHIM_CALL VdRetrainEDRAMWorker_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t unk0 = SHIM_GET_ARG_32(0);
XELOGD(
"VdRetrainEDRAMWorker(%.8X)",
unk0);
SHIM_SET_RETURN(0);
}
SHIM_CALL VdRetrainEDRAM_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t unk0 = SHIM_GET_ARG_32(0);
uint32_t unk1 = SHIM_GET_ARG_32(1);
uint32_t unk2 = SHIM_GET_ARG_32(2);
uint32_t unk3 = SHIM_GET_ARG_32(3);
uint32_t unk4 = SHIM_GET_ARG_32(4);
uint32_t unk5 = SHIM_GET_ARG_32(5);
XELOGD(
"VdRetrainEDRAM(%.8X, %.8X, %.8X, %.8X, %.8X, %.8X)",
unk0, unk1, unk2, unk3, unk4, unk5);
SHIM_SET_RETURN(0);
}
SHIM_CALL VdSwap_shim(
xe_ppc_state_t* ppc_state, KernelState* state) {
uint32_t unk0 = SHIM_GET_ARG_32(0);
uint32_t unk1 = SHIM_GET_ARG_32(1);
uint32_t unk2 = SHIM_GET_ARG_32(2);
uint32_t unk3 = SHIM_GET_ARG_32(3);
uint32_t unk4 = SHIM_GET_ARG_32(4);
uint32_t unk5 = SHIM_GET_ARG_32(5);
uint32_t unk6 = SHIM_GET_ARG_32(6);
uint32_t unk7 = SHIM_GET_ARG_32(7);
XELOGD(
"VdSwap(%.8X, %.8X, %.8X, %.8X, %.8X, %.8X, %.8X, %.8X)",
unk0,
unk1,
unk2,
unk3,
unk4,
unk5,
unk6,
unk7);
KernelState* kernel_state = shared_kernel_state_;
XEASSERTNOTNULL(kernel_state);
GraphicsSystem* gs = kernel_state->emulator()->graphics_system();
if (!gs) {
return;
}
gs->set_swap_pending(true);
SHIM_SET_RETURN(0);
}
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
void xe::kernel::xboxkrnl::RegisterVideoExports(
ExportResolver* export_resolver, KernelState* state) {
SHIM_SET_MAPPING("xboxkrnl.exe", VdGetCurrentDisplayGamma, state);
SHIM_SET_MAPPING("xboxkrnl.exe", VdGetCurrentDisplayInformation, state);
SHIM_SET_MAPPING("xboxkrnl.exe", VdQueryVideoFlags, state);
SHIM_SET_MAPPING("xboxkrnl.exe", VdQueryVideoMode, state);
SHIM_SET_MAPPING("xboxkrnl.exe", VdInitializeEngines, state);
SHIM_SET_MAPPING("xboxkrnl.exe", VdSetGraphicsInterruptCallback, state);
SHIM_SET_MAPPING("xboxkrnl.exe", VdInitializeRingBuffer, state);
SHIM_SET_MAPPING("xboxkrnl.exe", VdEnableRingBufferRPtrWriteBack, state);
SHIM_SET_MAPPING("xboxkrnl.exe", VdGetSystemCommandBuffer, state);
SHIM_SET_MAPPING("xboxkrnl.exe",
VdSetSystemCommandBufferGpuIdentifierAddress, state);
SHIM_SET_MAPPING("xboxkrnl.exe", VdIsHSIOTrainingSucceeded, state);
SHIM_SET_MAPPING("xboxkrnl.exe", VdPersistDisplay, state);
SHIM_SET_MAPPING("xboxkrnl.exe", VdRetrainEDRAMWorker, state);
SHIM_SET_MAPPING("xboxkrnl.exe", VdRetrainEDRAM, state);
SHIM_SET_MAPPING("xboxkrnl.exe", VdSwap, state);
xe_memory_ref memory = state->memory();
uint8_t* mem = xe_memory_addr(memory);
// VdGlobalDevice (4b)
// Pointer to a global D3D device. Games only seem to set this, so we don't
// have to do anything. We may want to read it back later, though.
uint32_t pVdGlobalDevice = xe_memory_heap_alloc(memory, 0, 4, 0);
export_resolver->SetVariableMapping(
"xboxkrnl.exe", ordinals::VdGlobalDevice,
pVdGlobalDevice);
XESETUINT32BE(mem + pVdGlobalDevice, 0);
// VdGlobalXamDevice (4b)
// Pointer to the XAM D3D device, which we don't have.
uint32_t pVdGlobalXamDevice = xe_memory_heap_alloc(memory, 0, 4, 0);
export_resolver->SetVariableMapping(
"xboxkrnl.exe", ordinals::VdGlobalXamDevice,
pVdGlobalXamDevice);
XESETUINT32BE(mem + pVdGlobalXamDevice, 0);
// VdGpuClockInMHz (4b)
// GPU clock. Xenos is 500MHz. Hope nothing is relying on this timing...
uint32_t pVdGpuClockInMHz = xe_memory_heap_alloc(memory, 0, 4, 0);
export_resolver->SetVariableMapping(
"xboxkrnl.exe", ordinals::VdGpuClockInMHz,
pVdGpuClockInMHz);
XESETUINT32BE(mem + pVdGpuClockInMHz, 500);
// VdHSIOCalibrationLock (28b)
// CriticalSection.
uint32_t pVdHSIOCalibrationLock = xe_memory_heap_alloc(memory, 0, 28, 0);
export_resolver->SetVariableMapping(
"xboxkrnl.exe", ordinals::VdHSIOCalibrationLock,
pVdHSIOCalibrationLock);
xeRtlInitializeCriticalSectionAndSpinCount(pVdHSIOCalibrationLock, 10000);
}

View File

@@ -0,0 +1,57 @@
/**
******************************************************************************
* 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_VIDEO_H_
#define XENIA_KERNEL_XBOXKRNL_VIDEO_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/xbox.h>
namespace xe {
namespace kernel {
namespace xboxkrnl {
// http://ffplay360.googlecode.com/svn/trunk/Common/XTLOnPC.h
#pragma pack(push, 1)
typedef struct {
uint32_t display_width;
uint32_t display_height;
uint32_t is_interlaced;
uint32_t is_widescreen;
uint32_t is_hi_def;
float refresh_rate;
uint32_t video_standard;
uint32_t unknown_0x8a;
uint32_t unknown_0x01;
uint32_t reserved[3];
}
X_VIDEO_MODE;
#pragma pack(pop)
XEASSERTSTRUCTSIZE(X_VIDEO_MODE, 48);
void xeVdGetCurrentDisplayGamma(uint32_t* arg0, float* arg1);
uint32_t xeVdQueryVideoFlags();
void xeVdQueryVideoMode(X_VIDEO_MODE *video_mode, bool swap);
void xeVdInitializeEngines(uint32_t unk0, uint32_t callback, uint32_t unk1,
uint32_t unk2_ptr, uint32_t unk3_ptr);
void xeVdSetGraphicsInterruptCallback(uint32_t callback, uint32_t user_data);
void xeVdEnableRingBufferRPtrWriteBack(uint32_t ptr, uint32_t block_size);
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_VIDEO_H_

View File

@@ -0,0 +1,178 @@
/**
******************************************************************************
* 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/xboxkrnl/xobject.h>
#include <xenia/kernel/xboxkrnl/xboxkrnl_private.h>
#include <xenia/kernel/xboxkrnl/objects/xevent.h>
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl;
XObject::XObject(KernelState* kernel_state, Type type) :
kernel_state_(kernel_state),
handle_ref_count_(0),
pointer_ref_count_(1),
type_(type), handle_(X_INVALID_HANDLE_VALUE) {
kernel_state->object_table()->AddHandle(this, &handle_);
}
XObject::~XObject() {
XEASSERTZERO(handle_ref_count_);
XEASSERTZERO(pointer_ref_count_);
}
xe_memory_ref XObject::memory() {
return kernel_state_->memory();
}
XObject::Type XObject::type() {
return type_;
}
X_HANDLE XObject::handle() const {
return handle_;
}
void XObject::RetainHandle() {
xe_atomic_inc_32(&handle_ref_count_);
}
bool XObject::ReleaseHandle() {
if (!xe_atomic_dec_32(&handle_ref_count_)) {
return true;
}
return false;
}
void XObject::Retain() {
xe_atomic_inc_32(&pointer_ref_count_);
}
void XObject::Release() {
if (!xe_atomic_dec_32(&pointer_ref_count_)) {
XEASSERT(pointer_ref_count_ >= handle_ref_count_);
delete this;
}
}
X_STATUS XObject::Delete() {
return shared_kernel_state_->object_table()->RemoveHandle(handle_);
}
X_STATUS XObject::Wait(uint32_t wait_reason, uint32_t processor_mode,
uint32_t alertable, uint64_t* opt_timeout) {
return X_STATUS_SUCCESS;
}
void XObject::LockType() {
xe_mutex_lock(shared_kernel_state_->object_mutex_);
}
void XObject::UnlockType() {
xe_mutex_unlock(shared_kernel_state_->object_mutex_);
}
void XObject::SetNativePointer(uint32_t native_ptr) {
XObject::LockType();
DISPATCH_HEADER* header_be =
(DISPATCH_HEADER*)xe_memory_addr(kernel_state_->memory(), native_ptr);
DISPATCH_HEADER header;
header.type_flags = XESWAP32(header_be->type_flags);
header.signal_state = XESWAP32(header_be->signal_state);
header.wait_list_flink = XESWAP32(header_be->wait_list_flink);
header.wait_list_blink = XESWAP32(header_be->wait_list_blink);
XEASSERT(!(header.wait_list_blink & 0x1));
// Stash pointer in struct.
uint64_t object_ptr = reinterpret_cast<uint64_t>(this);
object_ptr |= 0x1;
header_be->wait_list_flink = XESWAP32((uint32_t)(object_ptr >> 32));
header_be->wait_list_blink = XESWAP32((uint32_t)(object_ptr & 0xFFFFFFFF));
XObject::UnlockType();
}
XObject* XObject::GetObject(KernelState* kernel_state, void* native_ptr) {
// Unfortunately the XDK seems to inline some KeInitialize calls, meaning
// we never see it and just randomly start getting passed events/timers/etc.
// Luckily it seems like all other calls (Set/Reset/Wait/etc) are used and
// we don't have to worry about PPC code poking the struct. Because of that,
// we init on first use, store our pointer in the struct, and dereference it
// each time.
// We identify this by checking the low bit of wait_list_blink - if it's 1,
// we have already put our pointer in there.
XObject::LockType();
DISPATCH_HEADER* header_be = (DISPATCH_HEADER*)native_ptr;
DISPATCH_HEADER header;
header.type_flags = XESWAP32(header_be->type_flags);
header.signal_state = XESWAP32(header_be->signal_state);
header.wait_list_flink = XESWAP32(header_be->wait_list_flink);
header.wait_list_blink = XESWAP32(header_be->wait_list_blink);
if (header.wait_list_blink & 0x1) {
// Already initialized.
uint64_t object_ptr =
((uint64_t)header.wait_list_flink << 32) |
((header.wait_list_blink) & ~0x1);
XObject* object = reinterpret_cast<XObject*>(object_ptr);
// TODO(benvanik): assert nothing has been changed in the struct.
XObject::UnlockType();
return object;
} else {
// First use, create new.
// http://www.nirsoft.net/kernel_struct/vista/KOBJECTS.html
XObject* object = NULL;
switch (header.type_flags & 0xFF) {
case 0: // EventNotificationObject
case 1: // EventSynchronizationObject
{
XEvent* ev = new XEvent(kernel_state);
ev->InitializeNative(native_ptr, header);
object = ev;
}
break;
case 2: // MutantObject
case 3: // ProcessObject
case 4: // QueueObject
case 5: // SemaphoreObject
case 6: // ThreadObject
case 7: // GateObject
case 8: // TimerNotificationObject
case 9: // TimerSynchronizationObject
case 18: // ApcObject
case 19: // DpcObject
case 20: // DeviceQueueObject
case 21: // EventPairObject
case 22: // InterruptObject
case 23: // ProfileObject
case 24: // ThreadedDpcObject
default:
XEASSERTALWAYS();
XObject::UnlockType();
return NULL;
}
// Stash pointer in struct.
uint64_t object_ptr = reinterpret_cast<uint64_t>(object);
object_ptr |= 0x1;
header_be->wait_list_flink = XESWAP32((uint32_t)(object_ptr >> 32));
header_be->wait_list_blink = XESWAP32((uint32_t)(object_ptr & 0xFFFFFFFF));
XObject::UnlockType();
return object;
}
}

View File

@@ -0,0 +1,86 @@
/**
******************************************************************************
* 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_XOBJECT_H_
#define XENIA_KERNEL_XBOXKRNL_XOBJECT_H_
#include <xenia/kernel/xboxkrnl/kernel_state.h>
#include <xenia/xbox.h>
namespace xe {
namespace kernel {
namespace xboxkrnl {
// http://www.nirsoft.net/kernel_struct/vista/DISPATCHER_HEADER.html
typedef struct {
uint32_t type_flags;
uint32_t signal_state;
uint32_t wait_list_flink;
uint32_t wait_list_blink;
} DISPATCH_HEADER;
class XObject {
public:
enum Type {
kTypeModule = 0x00000001,
kTypeThread = 0x00000002,
kTypeEvent = 0x00000003,
kTypeFile = 0x00000004,
};
XObject(KernelState* kernel_state, Type type);
virtual ~XObject();
Emulator* emulator() const { return kernel_state_->emulator_; }
KernelState* kernel_state() const { return kernel_state_; }
Type type();
X_HANDLE handle() const;
void RetainHandle();
bool ReleaseHandle();
void Retain();
void Release();
X_STATUS Delete();
// Reference()
// Dereference()
virtual X_STATUS Wait(uint32_t wait_reason, uint32_t processor_mode,
uint32_t alertable, uint64_t* opt_timeout);
static void LockType();
static void UnlockType();
static XObject* GetObject(KernelState* kernel_state, void* native_ptr);
protected:
xe_memory_ref memory(); // unretained
void SetNativePointer(uint32_t native_ptr);
KernelState* kernel_state_;
private:
volatile int32_t handle_ref_count_;
volatile int32_t pointer_ref_count_;
Type type_;
X_HANDLE handle_;
};
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_XOBJECT_H_