Merge branch 'master' into d3d12
This commit is contained in:
commit
af6dd50370
|
@ -0,0 +1,183 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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/cpu/lzx.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <climits>
|
||||||
|
|
||||||
|
#include "xenia/base/byte_order.h"
|
||||||
|
#include "xenia/base/logging.h"
|
||||||
|
#include "xenia/base/math.h"
|
||||||
|
#include "xenia/base/memory.h"
|
||||||
|
#include "xenia/kernel/util/xex2_info.h"
|
||||||
|
|
||||||
|
#include "third_party/mspack/lzx.h"
|
||||||
|
#include "third_party/mspack/mspack.h"
|
||||||
|
|
||||||
|
typedef struct mspack_memory_file_t {
|
||||||
|
struct mspack_system sys;
|
||||||
|
void* buffer;
|
||||||
|
off_t buffer_size;
|
||||||
|
off_t offset;
|
||||||
|
} mspack_memory_file;
|
||||||
|
mspack_memory_file* mspack_memory_open(struct mspack_system* sys, void* buffer,
|
||||||
|
const size_t buffer_size) {
|
||||||
|
assert_true(buffer_size < INT_MAX);
|
||||||
|
if (buffer_size >= INT_MAX) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
mspack_memory_file* memfile =
|
||||||
|
(mspack_memory_file*)calloc(1, sizeof(mspack_memory_file));
|
||||||
|
if (!memfile) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memfile->buffer = buffer;
|
||||||
|
memfile->buffer_size = (off_t)buffer_size;
|
||||||
|
memfile->offset = 0;
|
||||||
|
return memfile;
|
||||||
|
}
|
||||||
|
void mspack_memory_close(mspack_memory_file* file) {
|
||||||
|
mspack_memory_file* memfile = (mspack_memory_file*)file;
|
||||||
|
free(memfile);
|
||||||
|
}
|
||||||
|
int mspack_memory_read(struct mspack_file* file, void* buffer, int chars) {
|
||||||
|
mspack_memory_file* memfile = (mspack_memory_file*)file;
|
||||||
|
const off_t remaining = memfile->buffer_size - memfile->offset;
|
||||||
|
const off_t total = std::min(static_cast<off_t>(chars), remaining);
|
||||||
|
std::memcpy(buffer, (uint8_t*)memfile->buffer + memfile->offset, total);
|
||||||
|
memfile->offset += total;
|
||||||
|
return (int)total;
|
||||||
|
}
|
||||||
|
int mspack_memory_write(struct mspack_file* file, void* buffer, int chars) {
|
||||||
|
mspack_memory_file* memfile = (mspack_memory_file*)file;
|
||||||
|
const off_t remaining = memfile->buffer_size - memfile->offset;
|
||||||
|
const off_t total = std::min(static_cast<off_t>(chars), remaining);
|
||||||
|
std::memcpy((uint8_t*)memfile->buffer + memfile->offset, buffer, total);
|
||||||
|
memfile->offset += total;
|
||||||
|
return (int)total;
|
||||||
|
}
|
||||||
|
void* mspack_memory_alloc(struct mspack_system* sys, size_t chars) {
|
||||||
|
return std::calloc(chars, 1);
|
||||||
|
}
|
||||||
|
void mspack_memory_free(void* ptr) { free(ptr); }
|
||||||
|
void mspack_memory_copy(void* src, void* dest, size_t chars) {
|
||||||
|
std::memcpy(dest, src, chars);
|
||||||
|
}
|
||||||
|
struct mspack_system* mspack_memory_sys_create() {
|
||||||
|
struct mspack_system* sys =
|
||||||
|
(struct mspack_system*)std::calloc(1, sizeof(struct mspack_system));
|
||||||
|
if (!sys) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
sys->read = mspack_memory_read;
|
||||||
|
sys->write = mspack_memory_write;
|
||||||
|
sys->alloc = mspack_memory_alloc;
|
||||||
|
sys->free = mspack_memory_free;
|
||||||
|
sys->copy = mspack_memory_copy;
|
||||||
|
return sys;
|
||||||
|
}
|
||||||
|
void mspack_memory_sys_destroy(struct mspack_system* sys) { free(sys); }
|
||||||
|
|
||||||
|
int lzx_decompress(const void* lzx_data, size_t lzx_len, void* dest,
|
||||||
|
size_t dest_len, uint32_t window_size, void* window_data,
|
||||||
|
size_t window_data_len) {
|
||||||
|
uint32_t window_bits = 0;
|
||||||
|
uint32_t temp_sz = window_size;
|
||||||
|
for (size_t m = 0; m < 32; m++, window_bits++) {
|
||||||
|
temp_sz >>= 1;
|
||||||
|
if (temp_sz == 0x00000000) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int result_code = 1;
|
||||||
|
|
||||||
|
mspack_system* sys = mspack_memory_sys_create();
|
||||||
|
mspack_memory_file* lzxsrc =
|
||||||
|
mspack_memory_open(sys, (void*)lzx_data, lzx_len);
|
||||||
|
mspack_memory_file* lzxdst = mspack_memory_open(sys, dest, dest_len);
|
||||||
|
lzxd_stream* lzxd =
|
||||||
|
lzxd_init(sys, (struct mspack_file*)lzxsrc, (struct mspack_file*)lzxdst,
|
||||||
|
window_bits, 0, 0x8000, (off_t)dest_len, 0);
|
||||||
|
|
||||||
|
if (lzxd) {
|
||||||
|
if (window_data) {
|
||||||
|
// zero the window and then copy window_data to the end of it
|
||||||
|
std::memset(lzxd->window, 0, window_data_len);
|
||||||
|
std::memcpy(lzxd->window + (window_size - window_data_len), window_data,
|
||||||
|
window_data_len);
|
||||||
|
lzxd->ref_data_size = (uint32_t)window_data_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
result_code = lzxd_decompress(lzxd, (off_t)dest_len);
|
||||||
|
|
||||||
|
lzxd_free(lzxd);
|
||||||
|
lzxd = NULL;
|
||||||
|
}
|
||||||
|
if (lzxsrc) {
|
||||||
|
mspack_memory_close(lzxsrc);
|
||||||
|
lzxsrc = NULL;
|
||||||
|
}
|
||||||
|
if (lzxdst) {
|
||||||
|
mspack_memory_close(lzxdst);
|
||||||
|
lzxdst = NULL;
|
||||||
|
}
|
||||||
|
if (sys) {
|
||||||
|
mspack_memory_sys_destroy(sys);
|
||||||
|
sys = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lzxdelta_apply_patch(xe::xex2_delta_patch* patch, size_t patch_len,
|
||||||
|
uint32_t window_size, void* dest) {
|
||||||
|
void* patch_end = (char*)patch + patch_len;
|
||||||
|
auto* cur_patch = patch;
|
||||||
|
|
||||||
|
while (patch_end > cur_patch) {
|
||||||
|
int patch_sz = -4; // 0 byte patches need us to remove 4 byte from next
|
||||||
|
// patch addr because of patch_data field
|
||||||
|
if (cur_patch->compressed_len == 0 && cur_patch->uncompressed_len == 0 &&
|
||||||
|
cur_patch->new_addr == 0 && cur_patch->old_addr == 0)
|
||||||
|
break;
|
||||||
|
switch (cur_patch->compressed_len) {
|
||||||
|
case 0: // fill with 0
|
||||||
|
std::memset((char*)dest + cur_patch->new_addr, 0,
|
||||||
|
cur_patch->uncompressed_len);
|
||||||
|
break;
|
||||||
|
case 1: // copy from old -> new
|
||||||
|
std::memcpy((char*)dest + cur_patch->new_addr,
|
||||||
|
(char*)dest + cur_patch->old_addr,
|
||||||
|
cur_patch->uncompressed_len);
|
||||||
|
break;
|
||||||
|
default: // delta patch
|
||||||
|
patch_sz =
|
||||||
|
cur_patch->compressed_len - 4; // -4 because of patch_data field
|
||||||
|
|
||||||
|
int result = lzx_decompress(
|
||||||
|
cur_patch->patch_data, cur_patch->compressed_len,
|
||||||
|
(char*)dest + cur_patch->new_addr, cur_patch->uncompressed_len,
|
||||||
|
window_size, (char*)dest + cur_patch->old_addr,
|
||||||
|
cur_patch->uncompressed_len);
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_patch++;
|
||||||
|
cur_patch = (xe::xex2_delta_patch*)((char*)cur_patch +
|
||||||
|
patch_sz); // TODO: make this less ugly
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -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_CPU_LZX_H_
|
||||||
|
#define XENIA_CPU_LZX_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "xenia/cpu/module.h"
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
struct xex2_delta_patch;
|
||||||
|
} // namespace xe
|
||||||
|
|
||||||
|
int lzx_decompress(const void* lzx_data, size_t lzx_len, void* dest,
|
||||||
|
size_t dest_len, uint32_t window_size, void* window_data,
|
||||||
|
size_t window_data_len);
|
||||||
|
|
||||||
|
int lzxdelta_apply_patch(xe::xex2_delta_patch* patch, size_t patch_len,
|
||||||
|
uint32_t window_size, void* dest);
|
||||||
|
|
||||||
|
#endif // XENIA_CPU_LZX_H_
|
|
@ -17,6 +17,7 @@
|
||||||
#include "xenia/base/memory.h"
|
#include "xenia/base/memory.h"
|
||||||
#include "xenia/cpu/cpu_flags.h"
|
#include "xenia/cpu/cpu_flags.h"
|
||||||
#include "xenia/cpu/export_resolver.h"
|
#include "xenia/cpu/export_resolver.h"
|
||||||
|
#include "xenia/cpu/lzx.h"
|
||||||
#include "xenia/cpu/processor.h"
|
#include "xenia/cpu/processor.h"
|
||||||
#include "xenia/kernel/kernel_state.h"
|
#include "xenia/kernel/kernel_state.h"
|
||||||
#include "xenia/kernel/xmodule.h"
|
#include "xenia/kernel/xmodule.h"
|
||||||
|
@ -24,8 +25,6 @@
|
||||||
#include "third_party/crypto/TinySHA1.hpp"
|
#include "third_party/crypto/TinySHA1.hpp"
|
||||||
#include "third_party/crypto/rijndael-alg-fst.c"
|
#include "third_party/crypto/rijndael-alg-fst.c"
|
||||||
#include "third_party/crypto/rijndael-alg-fst.h"
|
#include "third_party/crypto/rijndael-alg-fst.h"
|
||||||
#include "third_party/mspack/lzx.h"
|
|
||||||
#include "third_party/mspack/mspack.h"
|
|
||||||
#include "third_party/pe/pe_image.h"
|
#include "third_party/pe/pe_image.h"
|
||||||
|
|
||||||
static const uint8_t xe_xex2_retail_key[16] = {
|
static const uint8_t xe_xex2_retail_key[16] = {
|
||||||
|
@ -35,165 +34,6 @@ static const uint8_t xe_xex2_devkit_key[16] = {
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
|
||||||
typedef struct mspack_memory_file_t {
|
|
||||||
struct mspack_system sys;
|
|
||||||
void* buffer;
|
|
||||||
off_t buffer_size;
|
|
||||||
off_t offset;
|
|
||||||
} mspack_memory_file;
|
|
||||||
mspack_memory_file* mspack_memory_open(struct mspack_system* sys, void* buffer,
|
|
||||||
const size_t buffer_size) {
|
|
||||||
assert_true(buffer_size < INT_MAX);
|
|
||||||
if (buffer_size >= INT_MAX) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
mspack_memory_file* memfile =
|
|
||||||
(mspack_memory_file*)calloc(1, sizeof(mspack_memory_file));
|
|
||||||
if (!memfile) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
memfile->buffer = buffer;
|
|
||||||
memfile->buffer_size = (off_t)buffer_size;
|
|
||||||
memfile->offset = 0;
|
|
||||||
return memfile;
|
|
||||||
}
|
|
||||||
void mspack_memory_close(mspack_memory_file* file) {
|
|
||||||
mspack_memory_file* memfile = (mspack_memory_file*)file;
|
|
||||||
free(memfile);
|
|
||||||
}
|
|
||||||
int mspack_memory_read(struct mspack_file* file, void* buffer, int chars) {
|
|
||||||
mspack_memory_file* memfile = (mspack_memory_file*)file;
|
|
||||||
const off_t remaining = memfile->buffer_size - memfile->offset;
|
|
||||||
const off_t total = std::min(static_cast<off_t>(chars), remaining);
|
|
||||||
memcpy(buffer, (uint8_t*)memfile->buffer + memfile->offset, total);
|
|
||||||
memfile->offset += total;
|
|
||||||
return (int)total;
|
|
||||||
}
|
|
||||||
int mspack_memory_write(struct mspack_file* file, void* buffer, int chars) {
|
|
||||||
mspack_memory_file* memfile = (mspack_memory_file*)file;
|
|
||||||
const off_t remaining = memfile->buffer_size - memfile->offset;
|
|
||||||
const off_t total = std::min(static_cast<off_t>(chars), remaining);
|
|
||||||
memcpy((uint8_t*)memfile->buffer + memfile->offset, buffer, total);
|
|
||||||
memfile->offset += total;
|
|
||||||
return (int)total;
|
|
||||||
}
|
|
||||||
void* mspack_memory_alloc(struct mspack_system* sys, size_t chars) {
|
|
||||||
return calloc(chars, 1);
|
|
||||||
}
|
|
||||||
void mspack_memory_free(void* ptr) { free(ptr); }
|
|
||||||
void mspack_memory_copy(void* src, void* dest, size_t chars) {
|
|
||||||
memcpy(dest, src, chars);
|
|
||||||
}
|
|
||||||
struct mspack_system* mspack_memory_sys_create() {
|
|
||||||
struct mspack_system* sys =
|
|
||||||
(struct mspack_system*)calloc(1, sizeof(struct mspack_system));
|
|
||||||
if (!sys) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
sys->read = mspack_memory_read;
|
|
||||||
sys->write = mspack_memory_write;
|
|
||||||
sys->alloc = mspack_memory_alloc;
|
|
||||||
sys->free = mspack_memory_free;
|
|
||||||
sys->copy = mspack_memory_copy;
|
|
||||||
return sys;
|
|
||||||
}
|
|
||||||
void mspack_memory_sys_destroy(struct mspack_system* sys) { free(sys); }
|
|
||||||
|
|
||||||
int lzx_decompress(const void* lzx_data, size_t lzx_len, void* dest,
|
|
||||||
size_t dest_len, uint32_t window_size, void* window_data,
|
|
||||||
size_t window_data_len) {
|
|
||||||
uint32_t window_bits = 0;
|
|
||||||
uint32_t temp_sz = window_size;
|
|
||||||
for (size_t m = 0; m < 32; m++, window_bits++) {
|
|
||||||
temp_sz >>= 1;
|
|
||||||
if (temp_sz == 0x00000000) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int result_code = 1;
|
|
||||||
|
|
||||||
mspack_system* sys = mspack_memory_sys_create();
|
|
||||||
mspack_memory_file* lzxsrc =
|
|
||||||
mspack_memory_open(sys, (void*)lzx_data, lzx_len);
|
|
||||||
mspack_memory_file* lzxdst = mspack_memory_open(sys, dest, dest_len);
|
|
||||||
lzxd_stream* lzxd =
|
|
||||||
lzxd_init(sys, (struct mspack_file*)lzxsrc, (struct mspack_file*)lzxdst,
|
|
||||||
window_bits, 0, 0x8000, (off_t)dest_len, 0);
|
|
||||||
|
|
||||||
if (lzxd) {
|
|
||||||
if (window_data) {
|
|
||||||
// zero the window and then copy window_data to the end of it
|
|
||||||
memset(lzxd->window, 0, window_data_len);
|
|
||||||
memcpy(lzxd->window + (window_size - window_data_len), window_data,
|
|
||||||
window_data_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
result_code = lzxd_decompress(lzxd, (off_t)dest_len);
|
|
||||||
|
|
||||||
lzxd_free(lzxd);
|
|
||||||
lzxd = NULL;
|
|
||||||
}
|
|
||||||
if (lzxsrc) {
|
|
||||||
mspack_memory_close(lzxsrc);
|
|
||||||
lzxsrc = NULL;
|
|
||||||
}
|
|
||||||
if (lzxdst) {
|
|
||||||
mspack_memory_close(lzxdst);
|
|
||||||
lzxdst = NULL;
|
|
||||||
}
|
|
||||||
if (sys) {
|
|
||||||
mspack_memory_sys_destroy(sys);
|
|
||||||
sys = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result_code;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lzxdelta_apply_patch(xe::xex2_delta_patch* patch, size_t patch_len,
|
|
||||||
uint32_t window_size, void* dest) {
|
|
||||||
void* patch_end = (char*)patch + patch_len;
|
|
||||||
auto* cur_patch = patch;
|
|
||||||
|
|
||||||
while (patch_end > cur_patch) {
|
|
||||||
int patch_sz = -4; // 0 byte patches need us to remove 4 byte from next
|
|
||||||
// patch addr because of patch_data field
|
|
||||||
if (cur_patch->compressed_len == 0 && cur_patch->uncompressed_len == 0 &&
|
|
||||||
cur_patch->new_addr == 0 && cur_patch->old_addr == 0)
|
|
||||||
break;
|
|
||||||
switch (cur_patch->compressed_len) {
|
|
||||||
case 0: // fill with 0
|
|
||||||
memset((char*)dest + cur_patch->new_addr, 0,
|
|
||||||
cur_patch->uncompressed_len);
|
|
||||||
break;
|
|
||||||
case 1: // copy from old -> new
|
|
||||||
memcpy((char*)dest + cur_patch->new_addr,
|
|
||||||
(char*)dest + cur_patch->old_addr, cur_patch->uncompressed_len);
|
|
||||||
break;
|
|
||||||
default: // delta patch
|
|
||||||
patch_sz =
|
|
||||||
cur_patch->compressed_len - 4; // -4 because of patch_data field
|
|
||||||
|
|
||||||
int result = lzx_decompress(
|
|
||||||
cur_patch->patch_data, cur_patch->compressed_len,
|
|
||||||
(char*)dest + cur_patch->new_addr, cur_patch->uncompressed_len,
|
|
||||||
window_size, (char*)dest + cur_patch->old_addr,
|
|
||||||
cur_patch->uncompressed_len);
|
|
||||||
|
|
||||||
if (result) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_patch++;
|
|
||||||
cur_patch = (xe::xex2_delta_patch*)((char*)cur_patch +
|
|
||||||
patch_sz); // TODO: make this less ugly
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void aes_decrypt_buffer(const uint8_t* session_key, const uint8_t* input_buffer,
|
void aes_decrypt_buffer(const uint8_t* session_key, const uint8_t* input_buffer,
|
||||||
const size_t input_size, uint8_t* output_buffer,
|
const size_t input_size, uint8_t* output_buffer,
|
||||||
const size_t output_size) {
|
const size_t output_size) {
|
||||||
|
@ -1144,9 +984,8 @@ bool XexModule::LoadContinue() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto library_data = reinterpret_cast<uint8_t*>(opt_import_libraries) +
|
auto library_data = reinterpret_cast<uint8_t*>(opt_import_libraries);
|
||||||
opt_import_libraries->string_table.size + 12;
|
uint32_t library_offset = opt_import_libraries->string_table.size + 12;
|
||||||
uint32_t library_offset = 0;
|
|
||||||
while (library_offset < opt_import_libraries->size) {
|
while (library_offset < opt_import_libraries->size) {
|
||||||
auto library =
|
auto library =
|
||||||
reinterpret_cast<xex2_import_library*>(library_data + library_offset);
|
reinterpret_cast<xex2_import_library*>(library_data + library_offset);
|
||||||
|
|
|
@ -564,6 +564,10 @@ using xe::cpu::ExportTag;
|
||||||
DECLARE_EXPORT(xboxkrnl, name, category, \
|
DECLARE_EXPORT(xboxkrnl, name, category, \
|
||||||
xe::cpu::ExportTag::tag1 | xe::cpu::ExportTag::tag2 | \
|
xe::cpu::ExportTag::tag1 | xe::cpu::ExportTag::tag2 | \
|
||||||
xe::cpu::ExportTag::tag3)
|
xe::cpu::ExportTag::tag3)
|
||||||
|
#define DECLARE_XBOXKRNL_EXPORT4(name, category, tag1, tag2, tag3, tag4) \
|
||||||
|
DECLARE_EXPORT(xboxkrnl, name, category, \
|
||||||
|
xe::cpu::ExportTag::tag1 | xe::cpu::ExportTag::tag2 | \
|
||||||
|
xe::cpu::ExportTag::tag3 | xe::cpu::ExportTag::tag4)
|
||||||
|
|
||||||
} // namespace kernel
|
} // namespace kernel
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
|
@ -28,28 +28,30 @@ namespace xam {
|
||||||
constexpr uint32_t X_LANGUAGE_ENGLISH = 1;
|
constexpr uint32_t X_LANGUAGE_ENGLISH = 1;
|
||||||
constexpr uint32_t X_LANGUAGE_JAPANESE = 2;
|
constexpr uint32_t X_LANGUAGE_JAPANESE = 2;
|
||||||
|
|
||||||
|
// Empty stub schema binary.
|
||||||
|
uint8_t schema_bin[] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00,
|
||||||
|
0x00, 0x2C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x2C, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
|
||||||
|
};
|
||||||
|
|
||||||
dword_result_t XamGetOnlineSchema() {
|
dword_result_t XamGetOnlineSchema() {
|
||||||
static uint32_t schema_guest = 0;
|
static uint32_t schema_guest = 0;
|
||||||
static uint32_t schema_ptr_guest = 0;
|
|
||||||
|
|
||||||
if (!schema_guest) {
|
if (!schema_guest) {
|
||||||
// create a dummy schema, 8 bytes of 0 seems to work fine
|
schema_guest =
|
||||||
// (with another 8 bytes for schema ptr/schema size)
|
kernel_state()->memory()->SystemHeapAlloc(8 + sizeof(schema_bin));
|
||||||
schema_guest = kernel_state()->memory()->SystemHeapAlloc(16);
|
|
||||||
schema_ptr_guest = schema_guest + 8;
|
|
||||||
|
|
||||||
auto schema = kernel_state()->memory()->TranslateVirtual(schema_guest);
|
auto schema = kernel_state()->memory()->TranslateVirtual(schema_guest);
|
||||||
memset(schema, 0, 16);
|
std::memcpy(schema + 8, schema_bin, sizeof(schema_bin));
|
||||||
|
xe::store_and_swap<uint32_t>(schema + 0, schema_guest + 8);
|
||||||
// store schema ptr + size
|
xe::store_and_swap<uint32_t>(schema + 4, sizeof(schema_bin));
|
||||||
xe::store_and_swap<uint32_t>(schema + 0x8, schema_guest);
|
|
||||||
xe::store_and_swap<uint32_t>(schema + 0xC, 0x8);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// return pointer to the schema ptr/schema size struct
|
// return pointer to the schema ptr/schema size struct
|
||||||
return schema_ptr_guest;
|
return schema_guest;
|
||||||
}
|
}
|
||||||
DECLARE_XAM_EXPORT2(XamGetOnlineSchema, kNone, kImplemented, kSketchy);
|
DECLARE_XAM_EXPORT1(XamGetOnlineSchema, kNone, kImplemented);
|
||||||
|
|
||||||
void XamFormatDateString(dword_t unk, qword_t filetime, lpvoid_t buffer,
|
void XamFormatDateString(dword_t unk, qword_t filetime, lpvoid_t buffer,
|
||||||
dword_t buffer_length) {
|
dword_t buffer_length) {
|
||||||
|
|
|
@ -373,8 +373,7 @@ void KeInitializeEvent(pointer_t<X_KEVENT> event_ptr, dword_t event_type,
|
||||||
}
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT1(KeInitializeEvent, kThreading, kImplemented);
|
DECLARE_XBOXKRNL_EXPORT1(KeInitializeEvent, kThreading, kImplemented);
|
||||||
|
|
||||||
dword_result_t KeSetEvent(pointer_t<X_KEVENT> event_ptr, dword_t increment,
|
uint32_t keSetEvent(X_KEVENT* event_ptr, uint32_t increment, uint32_t wait) {
|
||||||
dword_t wait) {
|
|
||||||
auto ev = XObject::GetNativeObject<XEvent>(kernel_state(), event_ptr);
|
auto ev = XObject::GetNativeObject<XEvent>(kernel_state(), event_ptr);
|
||||||
if (!ev) {
|
if (!ev) {
|
||||||
assert_always();
|
assert_always();
|
||||||
|
@ -383,6 +382,11 @@ dword_result_t KeSetEvent(pointer_t<X_KEVENT> event_ptr, dword_t increment,
|
||||||
|
|
||||||
return ev->Set(increment, !!wait);
|
return ev->Set(increment, !!wait);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dword_result_t KeSetEvent(pointer_t<X_KEVENT> event_ptr, dword_t increment,
|
||||||
|
dword_t wait) {
|
||||||
|
return keSetEvent(event_ptr, increment, wait);
|
||||||
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT2(KeSetEvent, kThreading, kImplemented, kHighFrequency);
|
DECLARE_XBOXKRNL_EXPORT2(KeSetEvent, kThreading, kImplemented, kHighFrequency);
|
||||||
|
|
||||||
dword_result_t KePulseEvent(pointer_t<X_KEVENT> event_ptr, dword_t increment,
|
dword_result_t KePulseEvent(pointer_t<X_KEVENT> event_ptr, dword_t increment,
|
||||||
|
@ -508,9 +512,8 @@ void KeInitializeSemaphore(pointer_t<X_KSEMAPHORE> semaphore_ptr, dword_t count,
|
||||||
}
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT1(KeInitializeSemaphore, kThreading, kImplemented);
|
DECLARE_XBOXKRNL_EXPORT1(KeInitializeSemaphore, kThreading, kImplemented);
|
||||||
|
|
||||||
dword_result_t KeReleaseSemaphore(pointer_t<X_KSEMAPHORE> semaphore_ptr,
|
uint32_t keReleaseSemaphore(X_KSEMAPHORE* semaphore_ptr, uint32_t increment,
|
||||||
dword_t increment, dword_t adjustment,
|
uint32_t adjustment, uint32_t wait) {
|
||||||
dword_t wait) {
|
|
||||||
auto sem =
|
auto sem =
|
||||||
XObject::GetNativeObject<XSemaphore>(kernel_state(), semaphore_ptr);
|
XObject::GetNativeObject<XSemaphore>(kernel_state(), semaphore_ptr);
|
||||||
if (!sem) {
|
if (!sem) {
|
||||||
|
@ -523,6 +526,12 @@ dword_result_t KeReleaseSemaphore(pointer_t<X_KSEMAPHORE> semaphore_ptr,
|
||||||
|
|
||||||
return sem->ReleaseSemaphore(adjustment);
|
return sem->ReleaseSemaphore(adjustment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dword_result_t KeReleaseSemaphore(pointer_t<X_KSEMAPHORE> semaphore_ptr,
|
||||||
|
dword_t increment, dword_t adjustment,
|
||||||
|
dword_t wait) {
|
||||||
|
return keReleaseSemaphore(semaphore_ptr, increment, adjustment, wait);
|
||||||
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT1(KeReleaseSemaphore, kThreading, kImplemented);
|
DECLARE_XBOXKRNL_EXPORT1(KeReleaseSemaphore, kThreading, kImplemented);
|
||||||
|
|
||||||
dword_result_t NtCreateSemaphore(lpdword_t handle_ptr,
|
dword_result_t NtCreateSemaphore(lpdword_t handle_ptr,
|
||||||
|
@ -719,9 +728,9 @@ dword_result_t NtCancelTimer(dword_t timer_handle,
|
||||||
}
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT1(NtCancelTimer, kThreading, kImplemented);
|
DECLARE_XBOXKRNL_EXPORT1(NtCancelTimer, kThreading, kImplemented);
|
||||||
|
|
||||||
dword_result_t KeWaitForSingleObject(lpvoid_t object_ptr, dword_t wait_reason,
|
uint32_t keWaitForSingleObject(void* object_ptr, uint32_t wait_reason,
|
||||||
dword_t processor_mode, dword_t alertable,
|
uint32_t processor_mode, uint32_t alertable,
|
||||||
lpqword_t timeout_ptr) {
|
uint64_t* timeout) {
|
||||||
auto object = XObject::GetNativeObject<XObject>(kernel_state(), object_ptr);
|
auto object = XObject::GetNativeObject<XObject>(kernel_state(), object_ptr);
|
||||||
|
|
||||||
if (!object) {
|
if (!object) {
|
||||||
|
@ -730,12 +739,19 @@ dword_result_t KeWaitForSingleObject(lpvoid_t object_ptr, dword_t wait_reason,
|
||||||
return X_STATUS_ABANDONED_WAIT_0;
|
return X_STATUS_ABANDONED_WAIT_0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t timeout = timeout_ptr ? static_cast<uint64_t>(*timeout_ptr) : 0u;
|
X_STATUS result =
|
||||||
X_STATUS result = object->Wait(wait_reason, processor_mode, alertable,
|
object->Wait(wait_reason, processor_mode, alertable, timeout);
|
||||||
timeout_ptr ? &timeout : nullptr);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dword_result_t KeWaitForSingleObject(lpvoid_t object_ptr, dword_t wait_reason,
|
||||||
|
dword_t processor_mode, dword_t alertable,
|
||||||
|
lpqword_t timeout_ptr) {
|
||||||
|
uint64_t timeout = timeout_ptr ? static_cast<uint64_t>(*timeout_ptr) : 0u;
|
||||||
|
return keWaitForSingleObject(object_ptr, wait_reason, processor_mode,
|
||||||
|
alertable, &timeout);
|
||||||
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT3(KeWaitForSingleObject, kThreading, kImplemented,
|
DECLARE_XBOXKRNL_EXPORT3(KeWaitForSingleObject, kThreading, kImplemented,
|
||||||
kBlocking, kHighFrequency);
|
kBlocking, kHighFrequency);
|
||||||
|
|
||||||
|
@ -844,13 +860,12 @@ dword_result_t NtSignalAndWaitForSingleObjectEx(dword_t signal_handle,
|
||||||
DECLARE_XBOXKRNL_EXPORT3(NtSignalAndWaitForSingleObjectEx, kThreading,
|
DECLARE_XBOXKRNL_EXPORT3(NtSignalAndWaitForSingleObjectEx, kThreading,
|
||||||
kImplemented, kBlocking, kHighFrequency);
|
kImplemented, kBlocking, kHighFrequency);
|
||||||
|
|
||||||
dword_result_t KfAcquireSpinLock(lpdword_t lock_ptr) {
|
uint32_t keKfAcquireSpinLock(uint32_t* lock) {
|
||||||
// XELOGD(
|
// XELOGD(
|
||||||
// "KfAcquireSpinLock(%.8X)",
|
// "KfAcquireSpinLock(%.8X)",
|
||||||
// lock_ptr);
|
// lock_ptr);
|
||||||
|
|
||||||
// Lock.
|
// Lock.
|
||||||
auto lock = reinterpret_cast<uint32_t*>(lock_ptr.host_address());
|
|
||||||
while (!xe::atomic_cas(0, 1, lock)) {
|
while (!xe::atomic_cas(0, 1, lock)) {
|
||||||
// Spin!
|
// Spin!
|
||||||
// TODO(benvanik): error on deadlock?
|
// TODO(benvanik): error on deadlock?
|
||||||
|
@ -863,18 +878,27 @@ dword_result_t KfAcquireSpinLock(lpdword_t lock_ptr) {
|
||||||
|
|
||||||
return old_irql;
|
return old_irql;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dword_result_t KfAcquireSpinLock(lpdword_t lock_ptr) {
|
||||||
|
auto lock = reinterpret_cast<uint32_t*>(lock_ptr.host_address());
|
||||||
|
return keKfAcquireSpinLock(lock);
|
||||||
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT3(KfAcquireSpinLock, kThreading, kImplemented, kBlocking,
|
DECLARE_XBOXKRNL_EXPORT3(KfAcquireSpinLock, kThreading, kImplemented, kBlocking,
|
||||||
kHighFrequency);
|
kHighFrequency);
|
||||||
|
|
||||||
void KfReleaseSpinLock(lpdword_t lock_ptr, dword_t old_irql) {
|
void keKfReleaseSpinLock(uint32_t* lock, dword_t old_irql) {
|
||||||
// Restore IRQL.
|
// Restore IRQL.
|
||||||
XThread* thread = XThread::GetCurrentThread();
|
XThread* thread = XThread::GetCurrentThread();
|
||||||
thread->LowerIrql(old_irql);
|
thread->LowerIrql(old_irql);
|
||||||
|
|
||||||
// Unlock.
|
// Unlock.
|
||||||
auto lock = reinterpret_cast<uint32_t*>(lock_ptr.host_address());
|
|
||||||
xe::atomic_dec(lock);
|
xe::atomic_dec(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KfReleaseSpinLock(lpdword_t lock_ptr, dword_t old_irql) {
|
||||||
|
auto lock = reinterpret_cast<uint32_t*>(lock_ptr.host_address());
|
||||||
|
keKfReleaseSpinLock(lock, old_irql);
|
||||||
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT2(KfReleaseSpinLock, kThreading, kImplemented,
|
DECLARE_XBOXKRNL_EXPORT2(KfReleaseSpinLock, kThreading, kImplemented,
|
||||||
kHighFrequency);
|
kHighFrequency);
|
||||||
|
|
||||||
|
@ -1092,7 +1116,7 @@ struct X_ERWLOCK {
|
||||||
be<uint32_t> readers_entry_count; // 0xC
|
be<uint32_t> readers_entry_count; // 0xC
|
||||||
X_KEVENT writer_event; // 0x10
|
X_KEVENT writer_event; // 0x10
|
||||||
X_KSEMAPHORE reader_semaphore; // 0x20
|
X_KSEMAPHORE reader_semaphore; // 0x20
|
||||||
be<uint32_t> spin_lock; // 0x34
|
uint32_t spin_lock; // 0x34
|
||||||
};
|
};
|
||||||
|
|
||||||
void ExInitializeReadWriteLock(pointer_t<X_ERWLOCK> lock_ptr) {
|
void ExInitializeReadWriteLock(pointer_t<X_ERWLOCK> lock_ptr) {
|
||||||
|
@ -1105,6 +1129,51 @@ void ExInitializeReadWriteLock(pointer_t<X_ERWLOCK> lock_ptr) {
|
||||||
}
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT1(ExInitializeReadWriteLock, kThreading, kImplemented);
|
DECLARE_XBOXKRNL_EXPORT1(ExInitializeReadWriteLock, kThreading, kImplemented);
|
||||||
|
|
||||||
|
void ExAcquireReadWriteLockExclusive(pointer_t<X_ERWLOCK> lock_ptr) {
|
||||||
|
auto old_irql = keKfAcquireSpinLock(&lock_ptr->spin_lock);
|
||||||
|
lock_ptr->lock_count++;
|
||||||
|
keKfReleaseSpinLock(&lock_ptr->spin_lock, old_irql);
|
||||||
|
|
||||||
|
if (!lock_ptr->lock_count) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock_ptr->writers_waiting_count++;
|
||||||
|
keWaitForSingleObject(&lock_ptr->writer_event, 0, 0, 0, nullptr);
|
||||||
|
}
|
||||||
|
DECLARE_XBOXKRNL_EXPORT4(ExAcquireReadWriteLockExclusive, kThreading,
|
||||||
|
kImplemented, kBlocking, kHighFrequency, kSketchy);
|
||||||
|
|
||||||
|
void ExReleaseReadWriteLock(pointer_t<X_ERWLOCK> lock_ptr) {
|
||||||
|
auto old_irql = keKfAcquireSpinLock(&lock_ptr->spin_lock);
|
||||||
|
lock_ptr->lock_count--;
|
||||||
|
|
||||||
|
if (lock_ptr->lock_count < 0) {
|
||||||
|
keKfReleaseSpinLock(&lock_ptr->spin_lock, old_irql);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lock_ptr->readers_entry_count) {
|
||||||
|
auto readers_waiting_count = lock_ptr->readers_waiting_count;
|
||||||
|
if (readers_waiting_count) {
|
||||||
|
lock_ptr->readers_waiting_count = 0;
|
||||||
|
lock_ptr->readers_entry_count = readers_waiting_count;
|
||||||
|
keKfReleaseSpinLock(&lock_ptr->spin_lock, old_irql);
|
||||||
|
keReleaseSemaphore(&lock_ptr->reader_semaphore, 1, readers_waiting_count,
|
||||||
|
0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto count = lock_ptr->readers_entry_count--;
|
||||||
|
keKfReleaseSpinLock(&lock_ptr->spin_lock, old_irql);
|
||||||
|
if (!count) {
|
||||||
|
keSetEvent(&lock_ptr->writer_event, 1, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DECLARE_XBOXKRNL_EXPORT2(ExReleaseReadWriteLock, kThreading, kImplemented,
|
||||||
|
kSketchy);
|
||||||
|
|
||||||
// NOTE: This function is very commonly inlined, and probably won't be called!
|
// NOTE: This function is very commonly inlined, and probably won't be called!
|
||||||
pointer_result_t InterlockedPushEntrySList(
|
pointer_result_t InterlockedPushEntrySList(
|
||||||
pointer_t<X_SLIST_HEADER> plist_ptr, pointer_t<X_SINGLE_LIST_ENTRY> entry) {
|
pointer_t<X_SLIST_HEADER> plist_ptr, pointer_t<X_SINGLE_LIST_ENTRY> entry) {
|
||||||
|
|
Loading…
Reference in New Issue