From 801510dc5b211f17a76b059fc2ecc96aec693bfc Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Fri, 9 Nov 2018 16:05:03 +0100 Subject: [PATCH 01/64] Lower memory requirements --- main.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/main.c b/main.c index 9fb4c0c..95b0921 100644 --- a/main.c +++ b/main.c @@ -96,10 +96,11 @@ Address CreateInterface(const char* name, unsigned int slotCount) { //FIXME: Unsure about most terminology / inner workings here Address interfaceAddress = Allocate(1000); //FIXME: Size of object Address vtableAddress = Allocate(4 * slotCount); + char* slotNames = malloc(64 * slotCount); uint32_t* vtable = (uint32_t*)Memory(vtableAddress); for(unsigned int i = 0; i < slotCount; i++) { // Point addresses to themself - char* slotName = malloc(128); + char* slotName = &slotNames[i * 64]; sprintf(slotName, "%s__%d", name, i); Export* export = LookupExportByName(slotName); @@ -1055,7 +1056,7 @@ HACKY_IMPORT_BEGIN(DirectDrawCreate) hacky_printf("lpGUID 0x%" PRIX32 "\n", stack[1]); hacky_printf("lplpDD 0x%" PRIX32 "\n", stack[2]); hacky_printf("pUnkOuter 0x%" PRIX32 "\n", stack[3]); - *(Address*)Memory(stack[2]) = CreateInterface("IDirectDraw4", 200); + *(Address*)Memory(stack[2]) = CreateInterface("IDirectDraw4", 30); eax = 0; // DD_OK esp += 3 * 4; HACKY_IMPORT_END() @@ -1906,7 +1907,7 @@ HACKY_COM_BEGIN(IDirectDraw4, 0) assert(false); } - *(Address*)Memory(stack[3]) = CreateInterface(name, 200); + *(Address*)Memory(stack[3]) = CreateInterface(name, 30); eax = 0; // FIXME: No idea what this expects to return.. esp += 3 * 4; HACKY_COM_END() @@ -1925,7 +1926,7 @@ HACKY_COM_BEGIN(IDirectDraw4, 5) hacky_printf("b 0x%" PRIX32 "\n", stack[3]); hacky_printf("c 0x%" PRIX32 "\n", stack[4]); hacky_printf("d 0x%" PRIX32 "\n", stack[5]); - *(Address*)Memory(stack[4]) = CreateInterface("IDirectDrawPalette", 200); + *(Address*)Memory(stack[4]) = CreateInterface("IDirectDrawPalette", 10); eax = 0; // FIXME: No idea what this expects to return.. esp += 5 * 4; HACKY_COM_END() @@ -1978,7 +1979,7 @@ enum { printf("GL handle is %d\n", texture->handle); } else { //FIXME: only added to catch bugs, null pointer should work - surface->texture = CreateInterface("invalid", 200); + surface->texture = CreateInterface("invalid", 50); //FIXME: WTF is this shit?! API(Direct3DTexture2)* texture = (API(Direct3DTexture2)*)Memory(surface->texture); @@ -3535,7 +3536,7 @@ HACKY_COM_BEGIN(IDirectInputA, 3) hacky_printf("rguid 0x%" PRIX32 "\n", stack[2]); hacky_printf("lpIDD 0x%" PRIX32 "\n", stack[3]); hacky_printf("pUnkOuter 0x%" PRIX32 "\n", stack[4]); - *(Address*)Memory(stack[3]) = CreateInterface("IDirectInputDeviceA", 200); + *(Address*)Memory(stack[3]) = CreateInterface("IDirectInputDeviceA", 20); eax = 0; // HRESULT -> non-negative means success esp += 4 * 4; HACKY_COM_END() From f5aec0f9851462956c8e6f88410df5a45d812343 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 10 Nov 2018 03:00:24 +0100 Subject: [PATCH 02/64] Avoid invalid memory access with icon names --- main.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/main.c b/main.c index 95b0921..445977c 100644 --- a/main.c +++ b/main.c @@ -1401,17 +1401,34 @@ HACKY_IMPORT_BEGIN(ExitThread) esp += 1 * 4; HACKY_IMPORT_END() +enum { + API(IDI_APPLICATION) = 0x7F00 +}; + +const char* IconName(Address address) { + const char* s; + switch(address) { + case API(IDI_APPLICATION): + s = ""; + break; + default: + s = (const char*)Memory(address); + break; + } + return s; +} + // Window creation function HACKY_IMPORT_BEGIN(LoadIconA) hacky_printf("hInstance 0x%" PRIX32 "\n", stack[1]); - hacky_printf("lpIconName 0x%" PRIX32 " ('%s')\n", stack[2], (char*)Memory(stack[2])); + hacky_printf("lpIconName 0x%" PRIX32 " ('%s')\n", stack[2], IconName(stack[2])); eax = 0; // NULL, pretend we failed esp += 2 * 4; HACKY_IMPORT_END() HACKY_IMPORT_BEGIN(LoadCursorA) hacky_printf("hInstance 0x%" PRIX32 "\n", stack[1]); - hacky_printf("lpCursorName 0x%" PRIX32 " ('%s')\n", stack[2], (char*)Memory(stack[2])); + hacky_printf("lpCursorName 0x%" PRIX32 " ('%s')\n", stack[2], IconName(stack[2])); eax = 0; // NULL, pretend we failed esp += 2 * 4; HACKY_IMPORT_END() From f262c431479bd5407ea48036bdb9a6fbd3574763 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Tue, 6 Nov 2018 05:37:41 +0100 Subject: [PATCH 03/64] Stub Xbox; start uc_native for some i386 hosts --- CMakeLists.txt | 36 ++-- emulation.c | 6 + uc_native.c | 298 ++++++++++++++++++++++++++++ xbox.c | 511 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 837 insertions(+), 14 deletions(-) create mode 100644 uc_native.c create mode 100644 xbox.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 91e1f87..156d71a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,30 +78,38 @@ include(package.cmake) if(USE_VM) target_compile_definitions(openswe1r PUBLIC -DUC_KVM) - target_sources(openswe1r PUBLIC - uc_kvm.c - ) +# target_sources(openswe1r PUBLIC +# uc_kvm.c +# ) else() target_link_libraries(openswe1r ${LIBUNICORN_LIBRARY} ) endif() -if(ENET_FOUND) - target_compile_definitions(openswe1r PUBLIC -DDPLAY_ENET) - target_link_libraries(openswe1r - ${ENET_LIBRARIES} - ) -endif() +#if(ENET_FOUND) +# target_compile_definitions(openswe1r PUBLIC -DDPLAY_ENET) +# target_link_libraries(openswe1r +# ${ENET_LIBRARIES} +# ) +#endif() + +#target_link_libraries(openswe1r +# ${OPENGL_LIBRARIES} +# ${GLEW_LIBRARIES} +# ${SDL2_LIBRARY} +# ${OPENAL_LIBRARY} +#) -target_link_libraries(openswe1r - ${OPENGL_LIBRARIES} - ${GLEW_LIBRARIES} - ${SDL2_LIBRARY} - ${OPENAL_LIBRARY} + +target_sources(openswe1r PUBLIC + uc_native.c + xbox.c ) if(MSVC) # Silence MSVC CRT security warnings target_compile_definitions(openswe1r PRIVATE _CRT_SECURE_NO_WARNINGS) endif() + +set_target_properties(openswe1r PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32 -static-libgcc") diff --git a/emulation.c b/emulation.c index 2357cce..2602c35 100644 --- a/emulation.c +++ b/emulation.c @@ -277,7 +277,13 @@ void* MapMemory(uint32_t address, uint32_t size, bool read, bool write, bool exe //FIXME: Permissions! uc_err err; assert(size % ucAlignment == 0); +#ifdef UC_NATIVE + //FIXME: Respect protection + void* memory = mmap(address, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_SHARED|MAP_FIXED, -1, 0); + assert(memory == address); +#else void* memory = aligned_malloc(ucAlignment, size); +#endif memset(memory, 0x00, size); err = uc_mem_map_ptr(uc, address, size, UC_PROT_ALL, memory); if (err) { diff --git a/uc_native.c b/uc_native.c new file mode 100644 index 0000000..72966b0 --- /dev/null +++ b/uc_native.c @@ -0,0 +1,298 @@ +// Copyright 2018 OpenSWE1R Maintainers +// Licensed under GPLv2 or any later version +// Refer to the included LICENSE.txt file. + +#include + +#include +#include + +#include + + +typedef struct { + int pad; +} uc_engine_native; + +uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, uint64_t begin, uint64_t end, ...) { + assert(false); +} + +uc_err uc_hook_del(uc_engine *uc, uc_hook hh) { + assert(false); +} + +uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **uc) { + uc_engine_native* u = malloc(sizeof(uc_engine_native)); + memset(u, 0x00, sizeof(uc_engine_native)); + +#if 0 + struct sigaction sa; + + sa.sa_flags = SA_SIGSEGV; + sigemptyset(&sa.sa_mask); + sa.sa_sigaction = sigsegv_handler; + if (sigaction(SIGSEGV, &sa, NULL) == -1) { + perror("sigaction"); + } +#endif + +#if 0 + uc_engine_kvm* u = malloc(sizeof(uc_engine_kvm)); + int r; + + u->hook_index = 0; + u->fd = -1; + u->vcpu_fd = -1; + u->vm_fd = -1; + u->run = NULL; + u->cb_head = NULL; + u->mem_slots = 0; + u->thread = pthread_self(); + + //FIXME: Only do this on the calling thread + signal(SIGUSR1, nopSignalHandler); // Prevent termination on USER1 signals + + int fd; + fd = open("/dev/kvm", O_RDWR); + if (fd == -1) { + perror("open /dev/kvm"); + return -1; + } + u->fd = fd; + + r = ioctl(u->fd, KVM_GET_API_VERSION, 0); + assert(r == 12); + + fd = ioctl(u->fd, KVM_CREATE_VM, 0); + if (fd == -1) { + fprintf(stderr, "kvm_create_vm: %m\n"); + return -2; + } + u->vm_fd = fd; + + // Give intel it's required space, I think these addresses are unused. + // Needs room for 4 pages + uint64_t vm_base = 0xFFFFFFFF - 0x4000 + 1; +#if 1 + r = ioctl(u->vm_fd, KVM_SET_IDENTITY_MAP_ADDR, &vm_base); // 1 page + if (r < 0) { + fprintf(stderr, "Error assigning Identity Map space: %m\n"); + return -5; + } +#endif +#if 1 + r = ioctl(u->vm_fd, KVM_SET_TSS_ADDR, vm_base + 0x1000); // 3 pages + if (r < 0) { + fprintf(stderr, "Error assigning TSS space: %m\n"); + return -6; + } +#endif + + r = ioctl(u->vm_fd, KVM_CREATE_VCPU, 0); + if (r == -1) { + fprintf(stderr, "kvm_create_vcpu: %m\n"); + return -7; + } + u->vcpu_fd = r; + +#ifdef KVM_CAP_IMMEDIATE_EXIT + kvm_print_cap(u->vm_fd, KVM_CAP_IMMEDIATE_EXIT); +#endif + kvm_print_cap(u->vm_fd, KVM_CAP_NR_VCPUS); + kvm_print_cap(u->vm_fd, KVM_CAP_MAX_VCPUS); + kvm_print_cap(u->vm_fd, KVM_CAP_ADJUST_CLOCK); + kvm_print_cap(u->vm_fd, KVM_CAP_TSC_CONTROL); + kvm_print_cap(u->vm_fd, KVM_CAP_TSC_DEADLINE_TIMER); + kvm_print_cap(u->vm_fd, KVM_CAP_READONLY_MEM); + kvm_print_cap(u->vm_fd, KVM_CAP_SET_IDENTITY_MAP_ADDR); + kvm_print_cap(u->vm_fd, KVM_CAP_SET_TSS_ADDR); + kvm_print_cap(u->vm_fd, KVM_CAP_SET_GUEST_DEBUG); + kvm_print_cap(u->vm_fd, KVM_CAP_IRQCHIP); + kvm_print_cap(u->vm_fd, KVM_CAP_NR_MEMSLOTS); + + long mmap_size = ioctl(u->fd, KVM_GET_VCPU_MMAP_SIZE, 0); + if (mmap_size == -1) { + fprintf(stderr, "get vcpu mmap size: %m\n"); + return -8; + } + void *map = mmap(NULL, mmap_size, PROT_READ|PROT_WRITE, MAP_SHARED, u->vcpu_fd, 0); + if (map == MAP_FAILED) { + fprintf(stderr, "mmap vcpu area: %m\n"); + return -9; + } + u->run = (struct kvm_run*)map; + + // Prepare CPU State + struct kvm_regs regs = { 0 }; + r = ioctl(u->vcpu_fd, KVM_GET_REGS, ®s); + + regs.rax = 0; + regs.rbx = 0; + regs.rcx = 0; + regs.rdx = 0; + regs.rsi = 0; + regs.rdi = 0; + regs.rsp = 0; + regs.rbp = 0; + // FIXME: regs.r8 - regs.r15 ? + + struct kvm_sregs sregs = { 0 }; + r = ioctl(u->vcpu_fd, KVM_GET_SREGS, &sregs); + + sregs.cr0 |= 1; // Enable protected mode + load_dtable(&sregs.gdt, 0xFFFFF000, 0x18); + load_segment(&sregs.cs, 0x08, 0x00000000, 0xFFFFFFFF, 0xCF9B); + load_segment(&sregs.ds, 0x10, 0x00000000, 0xFFFFFFFF, 0xCF93); + load_segment(&sregs.es, 0x10, 0x00000000, 0xFFFFFFFF, 0xCF93); + load_segment(&sregs.ss, 0x10, 0x00000000, 0xFFFFFFFF, 0xCF93); + + regs.rflags = 2; + + + r = ioctl(u->vcpu_fd, KVM_SET_REGS, ®s); + r = ioctl(u->vcpu_fd, KVM_SET_SREGS, &sregs); + + + // Enable signals + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGUSR1); + r = pthread_sigmask(SIG_UNBLOCK, &set, NULL); + if (r != 0) { + fprintf(stderr, "pthread_sigmask %m\n"); + } + + *uc = (uc_engine*)u; + return 0; +#endif +} +uc_err uc_close(uc_engine *uc) { + assert(false); + return 0; +} + + +uc_err uc_reg_read(uc_engine *uc, int regid, void *value) { +#if 0 + uc_engine_kvm* u = (uc_engine_kvm*)uc; + + assert(u->vcpu_fd != -1); + + struct kvm_regs regs; + struct kvm_sregs sregs; + int r = ioctl(u->vcpu_fd, KVM_GET_REGS, ®s); + int s = ioctl(u->vcpu_fd, KVM_GET_SREGS, &sregs); + + if (regid == UC_X86_REG_EIP) { + *(int*)value = regs.rip; + } else if (regid == UC_X86_REG_ESP) { + *(int*)value = regs.rsp; + } else if (regid == UC_X86_REG_EAX) { + *(int*)value = regs.rax; + } else { +// assert(false); + } + + return 0; +#endif +} +uc_err uc_reg_write(uc_engine *uc, int regid, const void *value) { +#if 0 + if (regid == UC_X86_REG_GDTR) { + const uc_x86_mmr* gdtr = value; + //sregs.gdt.base = gdtr->base; + //sregs.gdt.limit = gdtr->limit; + } else if (regid == UC_X86_REG_EIP) { + regs.rip = *(int*)value; + } else if (regid == UC_X86_REG_ESP) { + regs.rsp = *(unsigned int*)value; + } else if (regid == UC_X86_REG_EBP) { + regs.rbp = *(int*)value; + } else if (regid == UC_X86_REG_ESI) { + regs.rsi = *(int*)value; + } else if (regid == UC_X86_REG_EDI) { + regs.rdi = *(int*)value; + } else if (regid == UC_X86_REG_EAX) { + regs.rax = *(int*)value; + } else if (regid == UC_X86_REG_EBX) { + regs.rbx = *(int*)value; + } else if (regid == UC_X86_REG_ECX) { + regs.rcx = *(int*)value; + } else if (regid == UC_X86_REG_EDX) { + regs.rdx = *(int*)value; + } else if (regid == UC_X86_REG_EFLAGS) { + //regs.rflags = *(int*)value; + } else if (regid == UC_X86_REG_FPSW) { + //FIXME + } else if (regid == UC_X86_REG_FPCW) { + //FIXME + } else if (regid == UC_X86_REG_FPTAG) { + //FIXME + } else if (regid == UC_X86_REG_FP0) { + //FIXME + } else if (regid == UC_X86_REG_FP1) { + //FIXME + } else if (regid == UC_X86_REG_FP2) { + //FIXME + } else if (regid == UC_X86_REG_FP3) { + //FIXME + } else if (regid == UC_X86_REG_FP4) { + //FIXME + } else if (regid == UC_X86_REG_FP5) { + //FIXME + } else if (regid == UC_X86_REG_FP6) { + //FIXME + } else if (regid == UC_X86_REG_FP7) { + //FIXME + } else if (regid == UC_X86_REG_CS) { + +#if 0 + __u64 base; + __u32 limit; + __u16 selector; + __u8 type; + __u8 present, dpl, db, s, l, g, avl; + __u8 unusable; + __u8 padding; +#endif + //sregs.cs.selector = *(int*)value; + } else if (regid == UC_X86_REG_DS) { + //sregs.ds.selector = *(int*)value; + } else if (regid == UC_X86_REG_ES) { + //sregs.es.selector = *(int*)value; + } else if (regid == UC_X86_REG_SS) { + //sregs.ss.selector = *(int*)value; + } else if (regid == UC_X86_REG_FS) { + //sregs.fs.selector = *(int*)value; + + } + else { + assert(false); + } + +sregs.fs.base = 0xB0000000; +sregs.fs.limit = 0x1000; + + ioctl(u->vcpu_fd, KVM_SET_REGS, ®s); + ioctl(u->vcpu_fd, KVM_SET_SREGS, &sregs); +#endif + return 0; +} +uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count) { + printf("uc_emu_start\n"); + return 0; +} +uc_err uc_emu_stop(uc_engine *uc) { + assert(false); +} +uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size, uint32_t perms, void *ptr) { + printf("Mapping guest 0x%08" PRIX64 " - 0x%08" PRIX64 " to %p\n", address, address + size - 1, ptr); + + assert(address == ptr); + + return 0; +} +const char *uc_strerror(uc_err code) { + return "meh"; +} diff --git a/xbox.c b/xbox.c new file mode 100644 index 0000000..80b6066 --- /dev/null +++ b/xbox.c @@ -0,0 +1,511 @@ +// This file does not belong to OpenSWE1R. +// +// It's mostly a prototype for other libs which will be required on Xbox. +// Some of these will likely be stubbed / disabled in OpenSWE1R. +// However, it's currently not known which parts exactly; so this is a hack. + +#include + +#define GLEW_STATIC +#include + +#include +#include + + + + +int alcCreateContext(int a0) { + printf("%s\n", __func__); + return 0; +} + +int alcMakeContextCurrent(int a0) { + printf("%s\n", __func__); + return 1; +} + +int alcOpenDevice(int a0) { + printf("%s\n", __func__); + return 1; +} + + + + + + +int alBufferData(int a0) { + printf("%s\n", __func__); + return 0; +} + +int alGenBuffers(int a0) { + printf("%s\n", __func__); + return 0; +} + +int alGenSources(int a0) { + printf("%s\n", __func__); + return 0; +} + +int alSource3f(int a0) { + printf("%s\n", __func__); + return 0; +} + +int alSourcef(int a0) { + printf("%s\n", __func__); + return 0; +} + +int alSourcei(int a0) { + printf("%s\n", __func__); + return 0; +} + +int alSourcePlay(int a0) { + printf("%s\n", __func__); + return 0; +} + +int alSourceStop(int a0) { + printf("%s\n", __func__); + return 0; +} + + + + + + + + + + +#define GLAPI + + +GLAPI void GLAPIENTRY glBindTexture (GLenum target, GLuint texture) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY glClearDepth (GLclampd depth) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY glClear (GLbitfield mask) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY glClearStencil (GLint s) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY glCullFace (GLenum mode) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY glDepthFunc (GLenum func) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY glDepthMask (GLboolean flag) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY glDisable (GLenum cap) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const void *indices) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY glEnable (GLenum cap) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY glGenTextures (GLsizei n, GLuint *textures) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY glGetIntegerv (GLenum pname, GLint *params) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) { + printf("%s\n", __func__); + + switch(type) { + case GL_UNSIGNED_BYTE: { + FILE* f = fopen("/tmp/rgba8888.bin", "wb"); + fwrite(pixels, width * height * 4, 1, f); + fclose(f); + break; + } + case GL_UNSIGNED_SHORT_1_5_5_5_REV: { + FILE* f = fopen("/tmp/rgba5551.bin", "wb"); + fwrite(pixels, width * height * 2, 1, f); + fclose(f); + break; + } + case GL_UNSIGNED_SHORT_4_4_4_4_REV: { + FILE* f = fopen("/tmp/rgba4444.bin", "wb"); + fwrite(pixels, width * height * 2, 1, f); + fclose(f); + break; + } + default: + assert(false); + break; + } + return; +} + +GLAPI void GLAPIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height) { + printf("%s\n", __func__); + return; +} + + + + + + + +GLAPI void GLAPIENTRY _glActiveTexture(unsigned int a0) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY _glAttachShader(int a0) { + printf("%s\n", __func__); + return; +} + +void GLAPIENTRY _glBindBuffer(GLenum target, GLuint buffer) { + printf("%s\n", __func__); + return; +} + +void GLAPIENTRY _glBindVertexArray(int a0) { + printf("%s\n", __func__); + return; +} + +void GLAPIENTRY _glBufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY _glClearDepthf(int a0) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY _glCompileShader(int a0) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY _glCreateProgram(int a0) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY _glCreateShader(int a0) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY _glDebugMessageInsert(int a0) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY _glEnableVertexAttribArray(int a0) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY _glGenBuffers(int a0, unsigned int* a1) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY _glGenVertexArrays(int a0, unsigned int* a1) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY _glGetAttribLocation(int a0) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY _glewGetErrorString(int a0) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY _glGetProgramInfoLog(int a0) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY _glGetProgramiv(GLuint program, GLenum pname, GLint* param) { + printf("%s\n", __func__); + *param = GL_TRUE; + return; +} + +GLAPI void GLAPIENTRY _glGetShaderInfoLog(int a0) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY _glGetShaderiv(int a0) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY _glGetUniformLocation(int a0) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY _glLinkProgram(int a0) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY _glShaderSource(int a0) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY _glUniform1f(int a0) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY _glUniform1i(int a0) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY _glUniform3f(int a0) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY _glUniform3fv(int a0) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY _glUniformMatrix4fv(int a0, int a1, unsigned char a2, const float * a3) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY _glUseProgram(unsigned int a0) { + printf("%s\n", __func__); + return; +} + +GLAPI void GLAPIENTRY _glVertexAttribPointer(unsigned int a0, int a1, unsigned int a2, unsigned char a3, int a4, const void * a5) { + printf("%s\n", __func__); + return; +} + + + + + + +#undef GLEWAPI +#define GLEWAPI //extern +#define GLEW_FUN_EXPORT GLEWAPI + +GLEW_FUN_EXPORT PFNGLACTIVETEXTUREPROC __glewActiveTexture = _glActiveTexture; +GLEW_FUN_EXPORT PFNGLGENVERTEXARRAYSPROC __glewGenVertexArrays = _glGenVertexArrays; +GLEW_FUN_EXPORT PFNGLUSEPROGRAMPROC __glewUseProgram = _glUseProgram; +GLEW_FUN_EXPORT PFNGLVERTEXATTRIBPOINTERPROC __glewVertexAttribPointer = _glVertexAttribPointer; +GLEW_FUN_EXPORT PFNGLUNIFORMMATRIX4FVPROC __glewUniformMatrix4fv = _glUniformMatrix4fv; +GLEW_FUN_EXPORT PFNGLGENBUFFERSPROC __glewGenBuffers = _glGenBuffers; +GLEW_FUN_EXPORT PFNGLGETATTRIBLOCATIONPROC __glewGetAttribLocation = _glGetAttribLocation; +GLEW_FUN_EXPORT PFNGLGETPROGRAMINFOLOGPROC __glewGetProgramInfoLog = _glGetProgramInfoLog; +GLEW_FUN_EXPORT PFNGLGETPROGRAMIVPROC __glewGetProgramiv = _glGetProgramiv; +GLEW_FUN_EXPORT PFNGLGETSHADERINFOLOGPROC __glewGetShaderInfoLog = _glGetShaderInfoLog; +GLEW_FUN_EXPORT PFNGLBINDVERTEXARRAYPROC __glewBindVertexArray = _glBindVertexArray; +GLEW_FUN_EXPORT PFNGLGETUNIFORMLOCATIONPROC __glewGetUniformLocation = _glGetUniformLocation; +GLEW_FUN_EXPORT PFNGLUNIFORM1IPROC __glewUniform1i = _glUniform1i; +GLEW_FUN_EXPORT PFNGLUNIFORM3FPROC __glewUniform3f = _glUniform3f; +GLEW_FUN_EXPORT PFNGLUNIFORM3FVPROC __glewUniform3fv = _glUniform3fv; +GLEW_FUN_EXPORT PFNGLUNIFORM1FPROC __glewUniform1f = _glUniform1f; +GLEW_FUN_EXPORT PFNGLENABLEVERTEXATTRIBARRAYPROC __glewEnableVertexAttribArray = _glEnableVertexAttribArray; +GLEW_FUN_EXPORT PFNGLDEBUGMESSAGEINSERTPROC __glewDebugMessageInsert = _glDebugMessageInsert; +GLEW_FUN_EXPORT PFNGLATTACHSHADERPROC __glewAttachShader = _glAttachShader; +GLEW_FUN_EXPORT PFNGLBUFFERDATAPROC __glewBufferData = _glBufferData; +GLEW_FUN_EXPORT PFNGLBINDBUFFERPROC __glewBindBuffer = _glBindBuffer; +GLEW_FUN_EXPORT PFNGLLINKPROGRAMPROC __glewLinkProgram = _glLinkProgram; +GLEW_FUN_EXPORT PFNGLCOMPILESHADERPROC __glewCompileShader = _glCompileShader; +GLEW_FUN_EXPORT PFNGLCLEARDEPTHFPROC __glewClearDepthf = _glClearDepthf; +GLEW_FUN_EXPORT PFNGLSHADERSOURCEPROC __glewShaderSource = _glShaderSource; +GLEW_FUN_EXPORT PFNGLCREATEPROGRAMPROC __glewCreateProgram = _glCreateProgram; +GLEW_FUN_EXPORT PFNGLCREATESHADERPROC __glewCreateShader = _glCreateShader; +GLEW_FUN_EXPORT PFNGLGETSHADERIVPROC __glewGetShaderiv = _glGetShaderiv; + +GLEWAPI GLboolean glewExperimental = GL_FALSE; + +GLEWAPI const GLubyte * GLEWAPIENTRY glewGetErrorString (GLenum error) { + printf("%s\n", __func__); + return ""; +} + +GLEWAPI GLenum GLEWAPIENTRY glewInit (void) { + printf("%s\n", __func__); + return 0; +} + + + + +int pthread_kill(int a0) { + printf("%s\n", __func__); + assert(false); + return 0; +} + +int pthread_sigmask(int a0) { + printf("%s\n", __func__); + return 0; +} + + + + + + + + + + + + + + + +int SDL_CreateWindow(int a0) { + printf("%s\n", __func__); + return 1; +} + +int SDL_Delay(int a0) { + printf("%s\n", __func__); + return 0; +} + +int SDL_GetKeyboardState(int a0) { + printf("%s\n", __func__); + static unsigned char keys[256]; + return keys; +} + +int SDL_GetMouseState(int a0) { + printf("%s\n", __func__); + return 0; +} + +int SDL_GetPerformanceCounter(int a0) { + printf("%s\n", __func__); + return SDL_GetTicks(); +} + +int SDL_GetPerformanceFrequency(int a0) { + printf("%s\n", __func__); + return 1; +} + +int SDL_GetTicks(int a0) { + printf("%s\n", __func__); + static int t = 0; + return t++; +} + +int SDL_GL_CreateContext(int a0) { + printf("%s\n", __func__); + return 1; +} + +int SDL_GL_SetAttribute(int a0, int a1) { + printf("%s\n", __func__); + return 0; +} + +int SDL_GL_SwapWindow(int a0) { + printf("%s\n", __func__); + return 0; +} + +int SDL_Init(int a0) { + printf("%s\n", __func__); + return 0; +} + +int SDL_PollEvent(int a0) { + printf("%s\n", __func__); + return 0; +} + +int SDL_ShowWindow(int a0) { + printf("%s\n", __func__); + return 0; +} + + From 1a9c8df89fe92fdf84565c31357039811235b17f Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 8 Nov 2018 04:09:48 +0100 Subject: [PATCH 04/64] Support native code execution --- CMakeLists.txt | 2 + emulation.c | 67 +++++++++++++++++++- main.c | 1 + uc_native.c | 164 +++++++++++++++++++++++++++++++++++++++---------- 4 files changed, 199 insertions(+), 35 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 156d71a..213afce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -106,6 +106,8 @@ target_sources(openswe1r PUBLIC uc_native.c xbox.c ) +target_compile_definitions(openswe1r PUBLIC -DUC_NATIVE) + if(MSVC) # Silence MSVC CRT security warnings diff --git a/emulation.c b/emulation.c index 2602c35..29e4e50 100644 --- a/emulation.c +++ b/emulation.c @@ -19,6 +19,10 @@ #include "emulation.h" #include "exe.h" +#ifdef UC_NATIVE +#include +#endif + //FIXME: These are hacks (register when mapping instead!)! extern Exe* exe; uint8_t* stack = NULL; @@ -341,12 +345,73 @@ void* Memory(uint32_t address) { return NULL; } +#ifdef UC_NATIVE +#include "uc_native.h" +#include + +extern jmp_buf* host_jmp; +extern uint32_t guest_registers_esp; +extern Registers* guest_registers; +extern uint32_t host_esp; +static uint32_t host_eip; + +static __attribute__((__stdcall)) void return_to_host() { + guest_registers->esp = guest_registers_esp; + guest_registers->eip = host_eip; + printf("yay 0x%08X\n", guest_registers->eip); +#if 0 + asm("mov $0, %%ax\n" + "mov %%ax, %%fs\n":); +#endif + longjmp(*host_jmp, 1); +} +#endif + Address CreateHlt() { +#ifdef UC_NATIVE + + extern void(__attribute__((__stdcall)) __return_to_host)(); + asm("jmp continue\n" + ".global __return_to_host\n" + "__return_to_host:\n" + + // Keep a backup of the real guest ESP + "mov %%esp, guest_registers_esp\n" + + // Fill guest_registers + "mov guest_registers, %%esp\n" + "add $32, %%esp\n" + "pusha\n" + + // Move to host space + "mov host_esp, %%esp\n" + "popa\n" + + "call return_to_host\n" + "continue:\n":); + + Address code_address = Allocate(20); + uint8_t* code = Memory(code_address); + *code++ = 0x90; // Marker + + *code++ = 0xc7; // mov code_address, [guest_eip] + *code++ = 0x05; + *(uint32_t*)code = (uintptr_t)&host_eip; + code += 4; + *(uint32_t*)code = code_address + 1; + code += 4; + + *code++ = 0xE9; // jmp __return_to_host + *(uint32_t*)code = (uintptr_t)__return_to_host - (uintptr_t)code - 4; + code += 4; +#else Address code_address = Allocate(2); uint8_t* code = Memory(code_address); + *code++ = 0x90; // Marker *code++ = 0xF4; // HLT //FIXME: Are changes to regs even registered here?! *code++ = 0xC3; // End block with RET +#endif return code_address; } @@ -629,7 +694,7 @@ void RunEmulation() { uc_reg_read(uc, UC_X86_REG_EIP, &ctx->eip); Address hltAddress = ctx->eip - 1; - assert(*(uint8_t*)Memory(hltAddress) == 0xF4); + assert(*(uint8_t*)Memory(hltAddress) == 0x90); HltHandler* hltHandler = findHltHandler(hltAddress); if(hltHandler != NULL) { diff --git a/main.c b/main.c index 445977c..ff6443e 100644 --- a/main.c +++ b/main.c @@ -4127,6 +4127,7 @@ int main(int argc, char* argv[]) { //memset(Memory(0x423cd9), 0x90, 5); // Disable command line arg scanning + printf("-- Switching mode\n"); RunX86(exe); printf("-- Exiting\n"); diff --git a/uc_native.c b/uc_native.c index 72966b0..9b6b01d 100644 --- a/uc_native.c +++ b/uc_native.c @@ -6,12 +6,23 @@ #include #include - +#include #include +#include +#include +#define _GNU_SOURCE +#include +#include +#include + +#include +#include +#include "uc_native.h" typedef struct { - int pad; + jmp_buf jmp; + Registers registers; } uc_engine_native; uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, uint64_t begin, uint64_t end, ...) { @@ -22,6 +33,19 @@ uc_err uc_hook_del(uc_engine *uc, uc_hook hh) { assert(false); } + +#if 0 +static void sigsegv_handler(int sig, siginfo_t *si, void *arg) { + printf("Got SIGSEGV at address: 0x%lx\n",(long) si->si_addr); + printf("Implements the handler only\n"); + flag=1; + + ucontext *u = (ucontext *)arg; + unsigned char *pc = (unsigned char *)u->uc_mcontext.gregs[REG_RIP]; + +} +#endif + uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **uc) { uc_engine_native* u = malloc(sizeof(uc_engine_native)); memset(u, 0x00, sizeof(uc_engine_native)); @@ -38,7 +62,6 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **uc) { #endif #if 0 - uc_engine_kvm* u = malloc(sizeof(uc_engine_kvm)); int r; u->hook_index = 0; @@ -162,10 +185,10 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **uc) { if (r != 0) { fprintf(stderr, "pthread_sigmask %m\n"); } +#endif *uc = (uc_engine*)u; return 0; -#endif } uc_err uc_close(uc_engine *uc) { assert(false); @@ -174,53 +197,45 @@ uc_err uc_close(uc_engine *uc) { uc_err uc_reg_read(uc_engine *uc, int regid, void *value) { -#if 0 - uc_engine_kvm* u = (uc_engine_kvm*)uc; - - assert(u->vcpu_fd != -1); - - struct kvm_regs regs; - struct kvm_sregs sregs; - int r = ioctl(u->vcpu_fd, KVM_GET_REGS, ®s); - int s = ioctl(u->vcpu_fd, KVM_GET_SREGS, &sregs); + uc_engine_native* u = (uc_engine_native*)uc; if (regid == UC_X86_REG_EIP) { - *(int*)value = regs.rip; + *(int*)value = u->registers.eip; } else if (regid == UC_X86_REG_ESP) { - *(int*)value = regs.rsp; + *(int*)value = u->registers.esp; } else if (regid == UC_X86_REG_EAX) { - *(int*)value = regs.rax; + *(int*)value = u->registers.eax; } else { // assert(false); } return 0; -#endif } uc_err uc_reg_write(uc_engine *uc, int regid, const void *value) { -#if 0 + uc_engine_native* u = (uc_engine_native*)uc; + if (regid == UC_X86_REG_GDTR) { - const uc_x86_mmr* gdtr = value; + //const uc_x86_mmr* gdtr = value; //sregs.gdt.base = gdtr->base; //sregs.gdt.limit = gdtr->limit; } else if (regid == UC_X86_REG_EIP) { - regs.rip = *(int*)value; + u->registers.eip = *(int*)value; } else if (regid == UC_X86_REG_ESP) { - regs.rsp = *(unsigned int*)value; + u->registers.esp = *(unsigned int*)value; } else if (regid == UC_X86_REG_EBP) { - regs.rbp = *(int*)value; + u->registers.ebp = *(int*)value; } else if (regid == UC_X86_REG_ESI) { - regs.rsi = *(int*)value; + u->registers.esi = *(int*)value; } else if (regid == UC_X86_REG_EDI) { - regs.rdi = *(int*)value; + u->registers.edi = *(int*)value; } else if (regid == UC_X86_REG_EAX) { - regs.rax = *(int*)value; + u->registers.eax = *(int*)value; } else if (regid == UC_X86_REG_EBX) { - regs.rbx = *(int*)value; + u->registers.ebx = *(int*)value; } else if (regid == UC_X86_REG_ECX) { - regs.rcx = *(int*)value; + u->registers.ecx = *(int*)value; } else if (regid == UC_X86_REG_EDX) { - regs.rdx = *(int*)value; + u->registers.edx = *(int*)value; } else if (regid == UC_X86_REG_EFLAGS) { //regs.rflags = *(int*)value; } else if (regid == UC_X86_REG_FPSW) { @@ -271,16 +286,97 @@ uc_err uc_reg_write(uc_engine *uc, int regid, const void *value) { assert(false); } -sregs.fs.base = 0xB0000000; -sregs.fs.limit = 0x1000; - - ioctl(u->vcpu_fd, KVM_SET_REGS, ®s); - ioctl(u->vcpu_fd, KVM_SET_SREGS, &sregs); -#endif return 0; } + +// Accessed via inline assembly +static uint32_t _begin; +Registers* guest_registers; +uint32_t guest_registers_esp; +uint32_t host_esp; +jmp_buf* host_jmp; + uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count) { + uc_engine_native* u = (uc_engine_native*)uc; printf("uc_emu_start\n"); + + host_jmp = &u->jmp; + + if (setjmp(*host_jmp) == 0) { + + printf("Doing some bullshit\n"); + + _begin = begin; + + static struct user_desc ldt_desc; + + + static uint8_t* tls = NULL; + if (tls == NULL) { + tls = malloc(0x1000); + memset(tls, 0xBB, 0x1000); + u->registers.fs_base = tls; + + #if 0 + ldt_desc.entry_number = 0x63 >> 3; + int ret2 = syscall(SYS_get_thread_area, &ldt_desc); + printf("%d\n", ldt_desc.limit); + printf("0x%X\n", ldt_desc.contents); + #endif + + ldt_desc.entry_number = -1; + ldt_desc.base_addr = u->registers.fs_base; + ldt_desc.limit = 0xFFF; + ldt_desc.seg_32bit = 1; + ldt_desc.contents = 0x0; + ldt_desc.read_exec_only = 0; + ldt_desc.limit_in_pages = 0; + ldt_desc.seg_not_present = 0; + ldt_desc.useable = 1; + + int ret = syscall(SYS_set_thread_area, &ldt_desc); + printf("%d: Got seg %d\n", ret, ldt_desc.entry_number); + } + + // Set FS to use our new thread area + uint16_t seg = ldt_desc.entry_number; + asm("mov %[seg], %%ax\n" + "shl $3, %%ax\n" + "or $0x3, %%ax\n" + "movw %%ax, %%fs\n"::[seg]"r"(seg)); + + +#if 0 + uint32_t foo = 0; + asm("mov %%fs:0, %[foo]\n" : [foo]"=r"(foo)); // : [fs]"r"(fs)); + printf("Read 0x%X\n", foo); +#endif + + guest_registers = &u->registers; + guest_registers_esp = guest_registers->esp; + + asm volatile(// "int3\n" + //"movl fs, 32([registers])" + + // Make host backup + "pusha\n" + "mov %%esp, host_esp\n" + + // Load all registers + "mov guest_registers, %%esp\n" + "popa\n" + "mov guest_registers_esp, %%esp\n" + //FIXME: Fixup ESP too + + "jmp *_begin\n":); + + // This can never return, or setjmp / longjmp would break! + assert(false); + + } else { + printf("Returned\n"); + } + return 0; } uc_err uc_emu_stop(uc_engine *uc) { From 197b5ff32ffaa9132425f411dc7bcad34a8015b4 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Fri, 9 Nov 2018 15:44:37 +0100 Subject: [PATCH 05/64] add sw renderer + works on xbox (but out of mem) --- .gitignore | 8 +++ CMakeLists.txt | 2 + Makefile.xbox | 34 +++++++++ cmake/FindUnicorn.cmake | 10 +-- common.h | 12 ++++ emulation.c | 72 ++++++++++++++----- main.c | 71 ++++++++++++++++-- main.h | 7 +- uc_kvm.c | 5 +- uc_native.c | 23 +++--- uc_native.h | 31 ++++++++ xbox-hacks/bsearch.c | 64 +++++++++++++++++ xbox-hacks/qsort.c | 149 ++++++++++++++++++++++++++++++++++++++ xbox.c | 154 +++++++++++++++++++++++++++++++++++++--- xbox.h | 3 + 15 files changed, 594 insertions(+), 51 deletions(-) create mode 100644 Makefile.xbox create mode 100644 uc_native.h create mode 100644 xbox-hacks/bsearch.c create mode 100644 xbox-hacks/qsort.c create mode 100644 xbox.h diff --git a/.gitignore b/.gitignore index 567609b..96d998d 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,9 @@ build/ + +# nxdk garbage +bin/ +*.obj +*.d +*.iso +*.exe +*.lib diff --git a/CMakeLists.txt b/CMakeLists.txt index 213afce..abef0d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,8 @@ if(ENET_FOUND) ) endif() +message(${LIBUNICORN_INCLUDE_DIR}) + include_directories(SYSTEM ${LIBUNICORN_INCLUDE_DIR} ${OPENGL_INCLUDE_DIR} diff --git a/Makefile.xbox b/Makefile.xbox new file mode 100644 index 0000000..df71bbc --- /dev/null +++ b/Makefile.xbox @@ -0,0 +1,34 @@ +NXDK_DIR = $(CURDIR)/../nxdk +//NXDK_SDL = y + +XBE_TITLE = OpenSWE1R +GEN_XISO = $(XBE_TITLE).iso +SRCS = +#SHADER_OBJS = ps.inl vs.inl + +SRCS += $(CURDIR)/xbox.c + +SRCS += $(CURDIR)/main.c +SRCS += $(CURDIR)/emulation.c +SRCS += $(CURDIR)/export.c +SRCS += $(CURDIR)/shader.c + +SRCS += $(CURDIR)/dll/kernel32.c + +SRCS += $(CURDIR)/com/a3d.c +SRCS += $(CURDIR)/com/dplay.c + +SRCS += $(CURDIR)/uc_native.c + +SRCS += $(CURDIR)/xbox-hacks/qsort.c +SRCS += $(CURDIR)/xbox-hacks/bsearch.c + +CFLAGS += -DUC_NATIVE=1 -DUC_KVM=1 +CFLAGS += -I/usr/include/unicorn +CFLAGS += -I/usr/include/AL +CFLAGS += -DXBOX -DAPIENTRY= -DGLAPI= + +SDL_DIR = $(NXDK_DIR)/lib/sdl/SDL2 +CFLAGS += -I$(SDL_DIR)/include + +include $(NXDK_DIR)/Makefile diff --git a/cmake/FindUnicorn.cmake b/cmake/FindUnicorn.cmake index a0f2a71..94597d1 100644 --- a/cmake/FindUnicorn.cmake +++ b/cmake/FindUnicorn.cmake @@ -4,15 +4,15 @@ # LIBUNICORN_LIBRARY find_path(LIBUNICORN_INCLUDE_DIR - unicorn/unicorn.h + unicorn.h HINTS $ENV{UNICORNDIR} - PATH_SUFFIXES include) + PATH_SUFFIXES include/unicorn include) find_library(LIBUNICORN_LIBRARY NAMES unicorn HINTS $ENV{UNICORNDIR}) include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(unicorn DEFAULT_MSG - LIBUNICORN_LIBRARY LIBUNICORN_INCLUDE_DIR) -mark_as_advanced(LIBUNICORN_INCLUDE_DIR LIBUNICORN_LIBRARY) + +find_package_handle_standard_args(unicorn + REQUIRED_VARS LIBUNICORN_LIBRARY LIBUNICORN_INCLUDE_DIR) diff --git a/common.h b/common.h index 53451e6..02b11b1 100644 --- a/common.h +++ b/common.h @@ -9,7 +9,11 @@ #include #if defined(_WIN32) +#if defined(XBOX) +# include +#else # include +#endif #else # include #endif @@ -35,7 +39,11 @@ static uint32_t AlignUp(uint32_t address, uint32_t size) { static void* aligned_malloc(size_t alignment, size_t size) { void* ptr; #if defined(_WIN32) +#ifdef XBOX + ptr = MmAllocateContiguousMemoryEx(size, 0x00000000, 0xFFFFFFFF, alignment, PAGE_READWRITE); +#else ptr = _aligned_malloc(size, alignment); +#endif #else posix_memalign(&ptr, alignment, size); #endif @@ -45,7 +53,11 @@ static void* aligned_malloc(size_t alignment, size_t size) { static void aligned_free(void* ptr) { #if defined(_WIN32) +#ifdef XBOX + MmFreeContiguousMemory(ptr); +#else _aligned_free(ptr); +#endif #else free(ptr); #endif diff --git a/emulation.c b/emulation.c index 29e4e50..e1156af 100644 --- a/emulation.c +++ b/emulation.c @@ -2,7 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the included LICENSE.txt file. -#include +#include "unicorn.h" #include #include @@ -20,26 +20,30 @@ #include "exe.h" #ifdef UC_NATIVE +#ifdef XBOX +#include +#else #include #endif +#endif //FIXME: These are hacks (register when mapping instead!)! extern Exe* exe; uint8_t* stack = NULL; uint8_t* heap = NULL; -static uint32_t gdtAddress = 0xA0000000; //FIXME: Search somehow?! +static uint32_t gdtAddress = 0x83000000; //FIXME: Search somehow?! static uint32_t gdtSize = 31 * sizeof(SegmentDescriptor); //FIXME: 31 came from the UC sample, why?! -static uint32_t tlsAddress = 0xB0000000; //FIXME: No idea where to put this yet +static uint32_t tlsAddress = 0x83100000; //FIXME: No idea where to put this yet static uint32_t tlsSize = 0x1000; -static uint32_t stackAddress = 0xC0000000; // FIXME: Search free region instead..? -static uint32_t stackSize = 16 * 1024 * 1024; // 4 MiB stack should be PLENTY +static uint32_t stackAddress = 0x83200000; // FIXME: Search free region instead..? +static uint32_t stackSize = 3 * 1024 * 1024; // 3 MiB stack should be PLENTY -#define HEAP_ADDRESS 0x0D000000 +#define HEAP_ADDRESS 0x81000000 static uint32_t heapAddress = HEAP_ADDRESS; -static uint32_t heapSize = 1024 * 1024 * 1024; // 1024 MiB +static uint32_t heapSize = 16 * 1024 * 1024; // 16 MiB static uc_engine *uc; static uint32_t ucAlignment = 0x1000; @@ -282,8 +286,29 @@ void* MapMemory(uint32_t address, uint32_t size, bool read, bool write, bool exe uc_err err; assert(size % ucAlignment == 0); #ifdef UC_NATIVE +#ifdef XBOX +#if 0 + +#else + void* memory; + if(address & 0x80000000) { + uint32_t base_address = address & 0x7FFFFFFF; + memory = MmAllocateContiguousMemoryEx(size, base_address, base_address + size - 1, 0, PAGE_READWRITE); + } else { + // We can't move some data, like the EXE sections. However, they are not contiguous memory. + // So we can't have GPU resources in them. + memory = address; + SIZE_T allocated_size = size; + NTSTATUS status = NtAllocateVirtualMemory(&memory, 0, &allocated_size, MEM_COMMIT, PAGE_READWRITE); + printf("status was %x\n", status); + assert(status == STATUS_SUCCESS); + } + printf("got %p == %p (%d bytes)?\n", memory, address, size); +#endif +#else //FIXME: Respect protection void* memory = mmap(address, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_SHARED|MAP_FIXED, -1, 0); +#endif assert(memory == address); #else void* memory = aligned_malloc(ucAlignment, size); @@ -313,6 +338,10 @@ address += 0x1000; address &= 0xFFFFF000; #endif + assert(address < (HEAP_ADDRESS + heapSize)); + int use = (address - HEAP_ADDRESS); + debugPrint("%u / %u = %u percent\n", use, heapSize, (use * 100) / heapSize); + return ret; } @@ -355,7 +384,12 @@ extern Registers* guest_registers; extern uint32_t host_esp; static uint32_t host_eip; -static __attribute__((__stdcall)) void return_to_host() { +#ifndef __stdcall +#define __stdcall __attribute__((stdcall)) +#endif + + +void __stdcall return_to_host() { guest_registers->esp = guest_registers_esp; guest_registers->eip = host_eip; printf("yay 0x%08X\n", guest_registers->eip); @@ -370,24 +404,24 @@ static __attribute__((__stdcall)) void return_to_host() { Address CreateHlt() { #ifdef UC_NATIVE - extern void(__attribute__((__stdcall)) __return_to_host)(); + extern void(__stdcall __return_to_host)(); asm("jmp continue\n" - ".global __return_to_host\n" - "__return_to_host:\n" + ".global ___return_to_host@0\n" + "___return_to_host@0:\n" // Keep a backup of the real guest ESP - "mov %%esp, guest_registers_esp\n" + "mov %%esp, _guest_registers_esp\n" // Fill guest_registers - "mov guest_registers, %%esp\n" + "mov _guest_registers, %%esp\n" "add $32, %%esp\n" "pusha\n" // Move to host space - "mov host_esp, %%esp\n" + "mov _host_esp, %%esp\n" "popa\n" - "call return_to_host\n" + "call _return_to_host@0\n" "continue:\n":); Address code_address = Allocate(20); @@ -549,13 +583,13 @@ void InitializeEmulation() { uc_reg_write(uc, UC_X86_REG_EDX, &edx); #endif - // Map and set TLS (not exposed via flat memory) - uint8_t* tls = MapMemory(tlsAddress, tlsSize, true, true, false); - memset(tls, 0xBB, tlsSize); - // Allocate a heap heap = MapMemory(heapAddress, heapSize, true, true, true); memset(heap, 0xAA, heapSize); + + // Map and set TLS (not exposed via flat memory) + uint8_t* tls = MapMemory(tlsAddress, tlsSize, true, true, false); + memset(tls, 0xBB, tlsSize); } void SetTracing(bool enabled) { diff --git a/main.c b/main.c index ff6443e..e9c8315 100644 --- a/main.c +++ b/main.c @@ -3,7 +3,11 @@ // Refer to the included LICENSE.txt file. #include "main.h" +#ifndef XBOX #include "app_version.h" +#else +#define APP_VERSION_STRING "" +#endif #include #include @@ -18,8 +22,14 @@ #include "emulation.h" #include "exe.h" +#ifndef XBOX //FIXME: Alternative for non-posix OS! #include +#endif + +#ifdef XBOX +#include "xbox.h" +#endif #include "SDL.h" @@ -47,6 +57,7 @@ void AddExport(const char* name, void* callback, Address address) { Export* export = &exports[exportCount]; export->name = malloc(strlen(name) + 1); strcpy((char*)export->name, name); + printf(" Stored '%s' at %p\n", export->name, export->name); export->callback = callback; export->address = 0; exportCount++; @@ -89,7 +100,7 @@ uint32_t tls[1000] = {0}; #include "windows.h" // Hack while exports are not ready // HACK: -#include +#include "unicorn.h" static void UnknownImport(void* uc, Address address, void* user_data); Address CreateInterface(const char* name, unsigned int slotCount) { @@ -1000,11 +1011,22 @@ HACKY_IMPORT_BEGIN(CoCreateInstance) hacky_printf("ppv 0x%" PRIX32 "\n", stack[5]); const API(CLSID)* clsid = (const API(CLSID)*)Memory(stack[1]); char clsidString[1024]; + hacky_printf("pre sprintf\n"); sprintf(clsidString, "%08" PRIX32 "-%04" PRIX16 "-%04" PRIX16 "-%02" PRIX8 "%02" PRIX8 "-%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8, clsid->Data1, clsid->Data2, clsid->Data3, clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3], clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7]); +clsidString[50] = '\0'; + +hacky_printf("post sprintf / pre printf\n"); +hacky_printf("<<< (%d bytes)\n", strlen(clsidString)); +hacky_printf(clsidString); +hacky_printf("\n---\n"); +hacky_printf(" (read clsid: {%s})\n", clsidString); +hacky_printf(">>>\n"); + printf(" (read clsid: {%s})\n", clsidString); +hacky_printf("post printf\n"); const API(IID)* iid = (const API(IID)*)Memory(stack[4]); char iidString[1024]; sprintf(iidString, "%08" PRIX32 "-%04" PRIX16 "-%04" PRIX16 "-%02" PRIX8 "%02" PRIX8 "-%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8, @@ -3882,7 +3904,7 @@ Exe* LoadExe(const char* path) { sprintf(label, "<%s@%d>", name, ordinal); } else { API(IMAGE_IMPORT_BY_NAME)* importByName = Memory(exe->peHeader.imageBase + importByNameAddress); - printf(" 0x%" PRIX32 ": 0x%" PRIX16 " '%s' ..", thunkAddress, importByName->hint, importByName->name); + printf(" 0x%" PRIX32 ": 0x%" PRIX16 " '%s' (%p) ..", thunkAddress, importByName->hint, importByName->name, importByName->name); label = strdup(importByName->name); } @@ -3986,7 +4008,9 @@ void RunX86(Exe* exe) { printf("Mapping 0x%" PRIX32 " - 0x%" PRIX32 "\n", base, base + section->virtualSize - 1); void* relocatedMappedSection = MapMemory(base, AlignUp(section->virtualSize, exe->peHeader.sectionAlignment), true, true, true); memcpy(relocatedMappedSection, *mappedSection, section->virtualSize); - aligned_free(*mappedSection); + //FIXME: Can't free this :( + // This is used by some of the code [export->name most importantly] + //aligned_free(*mappedSection); *mappedSection = relocatedMappedSection; } } @@ -3999,7 +4023,47 @@ void RunX86(Exe* exe) { CleanupEmulation(); } +#ifdef XBOX +// Stolen from https://gist.github.com/mmozeiko/ae38aeb10add7cb66be4c00f24f8e688 + +// C initializers +__attribute__((section(".CRT$XCA"))) _PVFV __xc_a[] = { 0 }; +__attribute__((section(".CRT$XCZ"))) _PVFV __xc_z[] = { 0 }; + +static void win32_crt_call(_PVFV* a, _PVFV* b) { + while (a != b) { + if (*a) { + (**a)(); + } + a++; + } +} +#endif + int main(int argc, char* argv[]) { +#ifdef XBOX + + // Reserve the space for the EXE + void* memory = 0x00400000; + SIZE_T allocated_size = 0x00C00000; + NTSTATUS status = NtAllocateVirtualMemory(&memory, 0, &allocated_size, MEM_RESERVE, PAGE_READWRITE); + + pb_init(); + + pb_show_debug_screen(); + + // Clear log + FILE* f = fopen("log.txt", "wb"); + fclose(f); +#endif + + +#ifdef XBOX + printf("-- Running CRT functions ()\n"); + win32_crt_call(__xc_a, __xc_z); +#endif + + printf("-- Initializing\n"); printf("Version: %s\n", APP_VERSION_STRING); InitializeEmulation(); @@ -4127,7 +4191,6 @@ int main(int argc, char* argv[]) { //memset(Memory(0x423cd9), 0x90, 5); // Disable command line arg scanning - printf("-- Switching mode\n"); RunX86(exe); printf("-- Exiting\n"); diff --git a/main.h b/main.h index 1c59a05..5b23b00 100644 --- a/main.h +++ b/main.h @@ -5,7 +5,9 @@ #ifndef __OPENSWE1R_MAIN_H__ #define __OPENSWE1R_MAIN_H__ -#include +// We need to define _MSC_VER or unicorn attempts to typedef bool +#undef _MSC_VER +#include "unicorn.h" #include "emulation.h" @@ -27,7 +29,7 @@ Address CreateInterface(const char* name, unsigned int slotCount); void AddExport(const char* name, void* callback, Address address); // Defines an INITIALIZER macro which will run code at startup -#if defined(__GNUC__) +#if defined(__GNUC__) || defined(__clang__) # define INITIALIZER(_name) \ __attribute__((constructor)) void _name() #elif defined(_MSC_VER) @@ -84,6 +86,7 @@ void AddExport(const char* name, void* callback, Address address); if (!silent) { \ hacky_printf("Stack at 0x%" PRIX32 "; returning EAX: 0x%08" PRIX32 "\n", stackAddress, eax); \ hacky_printf("%7" PRIu32 " Emulation at %X ('%s') from %X\n\n", callId, eip, (char*)_user_data, returnAddress); \ + debugPrint("%u\n", callId); \ } \ callId++; \ \ diff --git a/uc_kvm.c b/uc_kvm.c index 83f6d2b..acb70d7 100644 --- a/uc_kvm.c +++ b/uc_kvm.c @@ -2,7 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the included LICENSE.txt file. -#include +#include "unicorn.h" #include #include @@ -443,7 +443,8 @@ uc_err uc_reg_write(uc_engine *uc, int regid, const void *value) { assert(false); } -sregs.fs.base = 0xB0000000; +//FIXME: Stolen from tlsAddress in emulation.c +sregs.fs.base = 0x83100000; sregs.fs.limit = 0x1000; ioctl(u->vcpu_fd, KVM_SET_REGS, ®s); diff --git a/uc_native.c b/uc_native.c index 9b6b01d..863464f 100644 --- a/uc_native.c +++ b/uc_native.c @@ -2,21 +2,24 @@ // Licensed under GPLv2 or any later version // Refer to the included LICENSE.txt file. -#include +#include "unicorn.h" #include #include #include #include + +#ifdef XBOX +#else +#define _GNU_SOURCE #include #include -#define _GNU_SOURCE #include #include #include - #include #include +#endif #include "uc_native.h" @@ -308,6 +311,8 @@ uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t time _begin = begin; +#ifdef XBOX +#else static struct user_desc ldt_desc; @@ -344,7 +349,7 @@ uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t time "shl $3, %%ax\n" "or $0x3, %%ax\n" "movw %%ax, %%fs\n"::[seg]"r"(seg)); - +#endif #if 0 uint32_t foo = 0; @@ -360,15 +365,15 @@ uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t time // Make host backup "pusha\n" - "mov %%esp, host_esp\n" + "mov %%esp, _host_esp\n" // Load all registers - "mov guest_registers, %%esp\n" + "mov _guest_registers, %%esp\n" "popa\n" - "mov guest_registers_esp, %%esp\n" + "mov _guest_registers_esp, %%esp\n" //FIXME: Fixup ESP too - "jmp *_begin\n":); + "jmp *__begin\n":); // This can never return, or setjmp / longjmp would break! assert(false); @@ -383,7 +388,7 @@ uc_err uc_emu_stop(uc_engine *uc) { assert(false); } uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size, uint32_t perms, void *ptr) { - printf("Mapping guest 0x%08" PRIX64 " - 0x%08" PRIX64 " to %p\n", address, address + size - 1, ptr); + printf("Mapping guest %p - %p to %p\n", (uintptr_t)address, (uintptr_t)(address + size - 1), ptr); assert(address == ptr); diff --git a/uc_native.h b/uc_native.h new file mode 100644 index 0000000..639e400 --- /dev/null +++ b/uc_native.h @@ -0,0 +1,31 @@ +// Copyright 2018 OpenSWE1R Maintainers +// Licensed under GPLv2 or any later version +// Refer to the included LICENSE.txt file. + +#ifndef __OPENSWE1R_UC_NATIVE_H__ +#define __OPENSWE1R_UC_NATIVE_H__ + + +typedef struct { + + // These are accessed by PUSHA / POPA, so they must come first. + // They must also be kept in this order. + uint32_t edi; // +0 + uint32_t esi; // +4 + uint32_t ebp; // +8 + uint32_t esp; // +12 + uint32_t ebx; // +16 + uint32_t edx; // +20 + uint32_t ecx; // +24 + uint32_t eax; // +28 + + // Extensions, can be re-ordered / added / removed, but assembly needs update + uint16_t fs; // +32 + uint16_t pad; // +34 + uint32_t eip; // +36 + + uint32_t fs_base; //+40 + +} Registers; + +#endif diff --git a/xbox-hacks/bsearch.c b/xbox-hacks/bsearch.c new file mode 100644 index 0000000..f044dbc --- /dev/null +++ b/xbox-hacks/bsearch.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 1990 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +/* + * Perform a binary search. + * + * The code below is a bit sneaky. After a comparison fails, we + * divide the work in half by moving either left or right. If lim + * is odd, moving left simply involves halving lim: e.g., when lim + * is 5 we look at item 2, so we change lim to 2 so that we will + * look at items 0 & 1. If lim is even, the same applies. If lim + * is odd, moving right again involes halving lim, this time moving + * the base up one item past p: e.g., when lim is 5 we change base + * to item 3 and make lim 2 so that we will look at items 3 and 4. + * If lim is even, however, we have to shrink it by one before + * halving: e.g., when lim is 4, we still looked at item 2, so we + * have to make lim 3, then halve, obtaining 1, so that we will only + * look at item 3. + */ +void * +bsearch(const void *key, const void *base0, size_t nmemb, size_t size, + int (*compar)(const void *, const void *)) +{ + const char *base = base0; + int lim, cmp; + const void *p; + for (lim = nmemb; lim != 0; lim >>= 1) { + p = base + (lim >> 1) * size; + cmp = (*compar)(key, p); + if (cmp == 0) + return ((void *)p); + if (cmp > 0) { /* key > p: move right */ + base = (char *)p + size; + lim--; + } /* else move left */ + } + return (NULL); +} diff --git a/xbox-hacks/qsort.c b/xbox-hacks/qsort.c new file mode 100644 index 0000000..6429e43 --- /dev/null +++ b/xbox-hacks/qsort.c @@ -0,0 +1,149 @@ +/* $OpenBSD: qsort.c,v 1.10 2005/08/08 08:05:37 espie Exp $ */ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +//#include +#include +static __inline char *med3(char *, char *, char *, int (*)(const void *, const void *)); +static __inline void swapfunc(char *, char *, int, int); +#define min(a, b) (a) < (b) ? a : b +/* + * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". + */ +#define swapcode(TYPE, parmi, parmj, n) { \ + long i = (n) / sizeof (TYPE); \ + TYPE *pi = (TYPE *) (parmi); \ + TYPE *pj = (TYPE *) (parmj); \ + do { \ + TYPE t = *pi; \ + *pi++ = *pj; \ + *pj++ = t; \ + } while (--i > 0); \ +} +#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ + es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1; +static __inline void +swapfunc(char *a, char *b, int n, int swaptype) +{ + if (swaptype <= 1) + swapcode(long, a, b, n) + else + swapcode(char, a, b, n) +} +#define swap(a, b) \ + if (swaptype == 0) { \ + long t = *(long *)(a); \ + *(long *)(a) = *(long *)(b); \ + *(long *)(b) = t; \ + } else \ + swapfunc(a, b, es, swaptype) +#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype) +static __inline char * +med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *)) +{ + return cmp(a, b) < 0 ? + (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a )) + :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c )); +} +void +qsort(void *aa, size_t n, size_t es, int (*cmp)(const void *, const void *)) +{ + char *pa, *pb, *pc, *pd, *pl, *pm, *pn; + int d, r, swaptype, swap_cnt; + char *a = aa; +loop: SWAPINIT(a, es); + swap_cnt = 0; + if (n < 7) { + for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es) + for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + pm = (char *)a + (n / 2) * es; + if (n > 7) { + pl = (char *)a; + pn = (char *)a + (n - 1) * es; + if (n > 40) { + d = (n / 8) * es; + pl = med3(pl, pl + d, pl + 2 * d, cmp); + pm = med3(pm - d, pm, pm + d, cmp); + pn = med3(pn - 2 * d, pn - d, pn, cmp); + } + pm = med3(pl, pm, pn, cmp); + } + swap(a, pm); + pa = pb = (char *)a + es; + + pc = pd = (char *)a + (n - 1) * es; + for (;;) { + while (pb <= pc && (r = cmp(pb, a)) <= 0) { + if (r == 0) { + swap_cnt = 1; + swap(pa, pb); + pa += es; + } + pb += es; + } + while (pb <= pc && (r = cmp(pc, a)) >= 0) { + if (r == 0) { + swap_cnt = 1; + swap(pc, pd); + pd -= es; + } + pc -= es; + } + if (pb > pc) + break; + swap(pb, pc); + swap_cnt = 1; + pb += es; + pc -= es; + } + if (swap_cnt == 0) { /* Switch to insertion sort */ + for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es) + for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + pn = (char *)a + n * es; + r = min(pa - (char *)a, pb - pa); + vecswap(a, pb - r, r); + r = min(pd - pc, pn - pd - (int)es); + vecswap(pb, pn - r, r); + if ((r = pb - pa) > (int)es) + qsort(a, r / es, es, cmp); + if ((r = pd - pc) > (int)es) { + /* Iterate rather than recurse to save stack space */ + a = pn - r; + n = r / es; + goto loop; + } +/* qsort(pn - r, r / es, es, cmp);*/ +} diff --git a/xbox.c b/xbox.c index 80b6066..f75a7a1 100644 --- a/xbox.c +++ b/xbox.c @@ -6,12 +6,25 @@ #include -#define GLEW_STATIC #include #include #include +#include +#include + + +#include "xbox.h" + + + + +// unistd.. thanks SDL +void _exit(int status) { + exit(status); +} + @@ -83,8 +96,15 @@ int alSourceStop(int a0) { +static void* element_array_buffer = NULL; +static void* array_buffer = NULL; + +extern float clipScale[]; +extern float clipOffset[]; -#define GLAPI +uint8_t buffer[640*480] = {0}; + +#define GLAPI // __stdcall GLAPI void GLAPIENTRY glBindTexture (GLenum target, GLuint texture) { @@ -109,6 +129,8 @@ GLAPI void GLAPIENTRY glClearDepth (GLclampd depth) { GLAPI void GLAPIENTRY glClear (GLbitfield mask) { printf("%s\n", __func__); + //FIXME: Clear color?! + memset(buffer, 0x00, sizeof(buffer)); return; } @@ -137,13 +159,102 @@ GLAPI void GLAPIENTRY glDisable (GLenum cap) { return; } +static void saveBuffer() { + + static int t = 0; + if (t++ < 60) { + return; + } + t = 0; + + FILE* f = fopen("fb.ppm", "wb"); + fprintf(f, "P3\n" + "640 480\n" + "255\n"); + for(int y = 0; y < 480; y++) { + for(int x = 0; x < 640; x++) { + uint8_t r = buffer[y * 640 + x]; + uint8_t g = buffer[y * 640 + x]; + uint8_t b = buffer[y * 640 + x]; + fprintf(f, "%d %d %d ", r,g,b); + } + fprintf(f, "\n"); + } + fclose(f); +} + +static void drawVertex(int i) { + + GLsizei stride = 4 * 4 + 4 + 4 + 1 * 8; + + struct Vertex { + float x; + float y; + float z; + float w; + float unk0; + float unk1; + float u; + float v; + }; + assert(sizeof(struct Vertex) == stride); + + struct Vertex* vertices = array_buffer; + struct Vertex* v = &vertices[i]; +/* +" gl_Position = vec4(positionIn.xyz * clipScale + clipOffset, 1.0);\n" +*/ + float fx = v->x * clipScale[0] + clipOffset[0]; + float fy = v->y * clipScale[1] + clipOffset[1]; + float fz = v->z * clipScale[2] + clipOffset[2]; + float fw = 1.0f; + + + // " gl_Position /= positionIn.w;\n" + fx /= fw; + fy /= fw; + fz /= fw; + fw /= fw; + + //" gl_Position.y = -gl_Position.y;\n" + fy = -fy; + + + int x = fx * 320 + 320; + int y = -fy * 240 + 240; + int z = fz * 0xFF; + + // Clip + if ((x < 0) || (x >= 640)) { return; } + if ((y < 0) || (y >= 480)) { return; } + + //FIXME: fz is typically -1.0?! + //if ((z < 0) || (z > 0xFF)) { return; } + z = 0xFF; + + buffer[y * 640 + x] = 0x80 + z / 2; + +} + GLAPI void GLAPIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count) { printf("%s\n", __func__); + + for(unsigned int i = 0; i < count; i++) { + drawVertex(first + i); + } + return; } GLAPI void GLAPIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const void *indices) { printf("%s\n", __func__); + + assert(type == GL_UNSIGNED_SHORT); + uint16_t* i16 = (uint16_t*)((uintptr_t)element_array_buffer + (uintptr_t)indices); + for(unsigned int i = 0; i < count; i++) { + drawVertex(i16[i]); + } + return; } @@ -177,19 +288,19 @@ GLAPI void GLAPIENTRY glTexImage2D (GLenum target, GLint level, GLint internalfo switch(type) { case GL_UNSIGNED_BYTE: { - FILE* f = fopen("/tmp/rgba8888.bin", "wb"); + FILE* f = fopen("rgba8888.bin", "wb"); fwrite(pixels, width * height * 4, 1, f); fclose(f); break; } case GL_UNSIGNED_SHORT_1_5_5_5_REV: { - FILE* f = fopen("/tmp/rgba5551.bin", "wb"); + FILE* f = fopen("rgba5551.bin", "wb"); fwrite(pixels, width * height * 2, 1, f); fclose(f); break; } case GL_UNSIGNED_SHORT_4_4_4_4_REV: { - FILE* f = fopen("/tmp/rgba4444.bin", "wb"); + FILE* f = fopen("rgba4444.bin", "wb"); fwrite(pixels, width * height * 2, 1, f); fclose(f); break; @@ -198,6 +309,9 @@ GLAPI void GLAPIENTRY glTexImage2D (GLenum target, GLint level, GLint internalfo assert(false); break; } + + printf("%s done\n", __func__); + return; } @@ -239,6 +353,15 @@ void GLAPIENTRY _glBindVertexArray(int a0) { void GLAPIENTRY _glBufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage) { printf("%s\n", __func__); + if (target == GL_ELEMENT_ARRAY_BUFFER) { + element_array_buffer = realloc(element_array_buffer, size); + memcpy(element_array_buffer, data, size); + } else if (target == GL_ARRAY_BUFFER) { + array_buffer = realloc(array_buffer, size); + memcpy(array_buffer, data, size); + } else { + assert(false); + } return; } @@ -313,9 +436,9 @@ GLAPI void GLAPIENTRY _glGetShaderiv(int a0) { return; } -GLAPI void GLAPIENTRY _glGetUniformLocation(int a0) { +GLAPI GLint GLAPIENTRY _glGetUniformLocation(GLuint program, const GLchar *name) { printf("%s\n", __func__); - return; + return name; } GLAPI void GLAPIENTRY _glLinkProgram(int a0) { @@ -343,8 +466,16 @@ GLAPI void GLAPIENTRY _glUniform3f(int a0) { return; } -GLAPI void GLAPIENTRY _glUniform3fv(int a0) { +GLAPI void GLAPIENTRY _glUniform3fv(GLint location, GLsizei count, const GLfloat *value) { printf("%s\n", __func__); +#if 0 + char* name = (char*)location; + if (!strcmp(name, "clipScale")) { + //FIXME! + } else { + printf("Unknown uniform: '%s'\n", name); + } +#endif return; } @@ -438,7 +569,7 @@ int pthread_sigmask(int a0) { - +#if 1 //#ifndef XBOX int SDL_CreateWindow(int a0) { @@ -490,6 +621,9 @@ int SDL_GL_SetAttribute(int a0, int a1) { int SDL_GL_SwapWindow(int a0) { printf("%s\n", __func__); + + saveBuffer(); + return 0; } @@ -508,4 +642,4 @@ int SDL_ShowWindow(int a0) { return 0; } - +#endif diff --git a/xbox.h b/xbox.h new file mode 100644 index 0000000..a81aef8 --- /dev/null +++ b/xbox.h @@ -0,0 +1,3 @@ +#pragma once + +typedef void (*_PVFV)(void); From 749a52e5045eb70919cafc1c6bf6a90542fd155f Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 6 Jun 2019 18:59:19 +0200 Subject: [PATCH 06/64] fixup: Use proper _WIN32 check for aligned_malloc --- common.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/common.h b/common.h index 02b11b1..89b804a 100644 --- a/common.h +++ b/common.h @@ -38,12 +38,10 @@ static uint32_t AlignUp(uint32_t address, uint32_t size) { static void* aligned_malloc(size_t alignment, size_t size) { void* ptr; -#if defined(_WIN32) #ifdef XBOX ptr = MmAllocateContiguousMemoryEx(size, 0x00000000, 0xFFFFFFFF, alignment, PAGE_READWRITE); -#else +#elif defined(_WIN32) ptr = _aligned_malloc(size, alignment); -#endif #else posix_memalign(&ptr, alignment, size); #endif @@ -52,12 +50,10 @@ static void* aligned_malloc(size_t alignment, size_t size) { } static void aligned_free(void* ptr) { -#if defined(_WIN32) #ifdef XBOX MmFreeContiguousMemory(ptr); -#else +#elif defined(_WIN32) _aligned_free(ptr); -#endif #else free(ptr); #endif From cde42834b0462a804cb11bcd51bdba544ed4a311 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 6 Jun 2019 19:00:14 +0200 Subject: [PATCH 07/64] Use smaller stack (hack: start stack in center) --- emulation.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/emulation.c b/emulation.c index e1156af..9c1c596 100644 --- a/emulation.c +++ b/emulation.c @@ -39,7 +39,7 @@ static uint32_t tlsAddress = 0x83100000; //FIXME: No idea where to put this yet static uint32_t tlsSize = 0x1000; static uint32_t stackAddress = 0x83200000; // FIXME: Search free region instead..? -static uint32_t stackSize = 3 * 1024 * 1024; // 3 MiB stack should be PLENTY +static uint32_t stackSize = 256 * 1024; // I've measured, and about 140k are in use at maximum #define HEAP_ADDRESS 0x81000000 static uint32_t heapAddress = HEAP_ADDRESS; @@ -655,7 +655,7 @@ unsigned int CreateEmulatedThread(uint32_t eip) { stack = MapMemory(stackAddress, stackSize, true, true, false); } static int threadId = 0; - uint32_t esp = stackAddress + stackSize / 2 + 256 * 1024 * threadId++; // 256 kiB per late thread + uint32_t esp = stackAddress + stackSize; assert(threadId < 4); threads = realloc(threads, ++threadCount * sizeof(ThreadContext)); From 3d9a274358e80d30784a22e636e988daf54001fe Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 6 Jun 2019 19:00:38 +0200 Subject: [PATCH 08/64] hack: Only dummy heap page --- emulation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emulation.c b/emulation.c index 9c1c596..ba22c38 100644 --- a/emulation.c +++ b/emulation.c @@ -43,7 +43,7 @@ static uint32_t stackSize = 256 * 1024; // I've measured, and about 140k are in #define HEAP_ADDRESS 0x81000000 static uint32_t heapAddress = HEAP_ADDRESS; -static uint32_t heapSize = 16 * 1024 * 1024; // 16 MiB +static uint32_t heapSize = 0x1000; //16 * 1024 * 1024; // 16 MiB static uc_engine *uc; static uint32_t ucAlignment = 0x1000; From 4ab42d61032dae234d8a0babf6298ff777d5a30b Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 6 Jun 2019 19:01:40 +0200 Subject: [PATCH 09/64] Support native malloc/free --- emulation.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/emulation.c b/emulation.c index ba22c38..4756362 100644 --- a/emulation.c +++ b/emulation.c @@ -323,6 +323,11 @@ void* MapMemory(uint32_t address, uint32_t size, bool read, bool write, bool exe } Address Allocate(Size size) { +#ifdef UC_NATIVE + Address ret = aligned_malloc(0x1000, size); + memset(Memory(ret), 0xDD, size); + return ret; +#else static uint32_t address = HEAP_ADDRESS; uint32_t ret = address; address += size; @@ -343,10 +348,15 @@ address &= 0xFFFFF000; debugPrint("%u / %u = %u percent\n", use, heapSize, (use * 100) / heapSize); return ret; +#endif } void Free(Address address) { +#ifdef UC_NATIVE + //aligned_free(address); +#else //FIXME! +#endif } void* Memory(uint32_t address) { From 51b1a8e56da5ab9e84a8ab889975bac30aa31084 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 6 Jun 2019 19:02:02 +0200 Subject: [PATCH 10/64] Support identity map in native map (FIXME: probably should be fixup?) --- emulation.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/emulation.c b/emulation.c index 4756362..dce4ec4 100644 --- a/emulation.c +++ b/emulation.c @@ -361,6 +361,8 @@ void Free(Address address) { void* Memory(uint32_t address) { + uint32_t orig_address = address; + if (address >= heapAddress && address < (heapAddress + heapSize)) { return &heap[address - heapAddress]; } @@ -381,6 +383,11 @@ void* Memory(uint32_t address) { } } +#ifdef UC_NATIVE + if (orig_address >= 0x80000000) { + return orig_address; + } +#endif return NULL; } From 9089fb97590f5df2cf8ce23ec5c08e1393126fd8 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 6 Jun 2019 19:02:13 +0200 Subject: [PATCH 11/64] Free memory from HeapFree --- main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/main.c b/main.c index e9c8315..df73b7d 100644 --- a/main.c +++ b/main.c @@ -975,6 +975,11 @@ HACKY_IMPORT_BEGIN(HeapFree) hacky_printf("hHeap 0x%" PRIX32 "\n", stack[1]); hacky_printf("dwFlags 0x%" PRIX32 "\n", stack[2]); hacky_printf("lpMem 0x%" PRIX32 "\n", stack[3]); + + assert(stack[2] == 0x0); + + Free(stack[3]); + eax = 1; // nonzero if succeeds esp += 3 * 4; HACKY_IMPORT_END() From 8ec3d783f7e1f3d63965b9fac446a0f1eab523e7 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 10 Nov 2018 02:07:07 +0100 Subject: [PATCH 12/64] Support i386 linux again --- emulation.c | 41 +++++++++++++++++++++++++---------------- main.h | 4 ++++ uc_native.c | 19 +++++++++---------- uc_native.h | 7 +++++++ 4 files changed, 45 insertions(+), 26 deletions(-) diff --git a/emulation.c b/emulation.c index dce4ec4..4f344d7 100644 --- a/emulation.c +++ b/emulation.c @@ -39,11 +39,15 @@ static uint32_t tlsAddress = 0x83100000; //FIXME: No idea where to put this yet static uint32_t tlsSize = 0x1000; static uint32_t stackAddress = 0x83200000; // FIXME: Search free region instead..? -static uint32_t stackSize = 256 * 1024; // I've measured, and about 140k are in use at maximum +static uint32_t stackSize = 256 * 1024; // About 140k are in use at maximum #define HEAP_ADDRESS 0x81000000 static uint32_t heapAddress = HEAP_ADDRESS; -static uint32_t heapSize = 0x1000; //16 * 1024 * 1024; // 16 MiB +#if 0 //def UC_NATIVE +static uint32_t heapSize = 0x1000; // Dummy page +#else +static uint32_t heapSize = 16 * 1024 * 1024; // 16 MiB +#endif static uc_engine *uc; static uint32_t ucAlignment = 0x1000; @@ -323,7 +327,7 @@ void* MapMemory(uint32_t address, uint32_t size, bool read, bool write, bool exe } Address Allocate(Size size) { -#ifdef UC_NATIVE +#if 0 // def UC_NATIVE Address ret = aligned_malloc(0x1000, size); memset(Memory(ret), 0xDD, size); return ret; @@ -345,7 +349,7 @@ address &= 0xFFFFF000; assert(address < (HEAP_ADDRESS + heapSize)); int use = (address - HEAP_ADDRESS); - debugPrint("%u / %u = %u percent\n", use, heapSize, (use * 100) / heapSize); + printf("%u / %u = %u percent\n", use, heapSize, (use * 100) / heapSize); return ret; #endif @@ -395,10 +399,6 @@ void* Memory(uint32_t address) { #include "uc_native.h" #include -extern jmp_buf* host_jmp; -extern uint32_t guest_registers_esp; -extern Registers* guest_registers; -extern uint32_t host_esp; static uint32_t host_eip; #ifndef __stdcall @@ -406,6 +406,7 @@ static uint32_t host_eip; #endif +void __stdcall return_to_host() asm("return_to_host"); void __stdcall return_to_host() { guest_registers->esp = guest_registers_esp; guest_registers->eip = host_eip; @@ -421,24 +422,32 @@ void __stdcall return_to_host() { Address CreateHlt() { #ifdef UC_NATIVE - extern void(__stdcall __return_to_host)(); +#if 0 //def XBOX +#define __RETURN_TO_HOST_ENTRY "___return_to_host@0" +#define RETURN_TO_HOST "_return_to_host@0" +#else +#define __RETURN_TO_HOST_ENTRY "__return_to_host" +#define RETURN_TO_HOST "" +#endif + + extern void(__stdcall __return_to_host_entry)() asm("__return_to_host_entry"); asm("jmp continue\n" - ".global ___return_to_host@0\n" - "___return_to_host@0:\n" + ".global __return_to_host_entry\n" + "__return_to_host_entry:\n" // Keep a backup of the real guest ESP - "mov %%esp, _guest_registers_esp\n" + "mov %%esp, guest_registers_esp\n" // Fill guest_registers - "mov _guest_registers, %%esp\n" + "mov guest_registers, %%esp\n" "add $32, %%esp\n" "pusha\n" // Move to host space - "mov _host_esp, %%esp\n" + "mov host_esp, %%esp\n" "popa\n" - "call _return_to_host@0\n" + "call return_to_host\n" "continue:\n":); Address code_address = Allocate(20); @@ -453,7 +462,7 @@ Address CreateHlt() { code += 4; *code++ = 0xE9; // jmp __return_to_host - *(uint32_t*)code = (uintptr_t)__return_to_host - (uintptr_t)code - 4; + *(uint32_t*)code = (uintptr_t)__return_to_host_entry - (uintptr_t)code - 4; code += 4; #else Address code_address = Allocate(2); diff --git a/main.h b/main.h index 5b23b00..889c242 100644 --- a/main.h +++ b/main.h @@ -82,6 +82,10 @@ void AddExport(const char* name, void* callback, Address address); eip = returnAddress; \ esp += 4; \ +#ifndef XBOX +#define debugPrint(fmt, ...) (0) +#endif + #define HACKY_IMPORT_END() \ if (!silent) { \ hacky_printf("Stack at 0x%" PRIX32 "; returning EAX: 0x%08" PRIX32 "\n", stackAddress, eax); \ diff --git a/uc_native.c b/uc_native.c index 863464f..9a466f1 100644 --- a/uc_native.c +++ b/uc_native.c @@ -293,7 +293,7 @@ uc_err uc_reg_write(uc_engine *uc, int regid, const void *value) { } // Accessed via inline assembly -static uint32_t _begin; +static uint32_t _begin asm("_begin"); Registers* guest_registers; uint32_t guest_registers_esp; uint32_t host_esp; @@ -311,8 +311,8 @@ uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t time _begin = begin; -#ifdef XBOX -#else +// For Xbox we can use the existing FS (might get corrupted?) +#ifndef XBOX static struct user_desc ldt_desc; @@ -345,10 +345,9 @@ uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t time // Set FS to use our new thread area uint16_t seg = ldt_desc.entry_number; - asm("mov %[seg], %%ax\n" - "shl $3, %%ax\n" + asm("shl $3, %%ax\n" "or $0x3, %%ax\n" - "movw %%ax, %%fs\n"::[seg]"r"(seg)); + "movw %%ax, %%fs\n"::"a"(seg)); #endif #if 0 @@ -365,15 +364,15 @@ uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t time // Make host backup "pusha\n" - "mov %%esp, _host_esp\n" + "mov %%esp, host_esp\n" // Load all registers - "mov _guest_registers, %%esp\n" + "mov guest_registers, %%esp\n" "popa\n" - "mov _guest_registers_esp, %%esp\n" + "mov guest_registers_esp, %%esp\n" //FIXME: Fixup ESP too - "jmp *__begin\n":); + "jmp *_begin\n":); // This can never return, or setjmp / longjmp would break! assert(false); diff --git a/uc_native.h b/uc_native.h index 639e400..2a46484 100644 --- a/uc_native.h +++ b/uc_native.h @@ -28,4 +28,11 @@ typedef struct { } Registers; +#include + +extern jmp_buf* host_jmp; +extern uint32_t guest_registers_esp asm("guest_registers_esp"); +extern Registers* guest_registers asm("guest_registers"); +extern uint32_t host_esp asm("host_esp"); + #endif From 91299bd62e7b1fda8c851f5ce971e4231c1d73fa Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 10 Nov 2018 02:22:25 +0100 Subject: [PATCH 13/64] Little cleanup --- emulation.c | 12 ------------ main.h | 2 +- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/emulation.c b/emulation.c index 4f344d7..0b4972f 100644 --- a/emulation.c +++ b/emulation.c @@ -291,9 +291,6 @@ void* MapMemory(uint32_t address, uint32_t size, bool read, bool write, bool exe assert(size % ucAlignment == 0); #ifdef UC_NATIVE #ifdef XBOX -#if 0 - -#else void* memory; if(address & 0x80000000) { uint32_t base_address = address & 0x7FFFFFFF; @@ -308,7 +305,6 @@ void* MapMemory(uint32_t address, uint32_t size, bool read, bool write, bool exe assert(status == STATUS_SUCCESS); } printf("got %p == %p (%d bytes)?\n", memory, address, size); -#endif #else //FIXME: Respect protection void* memory = mmap(address, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_SHARED|MAP_FIXED, -1, 0); @@ -422,14 +418,6 @@ void __stdcall return_to_host() { Address CreateHlt() { #ifdef UC_NATIVE -#if 0 //def XBOX -#define __RETURN_TO_HOST_ENTRY "___return_to_host@0" -#define RETURN_TO_HOST "_return_to_host@0" -#else -#define __RETURN_TO_HOST_ENTRY "__return_to_host" -#define RETURN_TO_HOST "" -#endif - extern void(__stdcall __return_to_host_entry)() asm("__return_to_host_entry"); asm("jmp continue\n" ".global __return_to_host_entry\n" diff --git a/main.h b/main.h index 889c242..9fa51b7 100644 --- a/main.h +++ b/main.h @@ -83,7 +83,7 @@ void AddExport(const char* name, void* callback, Address address); esp += 4; \ #ifndef XBOX -#define debugPrint(fmt, ...) (0) +#define debugPrint(fmt, ...) printf(fmt, ##__VA_ARGS__) #endif #define HACKY_IMPORT_END() \ From ff45f364e1dc63d98d9a27d33bbaa57d10111e1d Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 10 Nov 2018 02:22:38 +0100 Subject: [PATCH 14/64] Report broken address mappings --- emulation.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/emulation.c b/emulation.c index 0b4972f..22719ba 100644 --- a/emulation.c +++ b/emulation.c @@ -361,8 +361,6 @@ void Free(Address address) { void* Memory(uint32_t address) { - uint32_t orig_address = address; - if (address >= heapAddress && address < (heapAddress + heapSize)) { return &heap[address - heapAddress]; } @@ -372,6 +370,7 @@ void* Memory(uint32_t address) { } if (address >= exe->peHeader.imageBase) { + uint32_t orig_address = address; address -= exe->peHeader.imageBase; for(unsigned int sectionIndex = 0; sectionIndex < exe->coffHeader.numberOfSections; sectionIndex++) { PeSection* section = &exe->sections[sectionIndex]; @@ -381,12 +380,22 @@ void* Memory(uint32_t address) { return &exe->mappedSections[sectionIndex][offset]; } } + address = orig_address; + } + + if (address == 0) { + return NULL; } #ifdef UC_NATIVE - if (orig_address >= 0x80000000) { - return orig_address; +#ifdef XBOX + if (address >= 0x80000000) { + return address; } +#else + printf("Unmapped 0x%X\n", address); + assert(false); +#endif #endif return NULL; } From 81e6d755f5398957db8977f0c6eaee4bb9df9128 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 10 Nov 2018 03:25:33 +0100 Subject: [PATCH 15/64] Make logs more similar and smaller memory changes --- emulation.c | 4 ++-- main.c | 2 ++ main.h | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/emulation.c b/emulation.c index 22719ba..34d030d 100644 --- a/emulation.c +++ b/emulation.c @@ -39,14 +39,14 @@ static uint32_t tlsAddress = 0x83100000; //FIXME: No idea where to put this yet static uint32_t tlsSize = 0x1000; static uint32_t stackAddress = 0x83200000; // FIXME: Search free region instead..? -static uint32_t stackSize = 256 * 1024; // About 140k are in use at maximum +static uint32_t stackSize = 256 * 1024; // About 140kiB are in use at maximum #define HEAP_ADDRESS 0x81000000 static uint32_t heapAddress = HEAP_ADDRESS; #if 0 //def UC_NATIVE static uint32_t heapSize = 0x1000; // Dummy page #else -static uint32_t heapSize = 16 * 1024 * 1024; // 16 MiB +static uint32_t heapSize = 14 * 1024 * 1024; // 16 MiB #endif static uc_engine *uc; diff --git a/main.c b/main.c index df73b7d..c84e90f 100644 --- a/main.c +++ b/main.c @@ -57,7 +57,9 @@ void AddExport(const char* name, void* callback, Address address) { Export* export = &exports[exportCount]; export->name = malloc(strlen(name) + 1); strcpy((char*)export->name, name); +#if 0 printf(" Stored '%s' at %p\n", export->name, export->name); +#endif export->callback = callback; export->address = 0; exportCount++; diff --git a/main.h b/main.h index 9fa51b7..2f57497 100644 --- a/main.h +++ b/main.h @@ -83,13 +83,13 @@ void AddExport(const char* name, void* callback, Address address); esp += 4; \ #ifndef XBOX -#define debugPrint(fmt, ...) printf(fmt, ##__VA_ARGS__) +#define debugPrint(fmt, ...) (0) #endif #define HACKY_IMPORT_END() \ if (!silent) { \ hacky_printf("Stack at 0x%" PRIX32 "; returning EAX: 0x%08" PRIX32 "\n", stackAddress, eax); \ - hacky_printf("%7" PRIu32 " Emulation at %X ('%s') from %X\n\n", callId, eip, (char*)_user_data, returnAddress); \ + hacky_printf("%" PRIu32 " Emulation at %X ('%s') from %X\n\n", callId, eip, (char*)_user_data, returnAddress); \ debugPrint("%u\n", callId); \ } \ callId++; \ From eb94649cb55e00ef67fce6651d87caae11146931 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 6 Jun 2019 18:37:01 +0200 Subject: [PATCH 16/64] hack: Use safe stack region --- emulation.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/emulation.c b/emulation.c index 34d030d..ad4e210 100644 --- a/emulation.c +++ b/emulation.c @@ -39,7 +39,7 @@ static uint32_t tlsAddress = 0x83100000; //FIXME: No idea where to put this yet static uint32_t tlsSize = 0x1000; static uint32_t stackAddress = 0x83200000; // FIXME: Search free region instead..? -static uint32_t stackSize = 256 * 1024; // About 140kiB are in use at maximum +static uint32_t stackSize = 700 * 1024; // About 140kiB are in use at maximum #define HEAP_ADDRESS 0x81000000 static uint32_t heapAddress = HEAP_ADDRESS; @@ -678,7 +678,7 @@ unsigned int CreateEmulatedThread(uint32_t eip) { stack = MapMemory(stackAddress, stackSize, true, true, false); } static int threadId = 0; - uint32_t esp = stackAddress + stackSize; + uint32_t esp = stackAddress + stackSize / 2; assert(threadId < 4); threads = realloc(threads, ++threadCount * sizeof(ThreadContext)); From 713c941567a1e8532626a1e4ff81e1011916d939 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 6 Jun 2019 18:37:34 +0200 Subject: [PATCH 17/64] Swap host and guest FS --- emulation.c | 4 ++++ uc_native.c | 5 +++++ uc_native.h | 1 + 3 files changed, 10 insertions(+) diff --git a/emulation.c b/emulation.c index ad4e210..0f78923 100644 --- a/emulation.c +++ b/emulation.c @@ -440,6 +440,10 @@ Address CreateHlt() { "add $32, %%esp\n" "pusha\n" + // Move to host fs + "mov host_fs, %%eax\n" + "mov %%eax, %%fs:0\n" + // Move to host space "mov host_esp, %%esp\n" "popa\n" diff --git a/uc_native.c b/uc_native.c index 9a466f1..ad1cd8e 100644 --- a/uc_native.c +++ b/uc_native.c @@ -297,6 +297,7 @@ static uint32_t _begin asm("_begin"); Registers* guest_registers; uint32_t guest_registers_esp; uint32_t host_esp; +uint32_t host_fs; jmp_buf* host_jmp; uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count) { @@ -366,6 +367,10 @@ uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t time "pusha\n" "mov %%esp, host_esp\n" + // Get host fs stuff + "mov %%fs:0, %%eax\n" + "mov %%eax, host_fs\n" + // Load all registers "mov guest_registers, %%esp\n" "popa\n" diff --git a/uc_native.h b/uc_native.h index 2a46484..e91fe55 100644 --- a/uc_native.h +++ b/uc_native.h @@ -34,5 +34,6 @@ extern jmp_buf* host_jmp; extern uint32_t guest_registers_esp asm("guest_registers_esp"); extern Registers* guest_registers asm("guest_registers"); extern uint32_t host_esp asm("host_esp"); +extern uint32_t host_fs asm("host_fs"); #endif From 43e24711c34749877d3791a3b1d955c0d330f81c Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 6 Jun 2019 18:37:49 +0200 Subject: [PATCH 18/64] hack: Print memory stats --- emulation.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/emulation.c b/emulation.c index 0f78923..f3af033 100644 --- a/emulation.c +++ b/emulation.c @@ -710,6 +710,31 @@ static unsigned int GetThreadCount() { return threadCount; } +static void memory_statistics() { +#if 0 + printf("Memory statistics:\n"); +#ifdef XBOX + MM_STATISTICS ms; + ms.Length = sizeof(MM_STATISTICS); + MmQueryStatistics(&ms); + #define PRINT(stat) printf("- " #stat ": %d\n", ms.stat); + PRINT(TotalPhysicalPages) + PRINT(AvailablePages) + PRINT(VirtualMemoryBytesCommitted) + PRINT(VirtualMemoryBytesReserved) + PRINT(CachePagesCommitted) + PRINT(PoolPagesCommitted) + PRINT(StackPagesCommitted) + PRINT(ImagePagesCommitted) + #undef PRINT +#endif + + uint32_t esp; + asm("mov %%esp, %%eax":"=a"(esp)); + printf("- Stack: 0x%X\n", esp); +#endif +} + void RunEmulation() { uc_err err; @@ -733,6 +758,9 @@ void RunEmulation() { TransferContext(ctx, true); while(true) { + + memory_statistics(); + err = uc_emu_start(uc, ctx->eip, 0, 0, 0); // Finish profiling, if we have partial data From dbcb69abe35260005a9f281805a2759347fcb315 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 6 Jun 2019 18:38:13 +0200 Subject: [PATCH 19/64] Set stdout and stderr to unbuffered --- main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/main.c b/main.c index c84e90f..aed587f 100644 --- a/main.c +++ b/main.c @@ -4062,6 +4062,10 @@ int main(int argc, char* argv[]) { // Clear log FILE* f = fopen("log.txt", "wb"); fclose(f); +#else + //dup2(stdout, stderr); + setbuf(stdout, 0); + setbuf(stderr, 0); #endif From 2b56f8fa77589cb416b84e9cfd95784988603909 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 6 Jun 2019 18:38:31 +0200 Subject: [PATCH 20/64] fixup: set sdl keys to zero in xbox --- xbox.c | 1 + 1 file changed, 1 insertion(+) diff --git a/xbox.c b/xbox.c index f75a7a1..d009fc6 100644 --- a/xbox.c +++ b/xbox.c @@ -585,6 +585,7 @@ int SDL_Delay(int a0) { int SDL_GetKeyboardState(int a0) { printf("%s\n", __func__); static unsigned char keys[256]; + memset(keys, 0x00, sizeof(keys)); return keys; } From 4d22fd3bb6c14ef932d9f3331a56d5de80108897 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sun, 11 Nov 2018 04:07:41 +0100 Subject: [PATCH 21/64] Use host mapping --- common.h | 7 +++--- emulation.c | 62 +++++++++++++++++++++++++++++++---------------------- 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/common.h b/common.h index 89b804a..5f78f25 100644 --- a/common.h +++ b/common.h @@ -8,13 +8,12 @@ #include #include -#if defined(_WIN32) #if defined(XBOX) # include -#else +#elif defined(_WIN32) # include -#endif #else +# include # include #endif @@ -44,7 +43,9 @@ static void* aligned_malloc(size_t alignment, size_t size) { ptr = _aligned_malloc(size, alignment); #else posix_memalign(&ptr, alignment, size); + mprotect(ptr, size, PROT_READ | PROT_WRITE | PROT_EXEC); #endif + assert(ptr <= 0xFFFFFFFF); assert(ptr != NULL); return ptr; } diff --git a/emulation.c b/emulation.c index f3af033..795cb84 100644 --- a/emulation.c +++ b/emulation.c @@ -23,7 +23,9 @@ #ifdef XBOX #include #else +#include #include +#include #endif #endif @@ -39,14 +41,14 @@ static uint32_t tlsAddress = 0x83100000; //FIXME: No idea where to put this yet static uint32_t tlsSize = 0x1000; static uint32_t stackAddress = 0x83200000; // FIXME: Search free region instead..? -static uint32_t stackSize = 700 * 1024; // About 140kiB are in use at maximum +static uint32_t stackSize = 200 * 1024; // About 140kiB are in use at maximum #define HEAP_ADDRESS 0x81000000 static uint32_t heapAddress = HEAP_ADDRESS; -#if 0 //def UC_NATIVE +#ifdef UC_NATIVE static uint32_t heapSize = 0x1000; // Dummy page #else -static uint32_t heapSize = 14 * 1024 * 1024; // 16 MiB +static uint32_t heapSize = 20 * 1024 * 1024; // 16 MiB #endif static uc_engine *uc; @@ -307,7 +309,17 @@ void* MapMemory(uint32_t address, uint32_t size, bool read, bool write, bool exe printf("got %p == %p (%d bytes)?\n", memory, address, size); #else //FIXME: Respect protection + Size page_size = sysconf(_SC_PAGE_SIZE); + Address check_address = address; + while(check_address <= (address + size)) { + int ret = msync(check_address, page_size, MS_ASYNC); + assert((ret == -1) && (errno == ENOMEM)); + check_address += page_size; + } void* memory = mmap(address, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_SHARED|MAP_FIXED, -1, 0); + + + memory = mmap(address, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_SHARED|MAP_FIXED, -1, 0); #endif assert(memory == address); #else @@ -323,37 +335,40 @@ void* MapMemory(uint32_t address, uint32_t size, bool read, bool write, bool exe } Address Allocate(Size size) { -#if 0 // def UC_NATIVE +#ifdef UC_NATIVE Address ret = aligned_malloc(0x1000, size); - memset(Memory(ret), 0xDD, size); - return ret; #else static uint32_t address = HEAP_ADDRESS; - uint32_t ret = address; - address += size; -#if 1 - // Debug memset to detect memory errors - memset(Memory(ret), 0xDD, size); -#endif - //FIXME: Proper allocator #if 1 -//FIXME: This is a hack to fix alignment + to avoid too small allocations -address += 0x1000; -address &= 0xFFFFF000; + //FIXME: This is a hack to fix alignment + to avoid too small allocations + address += 0xFFF; + address &= 0xFFFFF000; #endif + Address ret = address; + + address += size; + //FIXME: Proper allocator + assert(address < (HEAP_ADDRESS + heapSize)); int use = (address - HEAP_ADDRESS); printf("%u / %u = %u percent\n", use, heapSize, (use * 100) / heapSize); +#endif - return ret; + assert(ret != 0); + +#if 1 + // Debug memset to detect memory errors + memset(Memory(ret), 0xDD, size); #endif + + return ret; } void Free(Address address) { #ifdef UC_NATIVE - //aligned_free(address); + aligned_free(address); #else //FIXME! #endif @@ -388,14 +403,10 @@ void* Memory(uint32_t address) { } #ifdef UC_NATIVE -#ifdef XBOX - if (address >= 0x80000000) { - return address; - } + return address; #else printf("Unmapped 0x%X\n", address); assert(false); -#endif #endif return NULL; } @@ -415,7 +426,6 @@ void __stdcall return_to_host() asm("return_to_host"); void __stdcall return_to_host() { guest_registers->esp = guest_registers_esp; guest_registers->eip = host_eip; - printf("yay 0x%08X\n", guest_registers->eip); #if 0 asm("mov $0, %%ax\n" "mov %%ax, %%fs\n":); @@ -682,7 +692,7 @@ unsigned int CreateEmulatedThread(uint32_t eip) { stack = MapMemory(stackAddress, stackSize, true, true, false); } static int threadId = 0; - uint32_t esp = stackAddress + stackSize / 2; + uint32_t esp = stackAddress + stackSize - 1024; // We give 1k of headroom assert(threadId < 4); threads = realloc(threads, ++threadCount * sizeof(ThreadContext)); @@ -711,7 +721,7 @@ static unsigned int GetThreadCount() { } static void memory_statistics() { -#if 0 +#if 1 printf("Memory statistics:\n"); #ifdef XBOX MM_STATISTICS ms; From 75b76b805cea8faf4d7883b877d4ea16c339e213 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sun, 11 Nov 2018 04:08:02 +0100 Subject: [PATCH 22/64] Keep copy of EFLAGS and FPU (should fix stability issues) --- emulation.c | 10 ++++++++-- uc_native.c | 37 ++++++++++++++++++++++++------------- uc_native.h | 13 +++++++++---- 3 files changed, 41 insertions(+), 19 deletions(-) diff --git a/emulation.c b/emulation.c index 795cb84..9023670 100644 --- a/emulation.c +++ b/emulation.c @@ -447,9 +447,13 @@ Address CreateHlt() { // Fill guest_registers "mov guest_registers, %%esp\n" - "add $32, %%esp\n" + "add $36, %%esp\n" + "pushf\n" "pusha\n" + // Fill guest_registers_fpu + "fxsave guest_registers_fpu\n" + // Move to host fs "mov host_fs, %%eax\n" "mov %%eax, %%fs:0\n" @@ -457,9 +461,11 @@ Address CreateHlt() { // Move to host space "mov host_esp, %%esp\n" "popa\n" + "popf\n" + "fxrstor host_registers_fpu\n" "call return_to_host\n" - "continue:\n":); + "continue:\n":::"eax", "esp", "memory"); Address code_address = Allocate(20); uint8_t* code = Memory(code_address); diff --git a/uc_native.c b/uc_native.c index ad1cd8e..f90adb5 100644 --- a/uc_native.c +++ b/uc_native.c @@ -23,6 +23,16 @@ #include "uc_native.h" +// Accessed via inline assembly +static uint32_t _begin asm("_begin"); +Registers* guest_registers; +uint8_t guest_registers_fpu[512] __attribute__((aligned(16))); +uint8_t host_registers_fpu[512] __attribute__((aligned(16))); +uint32_t guest_registers_esp; +uint32_t host_esp; +uint32_t host_fs; +jmp_buf* host_jmp; + typedef struct { jmp_buf jmp; Registers registers; @@ -190,6 +200,12 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **uc) { } #endif + // Re-initialize a fresh FPU + asm("fxsave host_registers_fpu\n" + "finit\n" + "fxsave guest_registers_fpu\n" + "fxrstor host_registers_fpu\n":); + *uc = (uc_engine*)u; return 0; } @@ -292,14 +308,6 @@ uc_err uc_reg_write(uc_engine *uc, int regid, const void *value) { return 0; } -// Accessed via inline assembly -static uint32_t _begin asm("_begin"); -Registers* guest_registers; -uint32_t guest_registers_esp; -uint32_t host_esp; -uint32_t host_fs; -jmp_buf* host_jmp; - uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count) { uc_engine_native* u = (uc_engine_native*)uc; printf("uc_emu_start\n"); @@ -360,10 +368,9 @@ uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t time guest_registers = &u->registers; guest_registers_esp = guest_registers->esp; - asm volatile(// "int3\n" - //"movl fs, 32([registers])" - - // Make host backup + asm volatile(// Make host backup + "fxsave host_registers_fpu\n" + "pushf\n" "pusha\n" "mov %%esp, host_esp\n" @@ -374,10 +381,14 @@ uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t time // Load all registers "mov guest_registers, %%esp\n" "popa\n" + "popf\n" "mov guest_registers_esp, %%esp\n" //FIXME: Fixup ESP too - "jmp *_begin\n":); + // Load FPU registers + "fxrstor guest_registers_fpu\n" + + "jmp *_begin\n":::"eax", "esp", "memory"); // This can never return, or setjmp / longjmp would break! assert(false); diff --git a/uc_native.h b/uc_native.h index e91fe55..31eaf75 100644 --- a/uc_native.h +++ b/uc_native.h @@ -19,12 +19,15 @@ typedef struct { uint32_t ecx; // +24 uint32_t eax; // +28 + // Hack because we always do pusha and pushf in sequence + uint32_t eflags; // +32 + // Extensions, can be re-ordered / added / removed, but assembly needs update - uint16_t fs; // +32 - uint16_t pad; // +34 - uint32_t eip; // +36 + uint16_t fs; // +36 + uint16_t pad; // +40 + uint32_t eip; // +44 - uint32_t fs_base; //+40 + uint32_t fs_base; //+48 } Registers; @@ -33,6 +36,8 @@ typedef struct { extern jmp_buf* host_jmp; extern uint32_t guest_registers_esp asm("guest_registers_esp"); extern Registers* guest_registers asm("guest_registers"); +extern uint8_t guest_registers_fpu[512] asm("guest_registers_fpu"); +extern uint8_t host_registers_fpu[512] asm("host_registers_fpu"); extern uint32_t host_esp asm("host_esp"); extern uint32_t host_fs asm("host_fs"); From c4154dd006e3295a159947785baae8946642c1f6 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Mon, 12 Nov 2018 02:58:18 +0100 Subject: [PATCH 23/64] Use custom allocator in CreateHlt --- emulation.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/emulation.c b/emulation.c index 9023670..f24fb0a 100644 --- a/emulation.c +++ b/emulation.c @@ -437,6 +437,23 @@ void __stdcall return_to_host() { Address CreateHlt() { #ifdef UC_NATIVE + unsigned int code_size = 20; + +#if 0 + Address code_address = Allocate(20); +#else + static Address buffer; + static int buffer_size = 0; + if (buffer_size < code_size) { + buffer_size = 0x1000; + buffer = Allocate(buffer_size); + } + Address code_address = buffer; + buffer += code_size; + buffer_size -= code_size; +#endif + + extern void(__stdcall __return_to_host_entry)() asm("__return_to_host_entry"); asm("jmp continue\n" ".global __return_to_host_entry\n" @@ -467,7 +484,6 @@ Address CreateHlt() { "call return_to_host\n" "continue:\n":::"eax", "esp", "memory"); - Address code_address = Allocate(20); uint8_t* code = Memory(code_address); *code++ = 0x90; // Marker From 9fbcf1afa7ab82374eb50f510ee97b5177f35416 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Mon, 12 Nov 2018 03:13:05 +0100 Subject: [PATCH 24/64] Map memory in LoadSection --- main.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/main.c b/main.c index aed587f..1312979 100644 --- a/main.c +++ b/main.c @@ -257,7 +257,8 @@ void LoadSection(Exe* exe, unsigned int sectionIndex) { PeSection* section = &exe->sections[sectionIndex]; // Map memory for section - uint8_t* mem = (uint8_t*)aligned_malloc(0x1000, section->virtualSize); + uint32_t base = exe->peHeader.imageBase + section->virtualAddress; + uint8_t* mem = MapMemory(base, AlignUp(section->virtualSize, exe->peHeader.sectionAlignment), true, true, true); // Read data from exe and fill rest of space with zero fseek(exe->f, section->rawAddress, SEEK_SET); @@ -4006,22 +4007,6 @@ void UnloadExe(Exe* exe) { //FIXME: Abstract exe mapping and context creation from emu kickoff void RunX86(Exe* exe) { - // Map the important exe parts into emu memory - for(unsigned int sectionIndex = 0; sectionIndex < exe->coffHeader.numberOfSections; sectionIndex++) { - PeSection* section = &exe->sections[sectionIndex]; - void** mappedSection = (void**)&exe->mappedSections[sectionIndex]; - if (*mappedSection != NULL) { - uint32_t base = exe->peHeader.imageBase + section->virtualAddress; - printf("Mapping 0x%" PRIX32 " - 0x%" PRIX32 "\n", base, base + section->virtualSize - 1); - void* relocatedMappedSection = MapMemory(base, AlignUp(section->virtualSize, exe->peHeader.sectionAlignment), true, true, true); - memcpy(relocatedMappedSection, *mappedSection, section->virtualSize); - //FIXME: Can't free this :( - // This is used by some of the code [export->name most importantly] - //aligned_free(*mappedSection); - *mappedSection = relocatedMappedSection; - } - } - //FIXME: Schedule a virtual main-thread printf("Emulation starting\n"); CreateEmulatedThread(exe->peHeader.imageBase + exe->peHeader.addressOfEntryPoint); From fbe1308bff0b428f591bca30cca85fe33c245e29 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Tue, 13 Nov 2018 01:58:11 +0100 Subject: [PATCH 25/64] Some better printf debugging --- emulation.c | 3 +++ uc_native.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/emulation.c b/emulation.c index f24fb0a..5a860c9 100644 --- a/emulation.c +++ b/emulation.c @@ -791,6 +791,9 @@ void RunEmulation() { while(true) { +#ifdef XBOX + //debugClearScreen(); +#endif memory_statistics(); err = uc_emu_start(uc, ctx->eip, 0, 0, 0); diff --git a/uc_native.c b/uc_native.c index f90adb5..f297596 100644 --- a/uc_native.c +++ b/uc_native.c @@ -315,8 +315,8 @@ uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t time host_jmp = &u->jmp; if (setjmp(*host_jmp) == 0) { - - printf("Doing some bullshit\n"); +extern uint32_t callId; + printf("Doing some bullshit %d at 0x%08X\n", callId, begin); _begin = begin; From 0974f6cedad8d1dbcd3952fe11ddab9f460e9845 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 15 Nov 2018 05:44:51 +0100 Subject: [PATCH 26/64] Allow non-native compilation again --- CMakeLists.txt | 60 +++++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index abef0d6..281d110 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,42 +78,46 @@ target_include_directories(openswe1r PRIVATE ${CMAKE_BINARY_DIR}) include(package.cmake) -if(USE_VM) - target_compile_definitions(openswe1r PUBLIC -DUC_KVM) -# target_sources(openswe1r PUBLIC -# uc_kvm.c -# ) -else() - target_link_libraries(openswe1r - ${LIBUNICORN_LIBRARY} +if(USE_NATIVE) + + target_sources(openswe1r PUBLIC + uc_native.c + xbox.c ) -endif() + target_compile_definitions(openswe1r PUBLIC -DUC_NATIVE -DUC_KVM) -#if(ENET_FOUND) -# target_compile_definitions(openswe1r PUBLIC -DDPLAY_ENET) -# target_link_libraries(openswe1r -# ${ENET_LIBRARIES} -# ) -#endif() + set_target_properties(openswe1r PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32 -static-libgcc") -#target_link_libraries(openswe1r -# ${OPENGL_LIBRARIES} -# ${GLEW_LIBRARIES} -# ${SDL2_LIBRARY} -# ${OPENAL_LIBRARY} -#) +else() + if(USE_VM) + target_compile_definitions(openswe1r PUBLIC -DUC_KVM) + target_sources(openswe1r PUBLIC + uc_kvm.c + ) + else() + target_link_libraries(openswe1r + ${LIBUNICORN_LIBRARY} + ) + endif() -target_sources(openswe1r PUBLIC - uc_native.c - xbox.c -) -target_compile_definitions(openswe1r PUBLIC -DUC_NATIVE) + if(ENET_FOUND) + target_compile_definitions(openswe1r PUBLIC -DDPLAY_ENET) + target_link_libraries(openswe1r + ${ENET_LIBRARIES} + ) + endif() + + target_link_libraries(openswe1r + ${OPENGL_LIBRARIES} + ${GLEW_LIBRARIES} + ${SDL2_LIBRARY} + ${OPENAL_LIBRARY} + ) +endif() if(MSVC) # Silence MSVC CRT security warnings target_compile_definitions(openswe1r PRIVATE _CRT_SECURE_NO_WARNINGS) endif() - -set_target_properties(openswe1r PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32 -static-libgcc") From c82db03319fdee702fc9bce864ff2d5efaf0fce8 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 8 Jun 2019 16:14:30 +0200 Subject: [PATCH 27/64] CMake build system hacks? --- CMakeLists.txt | 2 +- Makefile.xbox | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 281d110..2ddd145 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,7 +86,7 @@ if(USE_NATIVE) ) target_compile_definitions(openswe1r PUBLIC -DUC_NATIVE -DUC_KVM) - set_target_properties(openswe1r PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32 -static-libgcc") + set_target_properties(openswe1r PROPERTIES COMPILE_FLAGS "-m32 -O0" LINK_FLAGS "-m32 -static-libgcc -O0") else() diff --git a/Makefile.xbox b/Makefile.xbox index df71bbc..4009796 100644 --- a/Makefile.xbox +++ b/Makefile.xbox @@ -31,4 +31,6 @@ CFLAGS += -DXBOX -DAPIENTRY= -DGLAPI= SDL_DIR = $(NXDK_DIR)/lib/sdl/SDL2 CFLAGS += -I$(SDL_DIR)/include +CFLAGS += -Wno-inconsistent-dllimport + include $(NXDK_DIR)/Makefile From 754fda6a4bbe4c6a894bb4eed2b8772cb2a19f5e Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 8 Jun 2019 16:15:34 +0200 Subject: [PATCH 28/64] Lower file handle count (FIXME: move to other branch + set higher) --- main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.c b/main.c index 1312979..5754ec0 100644 --- a/main.c +++ b/main.c @@ -921,7 +921,7 @@ HACKY_IMPORT_BEGIN(wsprintfA) printf("Out: '%s'\n", out); HACKY_IMPORT_END() -FILE* handles[10000]; +FILE* handles[4096]; uint32_t handle_index = 1; HACKY_IMPORT_BEGIN(CreateFileA) From a8eefa0b8d456e1497e8eb09e6ab366ee104a9aa Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 8 Jun 2019 16:16:56 +0200 Subject: [PATCH 29/64] Assert on MapMemory error --- emulation.c | 1 + 1 file changed, 1 insertion(+) diff --git a/emulation.c b/emulation.c index 5a860c9..8dc286a 100644 --- a/emulation.c +++ b/emulation.c @@ -329,6 +329,7 @@ void* MapMemory(uint32_t address, uint32_t size, bool read, bool write, bool exe err = uc_mem_map_ptr(uc, address, size, UC_PROT_ALL, memory); if (err) { printf("Failed on uc_mem_map_ptr() with error returned %u: %s\n", err, uc_strerror(err)); + assert(false); } //FIXME: Add to mapped memory list return memory; From 5ae17a0d7dac64f8f143d3898a5a2283b9aec7cf Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 8 Jun 2019 16:18:06 +0200 Subject: [PATCH 30/64] Fixups for xbox.c stubs --- xbox.c | 114 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 69 insertions(+), 45 deletions(-) diff --git a/xbox.c b/xbox.c index d009fc6..7acd377 100644 --- a/xbox.c +++ b/xbox.c @@ -17,6 +17,11 @@ #include "xbox.h" +//typedef uint8_t Uint8; +//typedef uint32_t Uint32; + +#include "SDL.h" + @@ -331,27 +336,27 @@ GLAPI void GLAPIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei heigh -GLAPI void GLAPIENTRY _glActiveTexture(unsigned int a0) { +GLAPI void GLAPIENTRY _glActiveTexture(GLenum texture) { printf("%s\n", __func__); return; } -GLAPI void GLAPIENTRY _glAttachShader(int a0) { +GLAPI void GLAPIENTRY _glAttachShader(GLuint program, GLuint shader) { printf("%s\n", __func__); return; } -void GLAPIENTRY _glBindBuffer(GLenum target, GLuint buffer) { +GLAPI void GLAPIENTRY _glBindBuffer(GLenum target, GLuint buffer) { printf("%s\n", __func__); return; } -void GLAPIENTRY _glBindVertexArray(int a0) { +GLAPI void GLAPIENTRY _glBindVertexArray(GLuint array) { printf("%s\n", __func__); return; } -void GLAPIENTRY _glBufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage) { +GLAPI void GLAPIENTRY _glBufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage) { printf("%s\n", __func__); if (target == GL_ELEMENT_ARRAY_BUFFER) { element_array_buffer = realloc(element_array_buffer, size); @@ -359,38 +364,40 @@ void GLAPIENTRY _glBufferData(GLenum target, GLsizeiptr size, const void* data, } else if (target == GL_ARRAY_BUFFER) { array_buffer = realloc(array_buffer, size); memcpy(array_buffer, data, size); + } else if (target == GL_PIXEL_UNPACK_BUFFER) { + //FIXME: !!! } else { assert(false); } return; } -GLAPI void GLAPIENTRY _glClearDepthf(int a0) { +GLAPI void GLAPIENTRY _glClearDepthf(GLfloat depth) { printf("%s\n", __func__); return; } -GLAPI void GLAPIENTRY _glCompileShader(int a0) { +GLAPI void GLAPIENTRY _glCompileShader(GLuint shader) { printf("%s\n", __func__); return; } -GLAPI void GLAPIENTRY _glCreateProgram(int a0) { +GLAPI GLuint GLAPIENTRY _glCreateProgram(void) { printf("%s\n", __func__); - return; + return 1; } -GLAPI void GLAPIENTRY _glCreateShader(int a0) { +GLAPI GLuint GLAPIENTRY _glCreateShader(GLenum shaderType) { printf("%s\n", __func__); - return; + return 1; } -GLAPI void GLAPIENTRY _glDebugMessageInsert(int a0) { +GLAPI void GLAPIENTRY _glDebugMessageInsert(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char *message) { printf("%s\n", __func__); return; } -GLAPI void GLAPIENTRY _glEnableVertexAttribArray(int a0) { +GLAPI void GLAPIENTRY _glEnableVertexAttribArray(GLuint index) { printf("%s\n", __func__); return; } @@ -405,9 +412,19 @@ GLAPI void GLAPIENTRY _glGenVertexArrays(int a0, unsigned int* a1) { return; } -GLAPI void GLAPIENTRY _glGetAttribLocation(int a0) { +GLAPI GLint GLAPIENTRY _glGetAttribLocation(GLuint program, const GLchar *name) { printf("%s\n", __func__); - return; + return (GLint)name; +} + +GLAPI void * GLAPIENTRY _glMapBuffer(GLenum target, GLenum access) { + printf("%s\n", __func__); + return 0; +} + +GLAPI GLboolean GLAPIENTRY _glUnmapBuffer(GLenum target) { + printf("%s\n", __func__); + return 0; } GLAPI void GLAPIENTRY _glewGetErrorString(int a0) { @@ -415,7 +432,7 @@ GLAPI void GLAPIENTRY _glewGetErrorString(int a0) { return; } -GLAPI void GLAPIENTRY _glGetProgramInfoLog(int a0) { +GLAPI void GLAPIENTRY _glGetProgramInfoLog(GLuint program, GLsizei maxLength, GLsizei *length, GLchar *infoLog) { printf("%s\n", __func__); return; } @@ -426,42 +443,42 @@ GLAPI void GLAPIENTRY _glGetProgramiv(GLuint program, GLenum pname, GLint* param return; } -GLAPI void GLAPIENTRY _glGetShaderInfoLog(int a0) { +GLAPI void GLAPIENTRY _glGetShaderInfoLog(GLuint shader, GLsizei maxLength, GLsizei *length, GLchar *infoLog) { printf("%s\n", __func__); return; } -GLAPI void GLAPIENTRY _glGetShaderiv(int a0) { +GLAPI void GLAPIENTRY _glGetShaderiv(GLuint shader, GLenum pname, GLint *params) { printf("%s\n", __func__); return; } GLAPI GLint GLAPIENTRY _glGetUniformLocation(GLuint program, const GLchar *name) { printf("%s\n", __func__); - return name; + return (GLint)name; } -GLAPI void GLAPIENTRY _glLinkProgram(int a0) { +GLAPI void GLAPIENTRY _glLinkProgram(GLuint program) { printf("%s\n", __func__); return; } -GLAPI void GLAPIENTRY _glShaderSource(int a0) { +GLAPI void GLAPIENTRY _glShaderSource(GLuint shader, GLsizei count, const GLchar * const*string, const GLint *length) { printf("%s\n", __func__); return; } -GLAPI void GLAPIENTRY _glUniform1f(int a0) { +GLAPI void GLAPIENTRY _glUniform1f(GLint location, GLfloat v0) { printf("%s\n", __func__); return; } -GLAPI void GLAPIENTRY _glUniform1i(int a0) { +GLAPI void GLAPIENTRY _glUniform1i(GLint location, GLint v0) { printf("%s\n", __func__); return; } -GLAPI void GLAPIENTRY _glUniform3f(int a0) { +GLAPI void GLAPIENTRY _glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) { printf("%s\n", __func__); return; } @@ -484,7 +501,7 @@ GLAPI void GLAPIENTRY _glUniformMatrix4fv(int a0, int a1, unsigned char a2, c return; } -GLAPI void GLAPIENTRY _glUseProgram(unsigned int a0) { +GLAPI void GLAPIENTRY _glUseProgram(GLuint program) { printf("%s\n", __func__); return; } @@ -531,6 +548,8 @@ GLEW_FUN_EXPORT PFNGLSHADERSOURCEPROC __glewShaderSource = _glShaderSource; GLEW_FUN_EXPORT PFNGLCREATEPROGRAMPROC __glewCreateProgram = _glCreateProgram; GLEW_FUN_EXPORT PFNGLCREATESHADERPROC __glewCreateShader = _glCreateShader; GLEW_FUN_EXPORT PFNGLGETSHADERIVPROC __glewGetShaderiv = _glGetShaderiv; +GLEW_FUN_EXPORT PFNGLMAPBUFFERPROC __glewMapBuffer = _glMapBuffer; +GLEW_FUN_EXPORT PFNGLUNMAPBUFFERPROC __glewUnmapBuffer = _glUnmapBuffer; GLEWAPI GLboolean glewExperimental = GL_FALSE; @@ -572,75 +591,80 @@ int pthread_sigmask(int a0) { #if 1 //#ifndef XBOX -int SDL_CreateWindow(int a0) { +SDL_Window* SDL_CreateWindow(const char* title, + int x, + int y, + int w, + int h, + Uint32 flags) { printf("%s\n", __func__); return 1; } -int SDL_Delay(int a0) { +void SDL_Delay(Uint32 ms) { printf("%s\n", __func__); - return 0; + return; } -int SDL_GetKeyboardState(int a0) { +const Uint8* SDL_GetKeyboardState(int* numkeys) { printf("%s\n", __func__); static unsigned char keys[256]; memset(keys, 0x00, sizeof(keys)); return keys; } -int SDL_GetMouseState(int a0) { +Uint32 SDL_GetMouseState(int* x, int* y) { printf("%s\n", __func__); return 0; } -int SDL_GetPerformanceCounter(int a0) { +Uint32 SDL_GetTicks(void) { printf("%s\n", __func__); - return SDL_GetTicks(); + static int t = 0; + return t++; } -int SDL_GetPerformanceFrequency(int a0) { +Uint64 SDL_GetPerformanceCounter(void) { printf("%s\n", __func__); - return 1; + return SDL_GetTicks(); } -int SDL_GetTicks(int a0) { +Uint64 SDL_GetPerformanceFrequency(void) { printf("%s\n", __func__); - static int t = 0; - return t++; + return 1; } -int SDL_GL_CreateContext(int a0) { +SDL_GLContext SDL_GL_CreateContext(SDL_Window* window) { printf("%s\n", __func__); return 1; } -int SDL_GL_SetAttribute(int a0, int a1) { +int SDL_GL_SetAttribute(SDL_GLattr attr, int value) { printf("%s\n", __func__); return 0; } -int SDL_GL_SwapWindow(int a0) { +void SDL_GL_SwapWindow(SDL_Window* window) { printf("%s\n", __func__); saveBuffer(); - return 0; + return; } -int SDL_Init(int a0) { +int SDL_Init(Uint32 flags) { printf("%s\n", __func__); return 0; } -int SDL_PollEvent(int a0) { +int SDL_PollEvent(SDL_Event* event) { printf("%s\n", __func__); return 0; } -int SDL_ShowWindow(int a0) { +void SDL_ShowWindow(SDL_Window* window) { printf("%s\n", __func__); - return 0; + return; } #endif From 88153c750d2dbba8c6676a5a8f4e000286c8d061 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 8 Jun 2019 16:21:15 +0200 Subject: [PATCH 31/64] Do reference-counting --- com/a3d.c | 4 ++-- com/d3d.h | 2 +- com/ddraw.h | 2 +- main.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++- windows.h | 6 ++++++ 5 files changed, 61 insertions(+), 5 deletions(-) diff --git a/com/a3d.c b/com/a3d.c index 5cdf154..533a85b 100644 --- a/com/a3d.c +++ b/com/a3d.c @@ -15,7 +15,7 @@ typedef struct { - void* vtable; + API(IUnknown) iunknown; ALCdevice *device; ALCcontext *context; } A3d4; @@ -32,7 +32,7 @@ typedef struct { } API(WAVEFORMATEX); typedef struct { - void* vtable; + API(IUnknown) iunknown; ALuint al_source; ALuint al_buffer; API(WAVEFORMATEX) fmt; diff --git a/com/d3d.h b/com/d3d.h index 3dc0ae1..c512600 100644 --- a/com/d3d.h +++ b/com/d3d.h @@ -11,7 +11,7 @@ #include "../windows.h" typedef struct { - void* vtable; + API(IUnknown) iunknown; Address surface; GLuint handle; } API(Direct3DTexture2); diff --git a/com/ddraw.h b/com/ddraw.h index 365178a..d04bb48 100644 --- a/com/ddraw.h +++ b/com/ddraw.h @@ -235,7 +235,7 @@ enum { }; typedef struct { - void* vtable; + API(IUnknown) iunknown; Address texture; // Direct3DTexture2* API(DDSURFACEDESC2) desc; } API(DirectDrawSurface4); diff --git a/main.c b/main.c index 5754ec0..7b7ad12 100644 --- a/main.c +++ b/main.c @@ -133,8 +133,12 @@ Address CreateInterface(const char* name, unsigned int slotCount) { } vtable[i] = hltAddress; } + // First element in object is pointer to vtable - *(uint32_t*)Memory(interfaceAddress) = vtableAddress; + API(IUnknown)* iunknown = Memory(interfaceAddress); + iunknown->vtable_address = vtableAddress; + iunknown->instance_size = object_size; + iunknown->reference_count = 1; return interfaceAddress; } @@ -143,6 +147,28 @@ Address CreateInterface(const char* name, unsigned int slotCount) { #endif +static void AddRefInterface(Address address) { + API(IUnknown)* this = Memory(address); + + // Keep track that the new surface is being used + this->reference_count++; +} + +static void ReleaseInterface(Address address) { + API(IUnknown)* this = Memory(address); + + // Remove reference + this->reference_count--; + + // Check if the last user is gone now + if (this->reference_count == 0) { + printf("Free interface!\n"); + + //FIXME: Ref-counting is still broken.. or something + //Free(address); + } +} + @@ -2201,6 +2227,9 @@ HACKY_COM_BEGIN(IDirectDrawSurface4, 0) iid->Data4[4], iid->Data4[5], iid->Data4[6], iid->Data4[7]); if (iid->Data1 == 0x93281502) { //FIXME: Check for full GUID (Direct3DTexture2) printf("Returning texture 0x%" PRIX32 "\n", this->texture); + + AddRefInterface(this->texture); + *(Address*)Memory(stack[3]) = this->texture; } else { assert(false); @@ -2212,6 +2241,9 @@ HACKY_COM_END() // IDirectDrawSurface4 -> STDMETHOD_(ULONG,AddRef) (THIS) PURE; // 1 HACKY_COM_BEGIN(IDirectDrawSurface4, 1) hacky_printf("p 0x%" PRIX32 "\n", stack[1]); + + AddRefInterface(stack[1]); + eax = 1; // New reference count esp += 1 * 4; HACKY_COM_END() @@ -2219,6 +2251,13 @@ HACKY_COM_END() // IDirectDrawSurface4 -> STDMETHOD_(ULONG,Release) (THIS) PURE; //2 HACKY_COM_BEGIN(IDirectDrawSurface4, 2) hacky_printf("p 0x%" PRIX32 "\n", stack[1]); + + API(DirectDrawSurface4)* this = (API(DirectDrawSurface4)*)Memory(stack[1]); + Address texture = this->texture; + + ReleaseInterface(stack[1]); + ReleaseInterface(texture); + eax = 0; // FIXME: No idea what this expects to return.. esp += 1 * 4; HACKY_COM_END() @@ -2227,6 +2266,9 @@ HACKY_COM_END() HACKY_COM_BEGIN(IDirectDrawSurface4, 3) hacky_printf("p 0x%" PRIX32 "\n", stack[1]); hacky_printf("a 0x%" PRIX32 "\n", stack[2]); + + AddRefInterface(stack[2]); + eax = 0; // FIXME: No idea what this expects to return.. esp += 2 * 4; HACKY_COM_END() @@ -2288,6 +2330,8 @@ HACKY_COM_BEGIN(IDirectDrawSurface4, 8) hacky_printf("a 0x%" PRIX32 "\n", stack[2]); hacky_printf("b 0x%" PRIX32 "\n", stack[3]); + ReleaseInterface(stack[3]); + eax = 0; // FIXME: No idea what this expects to return.. esp += 3 * 4; HACKY_COM_END() @@ -3205,6 +3249,9 @@ HACKY_COM_BEGIN(IDirect3DTexture2, 0) if (!strcmp(iidString, "0B2B8630-AD35-11D0-8EA6-00609797EA5B")) { API(Direct3DTexture2)* this = Memory(stack[1]); *(Address*)Memory(stack[3]) = this->surface; + + AddRefInterface(this->surface); + } else { assert(false); } @@ -3217,6 +3264,9 @@ HACKY_COM_END() // IDirect3DTexture2 -> STDMETHOD_(ULONG,Release) (THIS) PURE; //2 HACKY_COM_BEGIN(IDirect3DTexture2, 2) hacky_printf("p 0x%" PRIX32 "\n", stack[1]); + + ReleaseInterface(stack[1]); + eax = 0; // FIXME: No idea what this expects to return.. esp += 1 * 4; HACKY_COM_END() diff --git a/windows.h b/windows.h index 9a85c42..5878c89 100644 --- a/windows.h +++ b/windows.h @@ -112,4 +112,10 @@ static void strcpy_ucs2(uint16_t* dest, uint16_t* src) { } +typedef struct { + uint32_t vtable_address; + uint32_t instance_size; + uint32_t reference_count; +} API(IUnknown); + #endif From 1448f12b7904def1741148c776852dcc771d85d8 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 8 Jun 2019 16:22:40 +0200 Subject: [PATCH 32/64] Use PBOs --- com/ddraw.h | 1 + main.c | 34 +++++++++++++++++++++++++++------- xbox.c | 5 +++++ 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/com/ddraw.h b/com/ddraw.h index d04bb48..ed3d964 100644 --- a/com/ddraw.h +++ b/com/ddraw.h @@ -238,6 +238,7 @@ typedef struct { API(IUnknown) iunknown; Address texture; // Direct3DTexture2* API(DDSURFACEDESC2) desc; + GLuint pbo; } API(DirectDrawSurface4); #endif diff --git a/main.c b/main.c index 7b7ad12..99a62e1 100644 --- a/main.c +++ b/main.c @@ -2045,14 +2045,16 @@ enum { if (desc->ddsCaps.dwCaps & API(DDSCAPS_TEXTURE)) { // FIXME: Delay this until the interface is queried the first time?! - surface->texture = CreateInterface("IDirect3DTexture2", 20); + surface->texture = CreateInterface("IDirect3DTexture2", 10); + surface->pbo = 0; API(Direct3DTexture2)* texture = (API(Direct3DTexture2)*)Memory(surface->texture); texture->surface = surfaceAddress; glGenTextures(1, &texture->handle); printf("GL handle is %d\n", texture->handle); } else { //FIXME: only added to catch bugs, null pointer should work - surface->texture = CreateInterface("invalid", 50); + surface->texture = CreateInterface("invalid", 10); + surface->pbo = 0; //FIXME: WTF is this shit?! API(Direct3DTexture2)* texture = (API(Direct3DTexture2)*)Memory(surface->texture); @@ -2374,6 +2376,7 @@ HACKY_COM_BEGIN(IDirectDrawSurface4, 12) surface->desc.ddpfPixelFormat.dwRGBBitCount = 16; surface->texture = 0; + surface->pbo = 0; *(Address*)Memory(stack[3]) = surfaceAddress; } //FIXME: Used to retrieve surface for mipmaps?! @@ -2428,9 +2431,20 @@ HACKY_COM_BEGIN(IDirectDrawSurface4, 25) //Hack: Part 1: check if we already have this surface in RAM if (this->desc.lpSurface == 0) { this->desc.lpSurface = Allocate(this->desc.dwHeight * this->desc.lPitch); - memset(Memory(this->desc.lpSurface), 0x77, this->desc.dwHeight * this->desc.lPitch); } + // Start a clean surface, or load it from PBO, if available + if (this->pbo == 0) { + memset(Memory(this->desc.lpSurface), 0x77, this->desc.dwHeight * this->desc.lPitch); + } else { + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->pbo); + void* ptr = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_READ_ONLY); + if (ptr != NULL) { //FIXME: Just assert this! + memcpy(Memory(this->desc.lpSurface), ptr, this->desc.dwHeight * this->desc.lPitch); + glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); + } + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + } if (this->desc.ddsCaps.dwCaps & API(DDSCAPS_ZBUFFER)) { assert(this->desc.lPitch == 2 * this->desc.dwWidth); @@ -2503,19 +2517,25 @@ HACKY_COM_BEGIN(IDirectDrawSurface4, 32) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + if (this->pbo == 0) { + glGenBuffers(1, &this->pbo); + } + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->pbo); + glBufferData(GL_PIXEL_UNPACK_BUFFER, desc->dwHeight * desc->lPitch, Memory(desc->lpSurface), GL_STATIC_DRAW); if (desc->ddpfPixelFormat.dwRGBBitCount == 32) { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, desc->dwWidth, desc->dwHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, Memory(desc->lpSurface)); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, desc->dwWidth, desc->dwHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); } else { if (desc->ddpfPixelFormat.dwRGBAlphaBitMask == 0x8000) { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, desc->dwWidth, desc->dwHeight, 0, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, Memory(desc->lpSurface)); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, desc->dwWidth, desc->dwHeight, 0, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, NULL); } else { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, desc->dwWidth, desc->dwHeight, 0, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV, Memory(desc->lpSurface)); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, desc->dwWidth, desc->dwHeight, 0, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV, NULL); } } + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); glBindTexture(GL_TEXTURE_2D, previousTexture); //Hack: part 2: don't free this to keep data in RAM. see lock for part 1 -#if 0 +#if 1 Free(desc->lpSurface); desc->lpSurface = 0; #endif diff --git a/xbox.c b/xbox.c index 7acd377..a450e2c 100644 --- a/xbox.c +++ b/xbox.c @@ -291,6 +291,11 @@ GLAPI void GLAPIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height GLAPI void GLAPIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) { printf("%s\n", __func__); + //FIXME: Add support for PBOs + if (pixels == NULL) { + return; + } + switch(type) { case GL_UNSIGNED_BYTE: { FILE* f = fopen("rgba8888.bin", "wb"); From ce499f960652ab79897234da310813ad0c6726e8 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 8 Jun 2019 16:23:14 +0200 Subject: [PATCH 33/64] hacks: Weird changes to memory-statistics printer --- emulation.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/emulation.c b/emulation.c index 8dc286a..7ccdc5e 100644 --- a/emulation.c +++ b/emulation.c @@ -744,13 +744,12 @@ static unsigned int GetThreadCount() { } static void memory_statistics() { -#if 1 - printf("Memory statistics:\n"); #ifdef XBOX + debugPrint(" Memory statistics:\n"); MM_STATISTICS ms; ms.Length = sizeof(MM_STATISTICS); MmQueryStatistics(&ms); - #define PRINT(stat) printf("- " #stat ": %d\n", ms.stat); + #define PRINT(stat) debugPrint(" - " #stat ": %d\n", ms.stat); PRINT(TotalPhysicalPages) PRINT(AvailablePages) PRINT(VirtualMemoryBytesCommitted) @@ -760,11 +759,12 @@ static void memory_statistics() { PRINT(StackPagesCommitted) PRINT(ImagePagesCommitted) #undef PRINT -#endif uint32_t esp; asm("mov %%esp, %%eax":"=a"(esp)); - printf("- Stack: 0x%X\n", esp); + debugPrint(" - Stack: 0x%X\n", esp); + + printf(" - AvailablePages: %d\n", ms.AvailablePages); #endif } From 0cc92063feadf169015acbbf97fc7e2735db7850 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 8 Jun 2019 16:23:50 +0200 Subject: [PATCH 34/64] Add crash handler for Xbox --- main.c | 177 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) diff --git a/main.c b/main.c index 99a62e1..f9eb42a 100644 --- a/main.c +++ b/main.c @@ -4085,6 +4085,164 @@ void RunX86(Exe* exe) { CleanupEmulation(); } +#ifdef XBOX + + +typedef struct { + union { + uint32_t edi; + uint16_t di; + }; + union { + uint32_t esi; + uint16_t si; + }; + uint32_t ebp; + uint32_t _esp; + union { + uint32_t ebx; + struct { + union { + uint16_t bx; + struct { + uint8_t bl, bh; + }; + }; + }; + }; + union { + uint32_t edx; + struct { + union { + uint16_t dx; + struct { + uint8_t dl, dh; + }; + }; + }; + }; + union { + uint32_t ecx; + struct { + union { + uint16_t cx; + struct { + uint8_t cl, ch; + }; + }; + }; + }; + union { + uint32_t eax; + struct { + union { + uint16_t ax; + struct { + uint8_t al, ah; + }; + }; + }; + }; +} __attribute__((packed)) Registers; + +typedef struct { + uint32_t error_code; + uint32_t eip; + uint16_t cs; + uint16_t _pad; + uint32_t eflags; +} __attribute__((packed)) TrapFrame; + +void __stdcall page_fault_handler(uint32_t cr2, TrapFrame* trap_frame, Registers* registers) { + + // This is an interrupt handler, so be careful with what you do. + // There shouldn't be any float math in here, and you should respect + // the IRQL requirements! + + //FIXME: Hardware interrupts are still enabled. + // We need to ensure that no hardware interrupt handler comes in, + // and triggers this handler again? + + + // Print debug information if remapped address will trigger the same error + debugPrint("\n"); + + debugPrint("Illegal access: CR2=0x%x, CS=0x%x, EIP=0x%x, EFLAGS=0x%x, error-code=0x%x", cr2, trap_frame->cs, trap_frame->eip, trap_frame->eflags, trap_frame->error_code); + debugPrint(" EAX=0x%x, ECX=0x%x\n", registers->eax, registers->ecx); + + // Get access to instruction bytes + uint8_t* instruction = (uint8_t*)trap_frame->eip; + + debugPrint("Instruction:"); + for(unsigned int i = 0; i < 16; i++) { + debugPrint(" %x%x", instruction[i] >> 4, instruction[i] & 0xF); + } + debugPrint("\n"); + + while(true); +} + +// This handler will be called for page faults +void __stdcall page_fault_isr(void); +asm("_page_fault_isr@0:\n" + + // Disable interrupts + "cli\n" + + // Set stack direction + "cld\n" + + // Keep a copy of all registers + "pusha\n" + + // Get pointer to all regs (top of stack); push it + "mov %esp, %eax\n" + "push %eax\n" + + // Above the regs (32 bytes), there's the trap frame; push it + "add $32, %eax\n" + "push %eax\n" + + // Now retrieve the address that triggered the page fault; push it + "movl %cr2, %eax\n" + "push %eax\n" + + // Call the C handler + "call _page_fault_handler@12\n" + + // Retrieve the original registers again + "popa\n" + + // Re-enable interrupts + "sti\n" + + // Pop error code and return from interrupt + "add $4, %esp\n" + "iret\n" +); //FIXME: Can this be relocated?! + +typedef struct { + uint16_t offset_lo; + uint16_t selector; + uint8_t zero; + uint8_t type_attr; + uint16_t offset_hi; +} __attribute__((packed)) IDTEntry; + +typedef struct { + uint16_t length; + IDTEntry* entries; +} __attribute__((packed)) IDT; + +void __stdcall get_idt(IDT* idt); +asm("_get_idt@4:\n" + "mov +4(%esp), %eax\n" + "sidtl (%eax)\n" + "retn $4\n" +); + +#endif + #ifdef XBOX // Stolen from https://gist.github.com/mmozeiko/ae38aeb10add7cb66be4c00f24f8e688 @@ -4124,6 +4282,25 @@ int main(int argc, char* argv[]) { #endif +#ifdef XBOX + // Install page fault handler and NIC interrupt handler + //FIXME: This assumes that the IDT is always identity mapped. + // We might want to MmMapIoSpace it instead. + IDT idt; + get_idt(&idt); + debugPrint("IDT at 0x%x (size %d)\n", (int)idt.entries, (int)idt.length); + debugPrint("Replacing IDT entry 0xE: 0x%x (old)\n", (idt.entries[0xE].offset_hi << 16) | idt.entries[0xE].offset_lo); + uintptr_t page_fault_isr_addr = (uintptr_t)page_fault_isr; + idt.entries[0xE].offset_lo = page_fault_isr_addr & 0xFFFF; + idt.entries[0xE].offset_hi = (page_fault_isr_addr >> 16) & 0xFFFF; + +for(int i = 0; i <= 0x13; i++) { + idt.entries[i].offset_lo = page_fault_isr_addr & 0xFFFF; + idt.entries[i].offset_hi = (page_fault_isr_addr >> 16) & 0xFFFF; +} + +#endif + #ifdef XBOX printf("-- Running CRT functions ()\n"); win32_crt_call(__xc_a, __xc_z); From 3c5d3eaeef6d9bf0c6d66cafbd917c02c86969fe Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 8 Jun 2019 16:25:08 +0200 Subject: [PATCH 35/64] Switch to NtAllocateVirtualMemory as default allocator on Xbox (was ContiguousMemory) --- common.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/common.h b/common.h index 5f78f25..5238c62 100644 --- a/common.h +++ b/common.h @@ -38,7 +38,11 @@ static uint32_t AlignUp(uint32_t address, uint32_t size) { static void* aligned_malloc(size_t alignment, size_t size) { void* ptr; #ifdef XBOX - ptr = MmAllocateContiguousMemoryEx(size, 0x00000000, 0xFFFFFFFF, alignment, PAGE_READWRITE); +// ptr = MmAllocateContiguousMemoryEx(size, 0x00000000, 0xFFFFFFFF, alignment, PAGE_READWRITE); + ptr = NULL; + DWORD allocated_size = size; + NTSTATUS status = NtAllocateVirtualMemory(&ptr, 0, &allocated_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + assert(status == STATUS_SUCCESS); #elif defined(_WIN32) ptr = _aligned_malloc(size, alignment); #else @@ -52,7 +56,10 @@ static void* aligned_malloc(size_t alignment, size_t size) { static void aligned_free(void* ptr) { #ifdef XBOX - MmFreeContiguousMemory(ptr); +// MmFreeContiguousMemory(ptr); + DWORD dwSize = 0; + NTSTATUS status = NtFreeVirtualMemory(&ptr, &dwSize, MEM_RELEASE); + assert(status == STATUS_SUCCESS); #elif defined(_WIN32) _aligned_free(ptr); #else From 4ef012fa8d32c43238f75abf5bc4b9f756988dcc Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 8 Jun 2019 16:26:24 +0200 Subject: [PATCH 36/64] Reduce stack size to 160kiB --- emulation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emulation.c b/emulation.c index 7ccdc5e..d40593d 100644 --- a/emulation.c +++ b/emulation.c @@ -41,7 +41,7 @@ static uint32_t tlsAddress = 0x83100000; //FIXME: No idea where to put this yet static uint32_t tlsSize = 0x1000; static uint32_t stackAddress = 0x83200000; // FIXME: Search free region instead..? -static uint32_t stackSize = 200 * 1024; // About 140kiB are in use at maximum +static uint32_t stackSize = 160 * 1024; // About 140kiB are in use at maximum #define HEAP_ADDRESS 0x81000000 static uint32_t heapAddress = HEAP_ADDRESS; From 977671da81f20c898c6c6e49ba7e23cbafa87607 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 8 Jun 2019 16:26:45 +0200 Subject: [PATCH 37/64] Move Xbox heap to 0x83400000 --- emulation.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/emulation.c b/emulation.c index d40593d..0debf30 100644 --- a/emulation.c +++ b/emulation.c @@ -43,7 +43,11 @@ static uint32_t tlsSize = 0x1000; static uint32_t stackAddress = 0x83200000; // FIXME: Search free region instead..? static uint32_t stackSize = 160 * 1024; // About 140kiB are in use at maximum +#ifdef XBOX #define HEAP_ADDRESS 0x81000000 +#else +#define HEAP_ADDRESS 0x83400000 +#endif static uint32_t heapAddress = HEAP_ADDRESS; #ifdef UC_NATIVE static uint32_t heapSize = 0x1000; // Dummy page From 1909ba7e37ce46d5703af4a5db0867f714e5607d Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 8 Jun 2019 16:27:33 +0200 Subject: [PATCH 38/64] Increase heap size to 200MiB (FIXME: comment buggy - says 16MiB) --- emulation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emulation.c b/emulation.c index 0debf30..a077da4 100644 --- a/emulation.c +++ b/emulation.c @@ -52,7 +52,7 @@ static uint32_t heapAddress = HEAP_ADDRESS; #ifdef UC_NATIVE static uint32_t heapSize = 0x1000; // Dummy page #else -static uint32_t heapSize = 20 * 1024 * 1024; // 16 MiB +static uint32_t heapSize = 200 * 1024 * 1024; // 16 MiB #endif static uc_engine *uc; From 10900421b052b59b056bb62533b510abb55865d3 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 8 Jun 2019 16:28:22 +0200 Subject: [PATCH 39/64] fixup: ??? --- emulation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emulation.c b/emulation.c index a077da4..3853553 100644 --- a/emulation.c +++ b/emulation.c @@ -315,7 +315,7 @@ void* MapMemory(uint32_t address, uint32_t size, bool read, bool write, bool exe //FIXME: Respect protection Size page_size = sysconf(_SC_PAGE_SIZE); Address check_address = address; - while(check_address <= (address + size)) { + while(check_address < (address + size)) { int ret = msync(check_address, page_size, MS_ASYNC); assert((ret == -1) && (errno == ENOMEM)); check_address += page_size; From a600646ca809d4d11080b60992f5f66b31d1c824 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 8 Jun 2019 16:28:48 +0200 Subject: [PATCH 40/64] fixup: Don't allocate twice? --- emulation.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/emulation.c b/emulation.c index 3853553..f19b311 100644 --- a/emulation.c +++ b/emulation.c @@ -321,9 +321,6 @@ void* MapMemory(uint32_t address, uint32_t size, bool read, bool write, bool exe check_address += page_size; } void* memory = mmap(address, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_SHARED|MAP_FIXED, -1, 0); - - - memory = mmap(address, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_SHARED|MAP_FIXED, -1, 0); #endif assert(memory == address); #else From 07bc60bed91ac5694587af993e0f2ae8e651c2cb Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 8 Jun 2019 16:29:21 +0200 Subject: [PATCH 41/64] Support CANARY option --- common.h | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/common.h b/common.h index 5238c62..02075be 100644 --- a/common.h +++ b/common.h @@ -46,7 +46,18 @@ static void* aligned_malloc(size_t alignment, size_t size) { #elif defined(_WIN32) ptr = _aligned_malloc(size, alignment); #else - posix_memalign(&ptr, alignment, size); +//#define CANARY +#ifdef CANARY + // Catch some errors with the game by allocating 2 dummy pages + size = AlignUp(size, alignment); + int ret = posix_memalign(&ptr, alignment, size + 0x2000); + assert(ret == 0); + mprotect(ptr, size + 0x2000, PROT_NONE); + ptr = (uintptr_t)ptr + 0x1000; +#else + int ret = posix_memalign(&ptr, alignment, size); + assert(ret == 0); +#endif mprotect(ptr, size, PROT_READ | PROT_WRITE | PROT_EXEC); #endif assert(ptr <= 0xFFFFFFFF); @@ -63,6 +74,9 @@ static void aligned_free(void* ptr) { #elif defined(_WIN32) _aligned_free(ptr); #else +#ifdef CANARY + ptr = (uintptr_t)ptr - 0x1000; +#endif free(ptr); #endif } From 866db360587086f4d832ea39dd9e88a31ec11888 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 8 Jun 2019 16:29:51 +0200 Subject: [PATCH 42/64] Only check memory for NATIVE mode, and initialize memory to 0xFF --- common.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/common.h b/common.h index 02075be..b500e43 100644 --- a/common.h +++ b/common.h @@ -60,8 +60,11 @@ static void* aligned_malloc(size_t alignment, size_t size) { #endif mprotect(ptr, size, PROT_READ | PROT_WRITE | PROT_EXEC); #endif - assert(ptr <= 0xFFFFFFFF); assert(ptr != NULL); +#ifdef UC_NATIVE + assert(ptr <= 0xFFFFFFFF); +#endif + memset(ptr, 0xFF, size); return ptr; } From 842f28307d509f8ed9d81ddeab67710cfe719cbb Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 8 Jun 2019 16:31:22 +0200 Subject: [PATCH 43/64] Various hacks for NATIVE mode and emulation --- emulation.c | 32 ++++++------- uc_native.c | 136 ++++++++++++++++++++++++++-------------------------- uc_native.h | 4 +- 3 files changed, 82 insertions(+), 90 deletions(-) diff --git a/emulation.c b/emulation.c index f19b311..015305e 100644 --- a/emulation.c +++ b/emulation.c @@ -415,27 +415,15 @@ void* Memory(uint32_t address) { #ifdef UC_NATIVE #include "uc_native.h" -#include -static uint32_t host_eip; +uint32_t host_eip; #ifndef __stdcall #define __stdcall __attribute__((stdcall)) #endif - - -void __stdcall return_to_host() asm("return_to_host"); -void __stdcall return_to_host() { - guest_registers->esp = guest_registers_esp; - guest_registers->eip = host_eip; -#if 0 - asm("mov $0, %%ax\n" - "mov %%ax, %%fs\n":); -#endif - longjmp(*host_jmp, 1); -} #endif + Address CreateHlt() { #ifdef UC_NATIVE @@ -483,7 +471,12 @@ Address CreateHlt() { "popf\n" "fxrstor host_registers_fpu\n" - "call return_to_host\n" +#ifdef XBOX + // Re-enable interrupts + "sti\n" +#endif + + "jmp return_to_host\n" "continue:\n":::"eax", "esp", "memory"); uint8_t* code = Memory(code_address); @@ -493,14 +486,14 @@ Address CreateHlt() { *code++ = 0x05; *(uint32_t*)code = (uintptr_t)&host_eip; code += 4; - *(uint32_t*)code = code_address + 1; + *(uint32_t*)code = code_address + 2; code += 4; *code++ = 0xE9; // jmp __return_to_host *(uint32_t*)code = (uintptr_t)__return_to_host_entry - (uintptr_t)code - 4; code += 4; #else - Address code_address = Allocate(2); + Address code_address = Allocate(3); uint8_t* code = Memory(code_address); *code++ = 0x90; // Marker *code++ = 0xF4; // HLT @@ -819,12 +812,15 @@ void RunEmulation() { uc_reg_read(uc, UC_X86_REG_EIP, &ctx->eip); - Address hltAddress = ctx->eip - 1; + Address hltAddress = ctx->eip - 2; assert(*(uint8_t*)Memory(hltAddress) == 0x90); HltHandler* hltHandler = findHltHandler(hltAddress); if(hltHandler != NULL) { + printf("Running handler for '%s'\n", hltHandler->user_data); hltHandler->callback(uc, hltHandler->address, hltHandler->user_data); + } else { + assert(false); } //Hack: Manually transfers EIP (might have been changed in callback) diff --git a/uc_native.c b/uc_native.c index f297596..d55cc45 100644 --- a/uc_native.c +++ b/uc_native.c @@ -6,7 +6,6 @@ #include #include -#include #include #ifdef XBOX @@ -31,10 +30,8 @@ uint8_t host_registers_fpu[512] __attribute__((aligned(16))); uint32_t guest_registers_esp; uint32_t host_esp; uint32_t host_fs; -jmp_buf* host_jmp; typedef struct { - jmp_buf jmp; Registers registers; } uc_engine_native; @@ -312,90 +309,91 @@ uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t time uc_engine_native* u = (uc_engine_native*)uc; printf("uc_emu_start\n"); - host_jmp = &u->jmp; + extern uint32_t callId; + printf("Doing some bullshit %d at 0x%08X\n", callId, begin); - if (setjmp(*host_jmp) == 0) { -extern uint32_t callId; - printf("Doing some bullshit %d at 0x%08X\n", callId, begin); - - _begin = begin; + _begin = begin; // For Xbox we can use the existing FS (might get corrupted?) #ifndef XBOX - static struct user_desc ldt_desc; - + static struct user_desc ldt_desc; - static uint8_t* tls = NULL; - if (tls == NULL) { - tls = malloc(0x1000); - memset(tls, 0xBB, 0x1000); - u->registers.fs_base = tls; - - #if 0 - ldt_desc.entry_number = 0x63 >> 3; - int ret2 = syscall(SYS_get_thread_area, &ldt_desc); - printf("%d\n", ldt_desc.limit); - printf("0x%X\n", ldt_desc.contents); - #endif - - ldt_desc.entry_number = -1; - ldt_desc.base_addr = u->registers.fs_base; - ldt_desc.limit = 0xFFF; - ldt_desc.seg_32bit = 1; - ldt_desc.contents = 0x0; - ldt_desc.read_exec_only = 0; - ldt_desc.limit_in_pages = 0; - ldt_desc.seg_not_present = 0; - ldt_desc.useable = 1; - - int ret = syscall(SYS_set_thread_area, &ldt_desc); - printf("%d: Got seg %d\n", ret, ldt_desc.entry_number); - } - // Set FS to use our new thread area - uint16_t seg = ldt_desc.entry_number; - asm("shl $3, %%ax\n" - "or $0x3, %%ax\n" - "movw %%ax, %%fs\n"::"a"(seg)); + static uint8_t* tls = NULL; + if (tls == NULL) { + tls = malloc(0x1000); + memset(tls, 0xBB, 0x1000); + u->registers.fs_base = tls; + +#if 0 + ldt_desc.entry_number = 0x63 >> 3; + int ret2 = syscall(SYS_get_thread_area, &ldt_desc); + printf("%d\n", ldt_desc.limit); + printf("0x%X\n", ldt_desc.contents); +#endif + + ldt_desc.entry_number = -1; + ldt_desc.base_addr = u->registers.fs_base; + ldt_desc.limit = 0xFFF; + ldt_desc.seg_32bit = 1; + ldt_desc.contents = 0x0; + ldt_desc.read_exec_only = 0; + ldt_desc.limit_in_pages = 0; + ldt_desc.seg_not_present = 0; + ldt_desc.useable = 1; + + int ret = syscall(SYS_set_thread_area, &ldt_desc); + printf("%d: Got seg %d\n", ret, ldt_desc.entry_number); +} + +// Set FS to use our new thread area +uint16_t seg = ldt_desc.entry_number; +asm("shl $3, %%ax\n" + "or $0x3, %%ax\n" + "movw %%ax, %%fs\n"::"a"(seg)); #endif #if 0 - uint32_t foo = 0; - asm("mov %%fs:0, %[foo]\n" : [foo]"=r"(foo)); // : [fs]"r"(fs)); - printf("Read 0x%X\n", foo); + uint32_t foo = 0; + asm("mov %%fs:0, %[foo]\n" : [foo]"=r"(foo)); // : [fs]"r"(fs)); + printf("Read 0x%X\n", foo); #endif - guest_registers = &u->registers; - guest_registers_esp = guest_registers->esp; + guest_registers = &u->registers; + guest_registers_esp = guest_registers->esp; - asm volatile(// Make host backup - "fxsave host_registers_fpu\n" - "pushf\n" - "pusha\n" - "mov %%esp, host_esp\n" - // Get host fs stuff - "mov %%fs:0, %%eax\n" - "mov %%eax, host_fs\n" + asm volatile(// Make host backup + "fxsave host_registers_fpu\n" + "pushf\n" + "pusha\n" + "mov %%esp, host_esp\n" - // Load all registers - "mov guest_registers, %%esp\n" - "popa\n" - "popf\n" - "mov guest_registers_esp, %%esp\n" - //FIXME: Fixup ESP too + // Get host fs stuff + "mov %%fs:0, %%eax\n" + "mov %%eax, host_fs\n" - // Load FPU registers - "fxrstor guest_registers_fpu\n" + // Load all registers + "mov guest_registers, %%esp\n" + "popa\n" + "popf\n" + "mov guest_registers_esp, %%esp\n" + //FIXME: Fixup ESP too - "jmp *_begin\n":::"eax", "esp", "memory"); + // Load FPU registers + "fxrstor guest_registers_fpu\n" +#ifdef XBOX + // Disable interrupts + "cli\n" +#endif + "jmp *_begin\n" + + ".global return_to_host\n" + "return_to_host:\n":::"eax", "esp", "memory"); - // This can never return, or setjmp / longjmp would break! - assert(false); - } else { - printf("Returned\n"); - } + guest_registers->esp = guest_registers_esp; + guest_registers->eip = host_eip; return 0; } diff --git a/uc_native.h b/uc_native.h index 31eaf75..d7f9848 100644 --- a/uc_native.h +++ b/uc_native.h @@ -31,14 +31,12 @@ typedef struct { } Registers; -#include - -extern jmp_buf* host_jmp; extern uint32_t guest_registers_esp asm("guest_registers_esp"); extern Registers* guest_registers asm("guest_registers"); extern uint8_t guest_registers_fpu[512] asm("guest_registers_fpu"); extern uint8_t host_registers_fpu[512] asm("host_registers_fpu"); extern uint32_t host_esp asm("host_esp"); extern uint32_t host_fs asm("host_fs"); +extern uint32_t host_eip asm("host_eip"); #endif From 13af4c3c531ba796091f46a88cf124de4ee52a8b Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 8 Jun 2019 16:32:02 +0200 Subject: [PATCH 44/64] Only allow 1 guest thread --- emulation.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/emulation.c b/emulation.c index 015305e..4fe3f06 100644 --- a/emulation.c +++ b/emulation.c @@ -710,7 +710,8 @@ unsigned int CreateEmulatedThread(uint32_t eip) { } static int threadId = 0; uint32_t esp = stackAddress + stackSize - 1024; // We give 1k of headroom - assert(threadId < 4); + assert(threadId == 0); + threadId++; threads = realloc(threads, ++threadCount * sizeof(ThreadContext)); ThreadContext* ctx = &threads[threadCount - 1]; From a0af720cbc818d7c6ba60c3df15786490e0b490b Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 8 Jun 2019 16:33:04 +0200 Subject: [PATCH 45/64] hack: Drastically remove COM object size / reuse vtables --- main.c | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/main.c b/main.c index f9eb42a..689fa07 100644 --- a/main.c +++ b/main.c @@ -107,14 +107,46 @@ uint32_t tls[1000] = {0}; static void UnknownImport(void* uc, Address address, void* user_data); Address CreateInterface(const char* name, unsigned int slotCount) { //FIXME: Unsure about most terminology / inner workings here - Address interfaceAddress = Allocate(1000); //FIXME: Size of object - Address vtableAddress = Allocate(4 * slotCount); - char* slotNames = malloc(64 * slotCount); + Size object_size = 1000; + static int objectcount = 0; + printf("objectcount: %d\n", objectcount++); + Address interfaceAddress = Allocate(object_size); //FIXME: Size of object + Address vtableAddress = Allocate(4 * slotCount + 32 * slotCount); + assert(vtableAddress != 0); + +#if 1 +debugPrint("FOO B\n"); + static Address IDirectDrawSurface4 = 0; + static Address IDirect3DTexture2 = 0; + if (!strcmp(name, "IDirectDrawSurface4")) { + assert(slotCount == 50); + if (IDirectDrawSurface4 == 0) { + IDirectDrawSurface4 = vtableAddress; + } else { + Free(vtableAddress); + vtableAddress = IDirectDrawSurface4; + } + } else if (!strcmp(name, "IDirect3DTexture2")) { + assert(slotCount == 10); + if (IDirect3DTexture2 == 0) { + IDirect3DTexture2 = vtableAddress; + } else { + Free(vtableAddress); + vtableAddress = IDirect3DTexture2; + } + } + assert(vtableAddress != 0); +debugPrint("FOO E\n"); +#endif + + char* slotNames = Memory(vtableAddress + 4 * slotCount); uint32_t* vtable = (uint32_t*)Memory(vtableAddress); + for(unsigned int i = 0; i < slotCount; i++) { // Point addresses to themself - char* slotName = &slotNames[i * 64]; + char* slotName = &slotNames[i * 32]; sprintf(slotName, "%s__%d", name, i); + assert(strlen(slotName) < 32); Export* export = LookupExportByName(slotName); Address hltAddress; From 3a6279da89d782cb68ee7e498208c5d2cd4aa526 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 8 Jun 2019 16:33:58 +0200 Subject: [PATCH 46/64] Explain error in game, which affects HeapAlloc --- main.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/main.c b/main.c index 689fa07..b295982 100644 --- a/main.c +++ b/main.c @@ -590,9 +590,17 @@ HACKY_IMPORT_BEGIN(HeapAlloc) hacky_printf("hHeap 0x%" PRIX32 "\n", stack[1]); hacky_printf("dwFlags 0x%" PRIX32 "\n", stack[2]); hacky_printf("dwBytes 0x%" PRIX32 "\n", stack[3]); - eax = Allocate(stack[3]); + + //FIXME: The game has a bug, where it allocates 1 byte too few in at least + // one instance. The error will be at 0x44ae32 in the webdemo + uint32_t size = stack[3]; + + eax = Allocate(size); + + assert((stack[2] == 0x0) || (stack[2] == 0x8)); + //FIXME: Only do this if flag is set.. - memset(Memory(eax), 0x00, stack[3]); + memset(Memory(eax), 0x00, size); esp += 3 * 4; HACKY_IMPORT_END() From 871861c0fd46236f149b7b1d95709a7f3325802a Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 8 Jun 2019 16:34:49 +0200 Subject: [PATCH 47/64] Make TlsGetValue silent --- main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.c b/main.c index b295982..f4d1ab0 100644 --- a/main.c +++ b/main.c @@ -873,7 +873,7 @@ HACKY_IMPORT_BEGIN(GetLastError) HACKY_IMPORT_END() HACKY_IMPORT_BEGIN(TlsGetValue) - silent = true; + silent = false; if (!silent) { hacky_printf("dwTlsIndex 0x%" PRIX32 "\n", stack[1]); } From 266fa67e1fc158b861f38b9c0d3525063c74026c Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 8 Jun 2019 16:35:13 +0200 Subject: [PATCH 48/64] Reduce COM object vtable sizes --- main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.c b/main.c index f4d1ab0..b54cde5 100644 --- a/main.c +++ b/main.c @@ -2727,7 +2727,7 @@ HACKY_COM_BEGIN(IDirect3D3, 6) hacky_printf("p 0x%" PRIX32 "\n", stack[1]); hacky_printf("a 0x%" PRIX32 "\n", stack[2]); hacky_printf("b 0x%" PRIX32 "\n", stack[3]); - *(Address*)Memory(stack[2]) = CreateInterface("IDirect3DViewport3", 200); + *(Address*)Memory(stack[2]) = CreateInterface("IDirect3DViewport3", 30); eax = 0; // FIXME: No idea what this expects to return.. esp += 3 * 4; HACKY_COM_END() @@ -2739,7 +2739,7 @@ HACKY_COM_BEGIN(IDirect3D3, 8) hacky_printf("b 0x%" PRIX32 "\n", stack[3]); hacky_printf("c 0x%" PRIX32 "\n", stack[4]); hacky_printf("d 0x%" PRIX32 "\n", stack[5]); - *(Address*)Memory(stack[4]) = CreateInterface("IDirect3DDevice3", 200); + *(Address*)Memory(stack[4]) = CreateInterface("IDirect3DDevice3", 50); eax = 0; // FIXME: No idea what this expects to return.. esp += 5 * 4; HACKY_COM_END() From fa21a4426c8543ae62d842ad0421b97502f420e6 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 8 Jun 2019 16:35:37 +0200 Subject: [PATCH 49/64] hack: Patch bugs in webdemo --- main.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/main.c b/main.c index b54cde5..3745801 100644 --- a/main.c +++ b/main.c @@ -4442,6 +4442,21 @@ for(int i = 0; i <= 0x13; i++) { *p++ = 0x31; *p++ = 0xC0; // xor eax, eax *p++ = 0xC3; // ret + // This instruction in the webdemo causes an illegal access. + // It accesses 4 bytes, starting 3 bytes before the end of an allocation. +#if 1 + *(uint8_t*)Memory(0x44ae32+0) = 0x90; + *(uint8_t*)Memory(0x44ae32+1) = 0x90; +#endif + +#if 1 + //FIXME: These are for the webdemo version only + // Valgrind doesn't like this, so we remove the prefix + // cs mov eax, eax -> mov eax, eax + *(uint8_t*)Memory(0x4a6421) = 0x90; + *(uint8_t*)Memory(0x4A63E1) = 0x90; +#endif + // 0x90 = nop (used to disable code) // 0xC3 = ret (used to skip function) // 0x84 = je (probably used to be `jne`, used to invert condition) From 662d5b7e3964a3bd5933696bbf8a73059299da66 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 8 Jun 2019 16:36:11 +0200 Subject: [PATCH 50/64] Disable uc_reg_write to certain registers in NATIVE mode --- uc_native.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/uc_native.c b/uc_native.c index d55cc45..f1baf45 100644 --- a/uc_native.c +++ b/uc_native.c @@ -238,14 +238,17 @@ uc_err uc_reg_write(uc_engine *uc, int regid, const void *value) { u->registers.eip = *(int*)value; } else if (regid == UC_X86_REG_ESP) { u->registers.esp = *(unsigned int*)value; +#if 0 } else if (regid == UC_X86_REG_EBP) { u->registers.ebp = *(int*)value; } else if (regid == UC_X86_REG_ESI) { u->registers.esi = *(int*)value; } else if (regid == UC_X86_REG_EDI) { u->registers.edi = *(int*)value; +#endif } else if (regid == UC_X86_REG_EAX) { u->registers.eax = *(int*)value; +#if 0 } else if (regid == UC_X86_REG_EBX) { u->registers.ebx = *(int*)value; } else if (regid == UC_X86_REG_ECX) { @@ -300,6 +303,7 @@ uc_err uc_reg_write(uc_engine *uc, int regid, const void *value) { } else { assert(false); +#endif } return 0; From 3bb9841b5963b763a8b3f39180106fb5975d1009 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 18 May 2019 13:05:50 +0200 Subject: [PATCH 51/64] Attempt to reach compatibility with upstream nxdk (untested) --- Makefile.xbox => Makefile.nxdk | 4 +- main.c | 37 ++++---- xbox-hacks/GL | 1 + xbox-hacks/bsearch.c | 64 -------------- xbox-hacks/qsort.c | 149 --------------------------------- xbox.c | 13 +-- 6 files changed, 23 insertions(+), 245 deletions(-) rename Makefile.xbox => Makefile.nxdk (85%) create mode 120000 xbox-hacks/GL delete mode 100644 xbox-hacks/bsearch.c delete mode 100644 xbox-hacks/qsort.c diff --git a/Makefile.xbox b/Makefile.nxdk similarity index 85% rename from Makefile.xbox rename to Makefile.nxdk index 4009796..65b3a02 100644 --- a/Makefile.xbox +++ b/Makefile.nxdk @@ -1,4 +1,3 @@ -NXDK_DIR = $(CURDIR)/../nxdk //NXDK_SDL = y XBE_TITLE = OpenSWE1R @@ -20,8 +19,7 @@ SRCS += $(CURDIR)/com/dplay.c SRCS += $(CURDIR)/uc_native.c -SRCS += $(CURDIR)/xbox-hacks/qsort.c -SRCS += $(CURDIR)/xbox-hacks/bsearch.c +CFLAGS += -isystem$(CURDIR)/xbox-hacks CFLAGS += -DUC_NATIVE=1 -DUC_KVM=1 CFLAGS += -I/usr/include/unicorn diff --git a/main.c b/main.c index 3745801..60ee77d 100644 --- a/main.c +++ b/main.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "common.h" #include "descriptor.h" @@ -32,6 +33,17 @@ #endif +//FIXME: REMOVE THIS BLOCK! Only used during development +#ifdef XBOX +#define debugPrint(fmt, ...) +#else +#include +#endif +#ifdef XBOX +#include +#include +#endif + #include "SDL.h" static SDL_Window* sdlWindow; @@ -4283,23 +4295,6 @@ asm("_get_idt@4:\n" #endif -#ifdef XBOX -// Stolen from https://gist.github.com/mmozeiko/ae38aeb10add7cb66be4c00f24f8e688 - -// C initializers -__attribute__((section(".CRT$XCA"))) _PVFV __xc_a[] = { 0 }; -__attribute__((section(".CRT$XCZ"))) _PVFV __xc_z[] = { 0 }; - -static void win32_crt_call(_PVFV* a, _PVFV* b) { - while (a != b) { - if (*a) { - (**a)(); - } - a++; - } -} -#endif - int main(int argc, char* argv[]) { #ifdef XBOX @@ -4308,6 +4303,8 @@ int main(int argc, char* argv[]) { SIZE_T allocated_size = 0x00C00000; NTSTATUS status = NtAllocateVirtualMemory(&memory, 0, &allocated_size, MEM_RESERVE, PAGE_READWRITE); + XVideoSetMode(640, 480, 32, REFRESH_DEFAULT); + pb_init(); pb_show_debug_screen(); @@ -4341,12 +4338,6 @@ for(int i = 0; i <= 0x13; i++) { #endif -#ifdef XBOX - printf("-- Running CRT functions ()\n"); - win32_crt_call(__xc_a, __xc_z); -#endif - - printf("-- Initializing\n"); printf("Version: %s\n", APP_VERSION_STRING); InitializeEmulation(); diff --git a/xbox-hacks/GL b/xbox-hacks/GL new file mode 120000 index 0000000..9501973 --- /dev/null +++ b/xbox-hacks/GL @@ -0,0 +1 @@ +/usr/include/GL \ No newline at end of file diff --git a/xbox-hacks/bsearch.c b/xbox-hacks/bsearch.c deleted file mode 100644 index f044dbc..0000000 --- a/xbox-hacks/bsearch.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 1990 Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include -/* - * Perform a binary search. - * - * The code below is a bit sneaky. After a comparison fails, we - * divide the work in half by moving either left or right. If lim - * is odd, moving left simply involves halving lim: e.g., when lim - * is 5 we look at item 2, so we change lim to 2 so that we will - * look at items 0 & 1. If lim is even, the same applies. If lim - * is odd, moving right again involes halving lim, this time moving - * the base up one item past p: e.g., when lim is 5 we change base - * to item 3 and make lim 2 so that we will look at items 3 and 4. - * If lim is even, however, we have to shrink it by one before - * halving: e.g., when lim is 4, we still looked at item 2, so we - * have to make lim 3, then halve, obtaining 1, so that we will only - * look at item 3. - */ -void * -bsearch(const void *key, const void *base0, size_t nmemb, size_t size, - int (*compar)(const void *, const void *)) -{ - const char *base = base0; - int lim, cmp; - const void *p; - for (lim = nmemb; lim != 0; lim >>= 1) { - p = base + (lim >> 1) * size; - cmp = (*compar)(key, p); - if (cmp == 0) - return ((void *)p); - if (cmp > 0) { /* key > p: move right */ - base = (char *)p + size; - lim--; - } /* else move left */ - } - return (NULL); -} diff --git a/xbox-hacks/qsort.c b/xbox-hacks/qsort.c deleted file mode 100644 index 6429e43..0000000 --- a/xbox-hacks/qsort.c +++ /dev/null @@ -1,149 +0,0 @@ -/* $OpenBSD: qsort.c,v 1.10 2005/08/08 08:05:37 espie Exp $ */ -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -//#include -#include -static __inline char *med3(char *, char *, char *, int (*)(const void *, const void *)); -static __inline void swapfunc(char *, char *, int, int); -#define min(a, b) (a) < (b) ? a : b -/* - * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". - */ -#define swapcode(TYPE, parmi, parmj, n) { \ - long i = (n) / sizeof (TYPE); \ - TYPE *pi = (TYPE *) (parmi); \ - TYPE *pj = (TYPE *) (parmj); \ - do { \ - TYPE t = *pi; \ - *pi++ = *pj; \ - *pj++ = t; \ - } while (--i > 0); \ -} -#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ - es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1; -static __inline void -swapfunc(char *a, char *b, int n, int swaptype) -{ - if (swaptype <= 1) - swapcode(long, a, b, n) - else - swapcode(char, a, b, n) -} -#define swap(a, b) \ - if (swaptype == 0) { \ - long t = *(long *)(a); \ - *(long *)(a) = *(long *)(b); \ - *(long *)(b) = t; \ - } else \ - swapfunc(a, b, es, swaptype) -#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype) -static __inline char * -med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *)) -{ - return cmp(a, b) < 0 ? - (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a )) - :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c )); -} -void -qsort(void *aa, size_t n, size_t es, int (*cmp)(const void *, const void *)) -{ - char *pa, *pb, *pc, *pd, *pl, *pm, *pn; - int d, r, swaptype, swap_cnt; - char *a = aa; -loop: SWAPINIT(a, es); - swap_cnt = 0; - if (n < 7) { - for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es) - for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; - pl -= es) - swap(pl, pl - es); - return; - } - pm = (char *)a + (n / 2) * es; - if (n > 7) { - pl = (char *)a; - pn = (char *)a + (n - 1) * es; - if (n > 40) { - d = (n / 8) * es; - pl = med3(pl, pl + d, pl + 2 * d, cmp); - pm = med3(pm - d, pm, pm + d, cmp); - pn = med3(pn - 2 * d, pn - d, pn, cmp); - } - pm = med3(pl, pm, pn, cmp); - } - swap(a, pm); - pa = pb = (char *)a + es; - - pc = pd = (char *)a + (n - 1) * es; - for (;;) { - while (pb <= pc && (r = cmp(pb, a)) <= 0) { - if (r == 0) { - swap_cnt = 1; - swap(pa, pb); - pa += es; - } - pb += es; - } - while (pb <= pc && (r = cmp(pc, a)) >= 0) { - if (r == 0) { - swap_cnt = 1; - swap(pc, pd); - pd -= es; - } - pc -= es; - } - if (pb > pc) - break; - swap(pb, pc); - swap_cnt = 1; - pb += es; - pc -= es; - } - if (swap_cnt == 0) { /* Switch to insertion sort */ - for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es) - for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; - pl -= es) - swap(pl, pl - es); - return; - } - pn = (char *)a + n * es; - r = min(pa - (char *)a, pb - pa); - vecswap(a, pb - r, r); - r = min(pd - pc, pn - pd - (int)es); - vecswap(pb, pn - r, r); - if ((r = pb - pa) > (int)es) - qsort(a, r / es, es, cmp); - if ((r = pd - pc) > (int)es) { - /* Iterate rather than recurse to save stack space */ - a = pn - r; - n = r / es; - goto loop; - } -/* qsort(pn - r, r / es, es, cmp);*/ -} diff --git a/xbox.c b/xbox.c index a450e2c..4c428c7 100644 --- a/xbox.c +++ b/xbox.c @@ -6,14 +6,15 @@ #include -#include - +#include #include #include - +#include #include #include +#define _PTRDIFF_T_DEFINED +#include #include "xbox.h" @@ -560,7 +561,7 @@ GLEWAPI GLboolean glewExperimental = GL_FALSE; GLEWAPI const GLubyte * GLEWAPIENTRY glewGetErrorString (GLenum error) { printf("%s\n", __func__); - return ""; + return (GLubyte*)""; } GLEWAPI GLenum GLEWAPIENTRY glewInit (void) { @@ -603,7 +604,7 @@ SDL_Window* SDL_CreateWindow(const char* title, int h, Uint32 flags) { printf("%s\n", __func__); - return 1; + return (SDL_Window*)1; } void SDL_Delay(Uint32 ms) { @@ -641,7 +642,7 @@ Uint64 SDL_GetPerformanceFrequency(void) { SDL_GLContext SDL_GL_CreateContext(SDL_Window* window) { printf("%s\n", __func__); - return 1; + return (SDL_GLContext)1; } int SDL_GL_SetAttribute(SDL_GLattr attr, int value) { From 677e343fe8dee9aa6aa084e40997da9628f4cca1 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Tue, 21 May 2019 12:18:32 +0200 Subject: [PATCH 52/64] More hacks for upstream nxdk --- emulation.c | 2 +- main.c | 52 ++++++++++++++++++++++++++++++++++++++++------------ xbox.c | 2 ++ 3 files changed, 43 insertions(+), 13 deletions(-) diff --git a/emulation.c b/emulation.c index 4fe3f06..f8cae2f 100644 --- a/emulation.c +++ b/emulation.c @@ -307,7 +307,7 @@ void* MapMemory(uint32_t address, uint32_t size, bool read, bool write, bool exe memory = address; SIZE_T allocated_size = size; NTSTATUS status = NtAllocateVirtualMemory(&memory, 0, &allocated_size, MEM_COMMIT, PAGE_READWRITE); - printf("status was %x\n", status); + printf("status was %x when allocating 0x%08X (became 0x%08X), 0x%X bytes (became 0x%X)\n", status, address, (uint32_t)memory, size, allocated_size); assert(status == STATUS_SUCCESS); } printf("got %p == %p (%d bytes)?\n", memory, address, size); diff --git a/main.c b/main.c index 60ee77d..5dda0c8 100644 --- a/main.c +++ b/main.c @@ -35,9 +35,16 @@ //FIXME: REMOVE THIS BLOCK! Only used during development #ifdef XBOX -#define debugPrint(fmt, ...) -#else #include +#define debugPrint(fmt, ...) \ + do { \ + char buf[4096]; \ + sprintf(buf, fmt, __VA_ARGS__); \ + printf("%s", buf); \ + debugPrint("%s", buf); \ + } while(0); +#else +#define debugPrint(fmt, ...) #endif #ifdef XBOX #include @@ -771,7 +778,12 @@ HACKY_IMPORT_BEGIN(LCMapStringW) HACKY_IMPORT_END() HACKY_IMPORT_BEGIN(GetModuleHandleA) - hacky_printf("lpModuleName 0x%" PRIX32 " ('%s')\n", stack[1], Memory(stack[1])); + char* lpModuleName = Memory(stack[1]); + hacky_printf("lpModuleName 0x%" PRIX32, stack[1]); + if (lpModuleName != NULL) { + hacky_printf(" ('%s')", lpModuleName); + } + hacky_printf("\n"); eax = 999; esp += 1 * 4; HACKY_IMPORT_END() @@ -1416,7 +1428,12 @@ HACKY_IMPORT_BEGIN(CreateEventA) hacky_printf("lpEventAttributes 0x%" PRIX32 "\n", stack[1]); hacky_printf("bManualReset 0x%" PRIX32 "\n", stack[2]); hacky_printf("bInitialState 0x%" PRIX32 "\n", stack[3]); - hacky_printf("lpName 0x%" PRIX32 " ('%s')\n", stack[4], (char*)Memory(stack[4])); + hacky_printf("lpName 0x%" PRIX32, stack[4]); + char* lpName = (char*)Memory(stack[4]); + if (lpName != NULL) { + hacky_printf(" ('%s')", lpName); + } + hacky_printf("\n"); eax = 5551337; // HANDLE esp += 4 * 4; @@ -3897,7 +3914,7 @@ static void UnknownImport(void* uc, Address address, void* user_data) { // NOTE: This purposely does not map the file into memory for portability Exe* LoadExe(const char* path) { exe = (Exe*)malloc(sizeof(Exe)); //FIXME: Hack to make this global! - memset(exe, 0x00, sizeof(exe)); + memset(exe, 0x00, sizeof(Exe)); // Load the exe file and skip the DOS header exe->f = fopen(path, "rb"); @@ -4295,23 +4312,34 @@ asm("_get_idt@4:\n" #endif -int main(int argc, char* argv[]) { #ifdef XBOX - +__attribute__((constructor(101))) static void reserve_memory() { // Reserve the space for the EXE - void* memory = 0x00400000; + PVOID memory = 0x00400000; SIZE_T allocated_size = 0x00C00000; NTSTATUS status = NtAllocateVirtualMemory(&memory, 0, &allocated_size, MEM_RESERVE, PAGE_READWRITE); + assert(status == STATUS_SUCCESS); +} +#endif + +#ifdef XBOX +__attribute__((constructor(102))) static void start_log() { + // Clear log + FILE* f = freopen("log.txt", "wb", stdout); + if (f == NULL) { + debugPrint("Failed to open log.txt\n"); + } +} +#endif + +int main(int argc, char* argv[]) { +#ifdef XBOX XVideoSetMode(640, 480, 32, REFRESH_DEFAULT); pb_init(); pb_show_debug_screen(); - - // Clear log - FILE* f = fopen("log.txt", "wb"); - fclose(f); #else //dup2(stdout, stderr); setbuf(stdout, 0); diff --git a/xbox.c b/xbox.c index 4c428c7..7a05962 100644 --- a/xbox.c +++ b/xbox.c @@ -440,6 +440,7 @@ GLAPI void GLAPIENTRY _glewGetErrorString(int a0) { GLAPI void GLAPIENTRY _glGetProgramInfoLog(GLuint program, GLsizei maxLength, GLsizei *length, GLchar *infoLog) { printf("%s\n", __func__); + strcpy(infoLog, ""); return; } @@ -451,6 +452,7 @@ GLAPI void GLAPIENTRY _glGetProgramiv(GLuint program, GLenum pname, GLint* param GLAPI void GLAPIENTRY _glGetShaderInfoLog(GLuint shader, GLsizei maxLength, GLsizei *length, GLchar *infoLog) { printf("%s\n", __func__); + strcpy(infoLog, ""); return; } From a57bf4a08b2e95772cfe705b4cd994a4c4dc6ddc Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Tue, 21 May 2019 15:46:28 +0200 Subject: [PATCH 53/64] Fix out of bounds write --- xbox.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xbox.c b/xbox.c index 7a05962..82e7694 100644 --- a/xbox.c +++ b/xbox.c @@ -440,7 +440,7 @@ GLAPI void GLAPIENTRY _glewGetErrorString(int a0) { GLAPI void GLAPIENTRY _glGetProgramInfoLog(GLuint program, GLsizei maxLength, GLsizei *length, GLchar *infoLog) { printf("%s\n", __func__); - strcpy(infoLog, ""); + strcpy(infoLog, ""); return; } @@ -452,7 +452,7 @@ GLAPI void GLAPIENTRY _glGetProgramiv(GLuint program, GLenum pname, GLint* param GLAPI void GLAPIENTRY _glGetShaderInfoLog(GLuint shader, GLsizei maxLength, GLsizei *length, GLchar *infoLog) { printf("%s\n", __func__); - strcpy(infoLog, ""); + strcpy(infoLog, ""); return; } From 18f8de13a6ad6c5f18e12ab96a40210675c3b2a8 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Tue, 21 May 2019 15:46:43 +0200 Subject: [PATCH 54/64] Avoid _begin from being optimized away --- uc_native.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uc_native.c b/uc_native.c index f1baf45..7164f0c 100644 --- a/uc_native.c +++ b/uc_native.c @@ -23,7 +23,7 @@ #include "uc_native.h" // Accessed via inline assembly -static uint32_t _begin asm("_begin"); +static volatile uint32_t _begin asm("_begin"); Registers* guest_registers; uint8_t guest_registers_fpu[512] __attribute__((aligned(16))); uint8_t host_registers_fpu[512] __attribute__((aligned(16))); From 7bff6cba95419dc8965ffd9def9b88d7135ac229 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Tue, 21 May 2019 15:46:58 +0200 Subject: [PATCH 55/64] Be aggressive about optimizations (untested) --- Makefile.nxdk | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Makefile.nxdk b/Makefile.nxdk index 65b3a02..44b6a96 100644 --- a/Makefile.nxdk +++ b/Makefile.nxdk @@ -31,4 +31,9 @@ CFLAGS += -I$(SDL_DIR)/include CFLAGS += -Wno-inconsistent-dllimport +# We are short on memory, so reduce binary footprint +CFLAGS += -Os +#FIXME: At least one of these is bad: -fno-stack-protector -fomit-frame-pointer -ffunction-sections -fdata-sections +NXDK_STACKSIZE=16384 + include $(NXDK_DIR)/Makefile From a65bcda7daefc505817a1a79bff5f132f82f2437 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Tue, 21 May 2019 17:04:59 +0200 Subject: [PATCH 56/64] Hack for deterministic timing --- main.c | 7 ++++++- xbox.c | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/main.c b/main.c index 5dda0c8..212c472 100644 --- a/main.c +++ b/main.c @@ -888,7 +888,12 @@ HACKY_IMPORT_END() HACKY_IMPORT_BEGIN(timeGetTime) //FIXME: Avoid overflow? - eax = SDL_GetTicks(); + //eax = SDL_GetTicks(); + + //FIXME: Undo! + static uint32_t t = 0; + eax = t++; + HACKY_IMPORT_END() HACKY_IMPORT_BEGIN(GetLastError) diff --git a/xbox.c b/xbox.c index 82e7694..62a270a 100644 --- a/xbox.c +++ b/xbox.c @@ -187,6 +187,7 @@ static void saveBuffer() { fprintf(f, "\n"); } fclose(f); + } static void drawVertex(int i) { @@ -628,7 +629,7 @@ Uint32 SDL_GetMouseState(int* x, int* y) { Uint32 SDL_GetTicks(void) { printf("%s\n", __func__); - static int t = 0; + static uint32_t t = 0; return t++; } From 0c6d4c56290b8d07f2d9c43f97089768d30f3ca2 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 30 May 2019 21:03:46 +0200 Subject: [PATCH 57/64] Some working rendering --- Makefile.nxdk | 12 +- emulation.c | 4 +- main.c | 22 +- main.h | 12 +- uc_native.c | 4 - xbox-hacks/.gitignore | 2 + xbox-hacks/ps.ps.cg | 11 + xbox-hacks/vs.vs.cg | 37 +++ xbox.c | 564 +++++++++++++++++++++++++++++++++++++++++- xbox.h | 2 + 10 files changed, 643 insertions(+), 27 deletions(-) create mode 100644 xbox-hacks/.gitignore create mode 100644 xbox-hacks/ps.ps.cg create mode 100644 xbox-hacks/vs.vs.cg diff --git a/Makefile.nxdk b/Makefile.nxdk index 44b6a96..6a8babd 100644 --- a/Makefile.nxdk +++ b/Makefile.nxdk @@ -1,4 +1,4 @@ -//NXDK_SDL = y +#NXDK_SDL = y XBE_TITLE = OpenSWE1R GEN_XISO = $(XBE_TITLE).iso @@ -31,9 +31,15 @@ CFLAGS += -I$(SDL_DIR)/include CFLAGS += -Wno-inconsistent-dllimport +#FIXME: Slow mode for pbkit! remove! +CFLAGS += -DGPU=1 +CFLAGS += -DDBG=1 + # We are short on memory, so reduce binary footprint -CFLAGS += -Os +#CFLAGS += -Os #FIXME: At least one of these is bad: -fno-stack-protector -fomit-frame-pointer -ffunction-sections -fdata-sections -NXDK_STACKSIZE=16384 +#NXDK_STACKSIZE=16384 + +SHADER_OBJS = xbox-hacks/ps.inl xbox-hacks/vs.inl include $(NXDK_DIR)/Makefile diff --git a/emulation.c b/emulation.c index f8cae2f..a4cb623 100644 --- a/emulation.c +++ b/emulation.c @@ -739,7 +739,7 @@ static unsigned int GetThreadCount() { } static void memory_statistics() { -#ifdef XBOX +#if 0 //#ifdef XBOX debugPrint(" Memory statistics:\n"); MM_STATISTICS ms; ms.Length = sizeof(MM_STATISTICS); @@ -818,7 +818,9 @@ void RunEmulation() { HltHandler* hltHandler = findHltHandler(hltAddress); if(hltHandler != NULL) { +#ifndef XBOX printf("Running handler for '%s'\n", hltHandler->user_data); +#endif hltHandler->callback(uc, hltHandler->address, hltHandler->user_data); } else { assert(false); diff --git a/main.c b/main.c index 212c472..91db377 100644 --- a/main.c +++ b/main.c @@ -36,15 +36,15 @@ //FIXME: REMOVE THIS BLOCK! Only used during development #ifdef XBOX #include -#define debugPrint(fmt, ...) \ +#define XboxHackyDebugPrint(fmt, ...) \ do { \ char buf[4096]; \ sprintf(buf, fmt, __VA_ARGS__); \ printf("%s", buf); \ - debugPrint("%s", buf); \ + /*debugPrint("%s", buf);*/ \ } while(0); #else -#define debugPrint(fmt, ...) +#define XboxHackyDebugPrint(fmt, ...) #endif #ifdef XBOX #include @@ -134,7 +134,7 @@ Address CreateInterface(const char* name, unsigned int slotCount) { assert(vtableAddress != 0); #if 1 -debugPrint("FOO B\n"); +XboxHackyDebugPrint("FOO B\n"); static Address IDirectDrawSurface4 = 0; static Address IDirect3DTexture2 = 0; if (!strcmp(name, "IDirectDrawSurface4")) { @@ -155,7 +155,7 @@ debugPrint("FOO B\n"); } } assert(vtableAddress != 0); -debugPrint("FOO E\n"); +XboxHackyDebugPrint("FOO E\n"); #endif char* slotNames = Memory(vtableAddress + 4 * slotCount); @@ -4340,11 +4340,19 @@ __attribute__((constructor(102))) static void start_log() { int main(int argc, char* argv[]) { #ifdef XBOX + // Set display mode (16bpp to save memory) + //FIXME: Temporarily switched to 32bpp, as I got weird issues at 16bpp XVideoSetMode(640, 480, 32, REFRESH_DEFAULT); - + + // Startup pbkit pb_init(); - +#ifdef GPU + pb_show_front_screen(); +#else pb_show_debug_screen(); +#endif + + initialize_screen(); #else //dup2(stdout, stderr); setbuf(stdout, 0); diff --git a/main.h b/main.h index 2f57497..96749d1 100644 --- a/main.h +++ b/main.h @@ -15,13 +15,12 @@ extern uint32_t callId; extern Address clearEax; -static inline int hacky_printf(const char* fmt, ...) { -#if 1 +static inline void hacky_printf(const char* fmt, ...) { +#if 0 va_list args; va_start(args, fmt); int ret = vprintf(fmt, args); va_end(args); - return ret; #endif } @@ -80,17 +79,12 @@ void AddExport(const char* name, void* callback, Address address); /* Pop the return address */ \ Address returnAddress = stack[0]; \ eip = returnAddress; \ - esp += 4; \ - -#ifndef XBOX -#define debugPrint(fmt, ...) (0) -#endif + esp += 4; #define HACKY_IMPORT_END() \ if (!silent) { \ hacky_printf("Stack at 0x%" PRIX32 "; returning EAX: 0x%08" PRIX32 "\n", stackAddress, eax); \ hacky_printf("%" PRIu32 " Emulation at %X ('%s') from %X\n\n", callId, eip, (char*)_user_data, returnAddress); \ - debugPrint("%u\n", callId); \ } \ callId++; \ \ diff --git a/uc_native.c b/uc_native.c index 7164f0c..a51220f 100644 --- a/uc_native.c +++ b/uc_native.c @@ -311,10 +311,6 @@ uc_err uc_reg_write(uc_engine *uc, int regid, const void *value) { uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count) { uc_engine_native* u = (uc_engine_native*)uc; - printf("uc_emu_start\n"); - - extern uint32_t callId; - printf("Doing some bullshit %d at 0x%08X\n", callId, begin); _begin = begin; diff --git a/xbox-hacks/.gitignore b/xbox-hacks/.gitignore new file mode 100644 index 0000000..778feb7 --- /dev/null +++ b/xbox-hacks/.gitignore @@ -0,0 +1,2 @@ +*.inl +*.inl.* diff --git a/xbox-hacks/ps.ps.cg b/xbox-hacks/ps.ps.cg new file mode 100644 index 0000000..76a31c8 --- /dev/null +++ b/xbox-hacks/ps.ps.cg @@ -0,0 +1,11 @@ +struct vOut { + float4 position : POSITION; + float4 diffuse : COLOR0; + float4 specular : COLOR1; + float2 uv0 : TEXCOORD0; +}; + +float4 main(vOut I) : COLOR +{ + return I.diffuse; +} diff --git a/xbox-hacks/vs.vs.cg b/xbox-hacks/vs.vs.cg new file mode 100644 index 0000000..c0faaaf --- /dev/null +++ b/xbox-hacks/vs.vs.cg @@ -0,0 +1,37 @@ +struct vIn { + float4 position : POSITION; + float4 diffuse : DIFFUSE; + float4 specular : SPECULAR; + float2 uv0 : TEXCOORD; +}; + +struct vOut { + float4 position : POSITION; + float4 diffuse : COLOR0; + float4 specular : COLOR1; + float2 uv0 : TEXCOORD0; +}; + +vOut main( + vIn I, + uniform float3 clipScale, + uniform float3 clipOffset + ) +{ + vOut result; + float4 position; + + position = float4(I.position.xyz * clipScale + clipOffset, 1.0); + position /= I.position.w; + position.y = -position.y; + + // Transfom for Xbox framebuffer + position = (position / position.w) * float4(320.0, -240.0, 0.0, 0.0) + float4(320.0, 240.0, 65536.0, 1.0); + position.xyz /= position.w; + + result.position = position; + result.diffuse = I.diffuse; + result.specular = I.specular; + result.uv0 = I.uv0; + return result; +} diff --git a/xbox.c b/xbox.c index 62a270a..8841625 100644 --- a/xbox.c +++ b/xbox.c @@ -23,7 +23,241 @@ #include "SDL.h" +#include +static int SCREEN_WIDTH = 0; +static int SCREEN_HEIGHT = 0; +static int SCREEN_BPP = 0; +#include +static const int pad = 0; + +static int mouse_x = 0; +static int mouse_y = 0; + +#define printf(fmt, ...) {} + + + + + + + + + + + + + + +#include +#include + +#ifdef GPU +#include +#include +#include +#include +#include +#include +#endif + +#if 0 +typedef struct { + float pos[3]; + float color[3]; +} __attribute__((packed)) ColoredVertex; + +static const ColoredVertex verts[] = { + // X Y Z R G B + {{-1.0, -1.0, 1.0}, { 0.1, 0.1, 0.6}}, /* Background triangle 1 */ + {{-1.0, 1.0, 1.0}, { 0.0, 0.0, 0.0}}, + {{ 1.0, 1.0, 1.0}, { 0.0, 0.0, 0.0}}, + {{-1.0, -1.0, 1.0}, { 0.1, 0.1, 0.6}}, /* Background triangle 2 */ + {{ 1.0, 1.0, 1.0}, { 0.0, 0.0, 0.0}}, + {{ 1.0, -1.0, 1.0}, { 0.1, 0.1, 0.6}}, + {{-1.0, -1.0, 1.0}, { 1.0, 0.0, 0.0}}, /* Foreground triangle */ + {{ 0.0, 1.0, 1.0}, { 0.0, 1.0, 0.0}}, + {{ 1.0, -1.0, 1.0}, { 0.0, 0.0, 1.0}}, +}; +#endif + +#define MASK(mask, val) (((val) << (ffs(mask)-1)) & (mask)) + +/* Main program function */ +static void triangle_main(void) { + uint32_t *p; + int i, status; + int width, height; + int start, last, now; + int fps, frames, frames_total; + + + + + + + + + + + +} + +/* Construct a viewport transformation matrix */ +static void matrix_viewport(float out[4][4], float x, float y, float width, float height, float z_min, float z_max) +{ + memset(out, 0, 4*4*sizeof(float)); + out[0][0] = width/2.0f; + out[1][1] = height/-2.0f; + out[2][2] = z_max - z_min; + out[3][3] = 1.0f; + out[3][0] = x + width/2.0f; + out[3][1] = y + height/2.0f; + out[3][2] = z_min; +} + +// We need ou own, as pb_erase_depth_stencil_buffer doesn't support giving a value +static void erase_depth_stencil_buffer(int x, int y, int w, int h) +{ + DWORD *p; + + int x1,y1,x2,y2; + + x1=x; + y1=y; + x2=x+w; + y2=y+h; + + p=pb_begin(); + pb_push(p++,NV20_TCL_PRIMITIVE_3D_CLEAR_VALUE_HORIZ,2); //sets rectangle coordinates + *(p++)=((x2-1)<<16)|x1; + *(p++)=((y2-1)<<16)|y1; + pb_push(p++,NV20_TCL_PRIMITIVE_3D_CLEAR_VALUE_DEPTH,3); //sets data used to fill in rectangle + *(p++)=0xffffff00; //(depth<<8)|stencil + *(p++)=0; //color + *(p++)=0x03; //triggers the HW rectangle fill (only on D&S) + pb_end(p); +} + +/* Load the shader we will render with */ +static void init_shader(void) +{ + uint32_t *p; + int i; + + /* Setup vertex shader */ + uint32_t vs_program[] = { +#include "xbox-hacks/vs.inl" + }; + + p = pb_begin(); + + /* Set run address of shader */ + pb_push1(p, NV097_SET_TRANSFORM_PROGRAM_START, 0); + p += 2; + + /* Set execution mode */ + pb_push1(p, NV097_SET_TRANSFORM_EXECUTION_MODE, + MASK(NV097_SET_TRANSFORM_EXECUTION_MODE_MODE, NV097_SET_TRANSFORM_EXECUTION_MODE_MODE_PROGRAM) + | MASK(NV097_SET_TRANSFORM_EXECUTION_MODE_RANGE_MODE, NV097_SET_TRANSFORM_EXECUTION_MODE_RANGE_MODE_PRIV)); + p += 2; + + pb_push1(p, NV097_SET_TRANSFORM_PROGRAM_CXT_WRITE_EN, 0); + p += 2; + + /* Set cursor and begin copying program */ + pb_push1(p, NV097_SET_TRANSFORM_PROGRAM_LOAD, 0); + p += 2; + + for (i=0; i 0xFF)) { return; } z = 0xFF; +#ifdef GPU + + pb_fill(x, y, 1, 1, 0xFF00FFFF); // Cyan + +#else + + // Draw to some debug output buffer[y * 640 + x] = 0x80 + z / 2; + + + // Draw to actual Xbox framebuffer + unsigned char *videoBuffer = XVideoGetFB(); + videoBuffer += (y * SCREEN_WIDTH + x) * (SCREEN_BPP >> 3); + + switch (SCREEN_BPP) { + case 32: + *((int*)videoBuffer) = 0xFFFFFFFF; + break; + case 16: + *((short*)videoBuffer) = 0xFFFF; + break; + } + +#endif + +} + +static void prepare_vertices(void) { + uint32_t *p; + +#if 1 + // Be a bit paranoid.. + //FIXME: Remove if confirmed to not change anything + while(pb_busy()) { + /* Wait for completion... */ + } + pb_reset(); +#endif + + + // Setup matrix + { + +// float m_viewport[4][4]; +// matrix_viewport(m_viewport, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 65536.0f); + + /* + * WARNING: Changing shader source code may impact constant locations! + * Check the intermediate file (*.inl) for the expected locations after + * changing the code. + */ + p = pb_begin(); + + /* Set shader constants cursor at C0 */ + pb_push1(p, NV097_SET_TRANSFORM_CONSTANT_LOAD, 96); p+=2; + + /* Send the transformation matrix */ + float c2[4] = {1, 320, -240, 0}; + float c3[4] = {320, 240, 65536, 1}; + pb_push(p++, NV097_SET_TRANSFORM_CONSTANT, 4 * 4); + memset(p, 0x00, (4 * 4) *4); + memcpy(p, clipScale, 3*4); p+=4; // c0 + memcpy(p, clipOffset, 3*4); p+=4; // c1 + memcpy(p, c2, 4*4); p+=4; + memcpy(p, c3, 4*4); p+=4; + + pb_end(p); + } + + + p = pb_begin(); + +#if 1 + // Set up wireframe mode + pb_push2(p,NV20_TCL_PRIMITIVE_3D_POLYGON_MODE_FRONT,0x1B01,0x1B01); p+=3; //FillMode="solid" BackFillMode="point" + pb_push1(p,NV20_TCL_PRIMITIVE_3D_CULL_FACE_ENABLE,0); p+=2;//CullModeEnable=TRUE + pb_push1(p,NV20_TCL_PRIMITIVE_3D_DEPTH_TEST_ENABLE,0); p+=2; //ZEnable=TRUE or FALSE (But don't use W, see below) +#endif + + /* Clear all attributes */ + pb_push(p++, NV097_SET_VERTEX_DATA_ARRAY_FORMAT,16); + for(int i = 0; i < 16; i++) { + *(p++) = NV097_SET_VERTEX_DATA_ARRAY_FORMAT_TYPE_F; + } + + pb_end(p); + + + size_t stride = 4 * 4 + 4 + 4 + 2 * 4; + //FIXME: Is this right? our sample doesn't use phys address... + uint8_t* buf = MmGetPhysicalAddress(array_buffer); + + + /* Set vertex position attribute */ + set_attrib_pointer(0, NV097_SET_VERTEX_DATA_ARRAY_FORMAT_TYPE_F, 4, stride, &buf[0]); + + /* Set vertex diffuse color attribute */ + set_attrib_pointer(3, NV097_SET_VERTEX_DATA_ARRAY_FORMAT_TYPE_UB_D3D, 4, stride, &buf[0+4*4]); + + /* Set vertex specular color attribute */ + set_attrib_pointer(4, NV097_SET_VERTEX_DATA_ARRAY_FORMAT_TYPE_UB_D3D, 4, stride, &buf[0+4*4+4]); + + /* Set vertex uv0 attribute */ + set_attrib_pointer(8, NV097_SET_VERTEX_DATA_ARRAY_FORMAT_TYPE_F, 2, stride, &buf[0*4*4+4+4]); + } GLAPI void GLAPIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count) { printf("%s\n", __func__); +#ifdef GPU + prepare_vertices(); + +debugPrint("array {\n"); + /* Begin drawing triangles */ + draw_arrays(NV097_SET_BEGIN_END_OP_TRIANGLES, first, count); +debugPrint("}\n"); + +#endif + +debugPrint("heh.. fuck!\n"); +pb_kill(); +while(1); + for(unsigned int i = 0; i < count; i++) { drawVertex(first + i); } @@ -256,8 +639,65 @@ GLAPI void GLAPIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count) { GLAPI void GLAPIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const void *indices) { printf("%s\n", __func__); +//debugPrint("elements: %d\n", count); + + // Skip empty draws + if (count == 0) { + return; + } + + assert(count <= 2000); + + assert(type == GL_UNSIGNED_SHORT); uint16_t* i16 = (uint16_t*)((uintptr_t)element_array_buffer + (uintptr_t)indices); + + //FIXME: Why doesn't this work? +#if 1 + //FIXME: Split into multiple of 60 [divisible by 1, 2, 3, 4, 5] element batches + if (count > 60) { + glDrawElements(mode, 60, type, indices); + glDrawElements(mode, count - 60, type, (uintptr_t)indices + 2*60); + return; + } +#endif + + +#ifdef GPU + prepare_vertices(); + + //FIXME: Make sure this is always the right mode! + int gpu_mode = NV097_SET_BEGIN_END_OP_TRIANGLES; + + uint32_t *p = pb_begin(); + + pb_push1(p, NV097_SET_BEGIN_END, gpu_mode); p += 2; + + unsigned int pair_count = count / 2; + if (pair_count > 0) { + + pb_push(p++,0x40000000|NV097_ARRAY_ELEMENT16, pair_count); //bit 30 means all params go to same register + + for(unsigned int i = 0; i < pair_count; i++) { + //FIXME: memcpy instead (endianess?) + *(p++) = (i16[2 * i + 1] << 16) | i16[2 * i + 0]; + } + } + + if (count & 1) { + pb_push(p++, NV097_ARRAY_ELEMENT32, 1); *p++ = i16[count - 1]; + } + + pb_push(p++, NV097_SET_BEGIN_END, 1); *p++ = NV097_SET_BEGIN_END_OP_END; + + pb_end(p); + +#if 0 +pb_kill(); +while(1); +#endif +#endif + for(unsigned int i = 0; i < count; i++) { drawVertex(i16[i]); } @@ -365,11 +805,21 @@ GLAPI void GLAPIENTRY _glBindVertexArray(GLuint array) { GLAPI void GLAPIENTRY _glBufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage) { printf("%s\n", __func__); + if (target == GL_ELEMENT_ARRAY_BUFFER) { + // Xbox puts element arrays into FIFO, so only accessed by CPU element_array_buffer = realloc(element_array_buffer, size); memcpy(element_array_buffer, data, size); } else if (target == GL_ARRAY_BUFFER) { - array_buffer = realloc(array_buffer, size); + // Xbox accesses vertices with GPU, so must be non-paged + + //FIXME: Only wait if buffer is in use + while(pb_busy()) { + /* Wait for completion... */ + } + + if (array_buffer != NULL) { MmFreeContiguousMemory(array_buffer); } + array_buffer = MmAllocateContiguousMemoryEx(size, 0, 0x3ffb000, 0, 0x404); memcpy(array_buffer, data, size); } else if (target == GL_PIXEL_UNPACK_BUFFER) { //FIXME: !!! @@ -619,11 +1069,77 @@ const Uint8* SDL_GetKeyboardState(int* numkeys) { printf("%s\n", __func__); static unsigned char keys[256]; memset(keys, 0x00, sizeof(keys)); + + int pad = 0; + + //FIXME: Poll input - This is a hack! because of shitty USB code + XInput_GetEvents(); + + keys[SDL_SCANCODE_ESCAPE] |= g_Pads[pad].CurrentButtons.ucAnalogButtons[XPAD_B] >> 7; + keys[SDL_SCANCODE_RETURN] |= g_Pads[pad].CurrentButtons.ucAnalogButtons[XPAD_A] >> 7; + keys[SDL_SCANCODE_SPACE] |= g_Pads[pad].CurrentButtons.ucAnalogButtons[XPAD_X] >> 7; + keys[SDL_SCANCODE_UP] |= (g_Pads[pad].CurrentButtons.usDigitalButtons & XPAD_DPAD_UP) ? 1 : 0; + keys[SDL_SCANCODE_DOWN] |= (g_Pads[pad].CurrentButtons.usDigitalButtons & XPAD_DPAD_DOWN) ? 1 : 0; + keys[SDL_SCANCODE_LEFT] |= (g_Pads[pad].CurrentButtons.usDigitalButtons & XPAD_DPAD_LEFT) ? 1 : 0; + keys[SDL_SCANCODE_RIGHT] |= (g_Pads[pad].CurrentButtons.usDigitalButtons & XPAD_DPAD_RIGHT) ? 1 : 0; + keys[SDL_SCANCODE_Q] |= 0; + keys[SDL_SCANCODE_W] |= 0; + keys[SDL_SCANCODE_E] |= 0; + keys[SDL_SCANCODE_R] |= 0; + keys[SDL_SCANCODE_I] |= 0; + keys[SDL_SCANCODE_A] |= 0; + keys[SDL_SCANCODE_S] |= 0; + keys[SDL_SCANCODE_D] |= 0; + keys[SDL_SCANCODE_F] |= 0; + keys[SDL_SCANCODE_J] |= 0; + keys[SDL_SCANCODE_K] |= 0; + keys[SDL_SCANCODE_L] |= 0; + keys[SDL_SCANCODE_M] |= 0; + keys[SDL_SCANCODE_F1] |= 0; + keys[SDL_SCANCODE_F2] |= 0; + keys[SDL_SCANCODE_F3] |= 0; + keys[SDL_SCANCODE_F4] |= 0; + keys[SDL_SCANCODE_F5] |= 0; + keys[SDL_SCANCODE_F6] |= 0; + keys[SDL_SCANCODE_F7] |= 0; + keys[SDL_SCANCODE_F12] |= 0; + keys[SDL_SCANCODE_GRAVE] |= 0; + keys[SDL_SCANCODE_EQUALS] |= 0; + keys[SDL_SCANCODE_MINUS] |= 0; + keys[SDL_SCANCODE_TAB] |= 0; + keys[SDL_SCANCODE_CAPSLOCK] |= 0; + keys[SDL_SCANCODE_LSHIFT] |= 0; + keys[SDL_SCANCODE_RSHIFT] |= 0; + keys[SDL_SCANCODE_LCTRL] |= 0; + keys[SDL_SCANCODE_RCTRL] |= 0; + keys[SDL_SCANCODE_LALT] |= 0; + keys[SDL_SCANCODE_RALT] |= 0; + return keys; } Uint32 SDL_GetMouseState(int* x, int* y) { printf("%s\n", __func__); + + //FIXME: Consider time as aspect and use + //mouse_x += dx * dt; + //mouse_y += dy * dt; + + //FIXME: Poll input - This is a hack! because of shitty USB code + XInput_GetEvents(); + + //FIXME: This is just a dirty hack.. remove + mouse_x = SCREEN_WIDTH / 2 + g_Pads[pad].sRThumbX / 64; + mouse_y = -40 + SCREEN_HEIGHT / 2 - g_Pads[pad].sRThumbY / 64; // Hack to pre-select single player + + if (mouse_x < 0) { mouse_x = 0; } + if (mouse_y < 0) { mouse_y = 0; } + if (mouse_x > SCREEN_WIDTH) { mouse_x = SCREEN_WIDTH; } + if (mouse_y > SCREEN_HEIGHT) { mouse_y = SCREEN_HEIGHT; } + + *x = mouse_x; + *y = mouse_y; + return 0; } @@ -656,7 +1172,49 @@ int SDL_GL_SetAttribute(SDL_GLattr attr, int value) { void SDL_GL_SwapWindow(SDL_Window* window) { printf("%s\n", __func__); - saveBuffer(); +#ifdef GPU + + //FIXME: Poll input - This is a hack! because of shitty USB code + XInput_GetEvents(); + + // Draw some text on the screen + pb_print("OpenSWE1R\n"); + extern uint32_t callId; + pb_print("Call: %u\n", callId); + pb_print("Mouse: %u %u\n", mouse_x, mouse_y); + pb_print("Pad: %d %d\n", g_Pads[pad].sRThumbX, g_Pads[pad].sRThumbY); + + pb_draw_text_screen(); + + + // Finish current frame + + while(pb_busy()) { + /* Wait for completion... */ + } + + /* Swap buffers (if we can) */ + while (pb_finished()) { + /* Not ready to swap yet */ + } + + + + + + // Prepare for next frame + + pb_wait_for_vbl(); + pb_reset(); + pb_target_back_buffer(); + +#else + + // Already done during draw: single buffered + +#endif + + //saveBuffer(); return; } diff --git a/xbox.h b/xbox.h index a81aef8..7db9b71 100644 --- a/xbox.h +++ b/xbox.h @@ -1,3 +1,5 @@ #pragma once +void initialize_screen(void); + typedef void (*_PVFV)(void); From 6957b6683774266a76aa7f12584b9357ba1024e2 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Fri, 31 May 2019 12:02:07 +0200 Subject: [PATCH 58/64] textures wip --- emulation.c | 8 +- main.c | 8 + xbox-hacks/ps.ps.cg | 8 +- xbox-hacks/vs.vs.cg | 5 +- xbox.c | 410 ++++++++++++++++++++++++++++++++------------ 5 files changed, 319 insertions(+), 120 deletions(-) diff --git a/emulation.c b/emulation.c index a4cb623..3b14110 100644 --- a/emulation.c +++ b/emulation.c @@ -740,11 +740,11 @@ static unsigned int GetThreadCount() { static void memory_statistics() { #if 0 //#ifdef XBOX - debugPrint(" Memory statistics:\n"); + printf(" Memory statistics:\n"); MM_STATISTICS ms; ms.Length = sizeof(MM_STATISTICS); MmQueryStatistics(&ms); - #define PRINT(stat) debugPrint(" - " #stat ": %d\n", ms.stat); + #define PRINT(stat) printf(" - " #stat ": %d\n", ms.stat); PRINT(TotalPhysicalPages) PRINT(AvailablePages) PRINT(VirtualMemoryBytesCommitted) @@ -757,9 +757,7 @@ static void memory_statistics() { uint32_t esp; asm("mov %%esp, %%eax":"=a"(esp)); - debugPrint(" - Stack: 0x%X\n", esp); - - printf(" - AvailablePages: %d\n", ms.AvailablePages); + printf(" - Stack: 0x%X\n", esp); #endif } diff --git a/main.c b/main.c index 91db377..efcd1a3 100644 --- a/main.c +++ b/main.c @@ -2550,7 +2550,9 @@ HACKY_COM_BEGIN(IDirectDrawSurface4, 25) API(DDSURFACEDESC2)* desc = Memory(stack[3]); memcpy(desc, &this->desc, sizeof(API(DDSURFACEDESC2))); +#if 0 printf("%d x %d (pitch: %d); bpp = %d; at 0x%08X\n", desc->dwWidth, desc->dwHeight, desc->lPitch, desc->ddpfPixelFormat.dwRGBBitCount, desc->lpSurface); +#endif #if 0 desc->dwWidth = 16; desc->dwHeight = 16; @@ -3195,11 +3197,13 @@ HACKY_COM_BEGIN(IDirect3DDevice3, 25) //FIXME: assert(false) once this runs faster break; } +#if 0 printf("Matrix %d:\n", a); printf(" %f\t%f\t%f\t%f\n", m[ 0], m[ 1], m[ 2], m[ 3]); printf(" %f\t%f\t%f\t%f\n", m[ 4], m[ 5], m[ 6], m[ 7]); printf(" %f\t%f\t%f\t%f\n", m[ 8], m[ 9], m[10], m[11]); printf(" %f\t%f\t%f\t%f\n", m[12], m[13], m[14], m[15]); +#endif eax = 0; // FIXME: No idea what this expects to return.. esp += 3 * 4; @@ -3595,7 +3599,9 @@ HACKY_COM_BEGIN(IDirectInputDeviceA, 10) UpdateKeyboardState(); uint32_t* count = (uint32_t*)Memory(stack[4]); unsigned int max_count = *count; +#if 0 printf("max count is %d\n", max_count); +#endif *count = 0; unsigned int objectSize = stack[2]; assert(objectSize == sizeof(API(DIDEVICEOBJECTDATA))); @@ -3613,7 +3619,9 @@ HACKY_COM_BEGIN(IDirectInputDeviceA, 10) } } memcpy(previousState, keyboardState, sizeof(keyboardState)); +#if 0 printf("returning %d entries\n", *count); +#endif eax = 0; // FIXME: No idea what this expects to return.. esp += 5 * 4; diff --git a/xbox-hacks/ps.ps.cg b/xbox-hacks/ps.ps.cg index 76a31c8..d953772 100644 --- a/xbox-hacks/ps.ps.cg +++ b/xbox-hacks/ps.ps.cg @@ -5,7 +5,11 @@ struct vOut { float2 uv0 : TEXCOORD0; }; -float4 main(vOut I) : COLOR +float4 main( + vOut I, + uniform sampler2D tex0 +) : COLOR { - return I.diffuse; + float4 color = tex2D(tex0, I.uv0.xy) * I.diffuse; + return color; } diff --git a/xbox-hacks/vs.vs.cg b/xbox-hacks/vs.vs.cg index c0faaaf..027dae2 100644 --- a/xbox-hacks/vs.vs.cg +++ b/xbox-hacks/vs.vs.cg @@ -15,7 +15,8 @@ struct vOut { vOut main( vIn I, uniform float3 clipScale, - uniform float3 clipOffset + uniform float3 clipOffset, + uniform float2 tex0Scale ) { vOut result; @@ -32,6 +33,6 @@ vOut main( result.position = position; result.diffuse = I.diffuse; result.specular = I.specular; - result.uv0 = I.uv0; + result.uv0 = I.uv0 * tex0Scale; return result; } diff --git a/xbox.c b/xbox.c index 8841625..d068937 100644 --- a/xbox.c +++ b/xbox.c @@ -4,6 +4,20 @@ // Some of these will likely be stubbed / disabled in OpenSWE1R. // However, it's currently not known which parts exactly; so this is a hack. + + + +// Some hacks.. +//#define DUMP_TEXTURE +#define SAME_TEXTURE // Without this, Xbox will run out of memory +#define USE_TEXTURES +#define MARK_VERTICES +//#define LOG + + + + + #include #include @@ -34,7 +48,9 @@ static const int pad = 0; static int mouse_x = 0; static int mouse_y = 0; +#ifndef LOG #define printf(fmt, ...) {} +#endif @@ -61,61 +77,9 @@ static int mouse_y = 0; #include #endif -#if 0 -typedef struct { - float pos[3]; - float color[3]; -} __attribute__((packed)) ColoredVertex; - -static const ColoredVertex verts[] = { - // X Y Z R G B - {{-1.0, -1.0, 1.0}, { 0.1, 0.1, 0.6}}, /* Background triangle 1 */ - {{-1.0, 1.0, 1.0}, { 0.0, 0.0, 0.0}}, - {{ 1.0, 1.0, 1.0}, { 0.0, 0.0, 0.0}}, - {{-1.0, -1.0, 1.0}, { 0.1, 0.1, 0.6}}, /* Background triangle 2 */ - {{ 1.0, 1.0, 1.0}, { 0.0, 0.0, 0.0}}, - {{ 1.0, -1.0, 1.0}, { 0.1, 0.1, 0.6}}, - {{-1.0, -1.0, 1.0}, { 1.0, 0.0, 0.0}}, /* Foreground triangle */ - {{ 0.0, 1.0, 1.0}, { 0.0, 1.0, 0.0}}, - {{ 1.0, -1.0, 1.0}, { 0.0, 0.0, 1.0}}, -}; -#endif #define MASK(mask, val) (((val) << (ffs(mask)-1)) & (mask)) -/* Main program function */ -static void triangle_main(void) { - uint32_t *p; - int i, status; - int width, height; - int start, last, now; - int fps, frames, frames_total; - - - - - - - - - - - -} - -/* Construct a viewport transformation matrix */ -static void matrix_viewport(float out[4][4], float x, float y, float width, float height, float z_min, float z_max) -{ - memset(out, 0, 4*4*sizeof(float)); - out[0][0] = width/2.0f; - out[1][1] = height/-2.0f; - out[2][2] = z_max - z_min; - out[3][3] = 1.0f; - out[3][0] = x + width/2.0f; - out[3][1] = y + height/2.0f; - out[3][2] = z_min; -} - // We need ou own, as pb_erase_depth_stencil_buffer doesn't support giving a value static void erase_depth_stencil_buffer(int x, int y, int w, int h) { @@ -127,16 +91,23 @@ static void erase_depth_stencil_buffer(int x, int y, int w, int h) y1=y; x2=x+w; y2=y+h; - + printf("zclear{"); p=pb_begin(); pb_push(p++,NV20_TCL_PRIMITIVE_3D_CLEAR_VALUE_HORIZ,2); //sets rectangle coordinates *(p++)=((x2-1)<<16)|x1; *(p++)=((y2-1)<<16)|y1; pb_push(p++,NV20_TCL_PRIMITIVE_3D_CLEAR_VALUE_DEPTH,3); //sets data used to fill in rectangle - *(p++)=0xffffff00; //(depth<<8)|stencil - *(p++)=0; //color - *(p++)=0x03; //triggers the HW rectangle fill (only on D&S) + if (SCREEN_BPP == 32) { + *(p++)=0xffffff00; //(depth<<8)|stencil + *(p++)=0; //color + *(p++)=0x03; //triggers the HW rectangle fill (only on D&S) + } else { + *(p++)=0xffff; //depth + *(p++)=0; //color + *(p++)=0x01; //triggers the HW rectangle fill (only on D&S) + } pb_end(p); + printf("}"); } /* Load the shader we will render with */ @@ -339,6 +310,9 @@ int alSourceStop(int a0) { static void* element_array_buffer = NULL; static void* array_buffer = NULL; +#ifdef USE_TEXTURES +static void** pixel_unpack_buffer = NULL; +#endif extern float clipScale[]; extern float clipOffset[]; @@ -351,9 +325,28 @@ uint8_t buffer[640*480] = {0}; #define GLAPI // __stdcall +#ifdef USE_TEXTURES +typedef struct { + GLenum type; + void** pbo; + unsigned int width; + unsigned int height; +} Texture; + +static Texture* texture_2d = NULL; +#endif GLAPI void GLAPIENTRY glBindTexture (GLenum target, GLuint texture) { printf("%s\n", __func__); + + assert(target == GL_TEXTURE_2D); + +#ifdef USE_TEXTURES + texture_2d = texture; + + printf("TEX Binding %p\n", texture); +#endif + return; } @@ -383,8 +376,7 @@ GLAPI void GLAPIENTRY glClear (GLbitfield mask) { erase_depth_stencil_buffer(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); //FIXME: Check flag - pb_fill(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0x00000000); //FIXME: Use proper color - pb_erase_text_screen(); + pb_fill(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0xff202020); //FIXME: Use proper color //FIXME: Why? while(pb_busy()) { @@ -455,6 +447,7 @@ static void saveBuffer() { } #endif +#ifdef MARK_VERTICES static void drawVertex(int i) { GLsizei stride = 4 * 4 + 4 + 4 + 2 * 4; @@ -531,13 +524,15 @@ static void drawVertex(int i) { #endif } +#endif +#ifdef GPU static void prepare_vertices(void) { uint32_t *p; #if 1 // Be a bit paranoid.. - //FIXME: Remove if confirmed to not change anything + //FIXME: Need to handle ringbuffer in pbkit.. while(pb_busy()) { /* Wait for completion... */ } @@ -545,6 +540,120 @@ static void prepare_vertices(void) { #endif +#ifdef USE_TEXTURES + +#if 0 + Texture t; + t.width = 32; + t.height = 32; + t.type = GL_UNSIGNED_BYTE; + static uint32_t* xxx = NULL; + if (xxx == NULL) { + xxx = MmAllocateContiguousMemoryEx(t.width * t.height * 4, 0, 0x3ffb000, 0, 0x404); + for(int y = 0; y < t.height; y++) { + for(int x = 0; x < t.width; x++) { + xxx[y * t.width + x] = ((x + (y & 8)) & 8) ? 0xFFFFFFFF : 0xFF0000FF; + } + } + } + void* pbo = xxx; + t.pbo = &pbo; + texture_2d = &t; +#endif + +#if 1 + /* Enable texture stage 0 */ + if (texture_2d != NULL) { + + void** pbo = texture_2d->pbo; + uintptr_t pixels = *pbo; + unsigned int width = texture_2d->width; + unsigned int height = texture_2d->height; + + uint32_t fmt = 0; + unsigned int pitch = 0; + switch(texture_2d->type) { + case GL_UNSIGNED_BYTE: { + fmt = NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_B8G8R8A8; + pitch = width * 4; +#ifdef DUMP_TEXTURE + FILE* f = fopen("rgba8888.bin", "wb"); + fwrite(pixels, pitch * height, 1, f); + fclose(f); +#endif + break; + } + case GL_UNSIGNED_SHORT_1_5_5_5_REV: { +#define NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_R5G5B5A1 0x3D + fmt = NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_R5G5B5A1; + pitch = width * 2; +#ifdef DUMP_TEXTURE + FILE* f = fopen("rgba5551.bin", "wb"); + fwrite(pixels, pitch * height, 1, f); + fclose(f); +#endif + break; + } + case GL_UNSIGNED_SHORT_4_4_4_4_REV: { + fmt = NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_A4R4G4B4; + pitch = width * 2; +#ifdef DUMP_TEXTURE + FILE* f = fopen("rgba4444.bin", "wb"); + fwrite(pixels, pitch * height, 1, f); + fclose(f); +#endif + break; + } + default: + assert(false); + break; + } + + printf("%s done\n", __func__); + + p=pb_begin(); + pb_push2(p,NV20_TCL_PRIMITIVE_3D_TX_OFFSET(0),(DWORD)(MmGetPhysicalAddress(pixels) & 0x03ffffff), (0x0001002a | (fmt << 8))); p+=3; //set stage 0 texture address & format + pb_push1(p,NV20_TCL_PRIMITIVE_3D_TX_NPOT_PITCH(0),pitch<<16); p+=2; //set stage 0 texture pitch (pitch<<16) + pb_push1(p,NV20_TCL_PRIMITIVE_3D_TX_NPOT_SIZE(0),(width<<16)|height); p+=2; //set stage 0 texture width & height ((witdh<<16)|height) + //pb_push1(p,NV20_TCL_PRIMITIVE_3D_TX_WRAP(0),0x00010101); p+=2;//set stage 0 texture modes (0x0W0V0U wrapping: 1=wrap 2=mirror 3=clamp 4=border 5=clamp to edge) + pb_push1(p,NV20_TCL_PRIMITIVE_3D_TX_ENABLE(0),0x4003ffc0); p+=2; //set stage 0 texture enable flags + //pb_push1(p,NV20_TCL_PRIMITIVE_3D_TX_FILTER(0),0x04074000); p+=2; //set stage 0 texture filters (AA!) + pb_end(p); + + printf("TEX Activated %p: %u x %u (pitch: %u), PBO: %p pixels: %p / %p\n", texture_2d, width, height, pitch, pbo, pixels, (void*)MmGetPhysicalAddress(pixels)); + + } else { + + p=pb_begin(); + pb_push1(p,NV20_TCL_PRIMITIVE_3D_TX_ENABLE(0),0x0003ffc0); p+=2;//set stage 0 texture enable flags (bit30 disabled) + pb_push1(p,NV20_TCL_PRIMITIVE_3D_TX_WRAP(0),0x00030303); p+=2;//set stage 0 texture modes (0x0W0V0U wrapping: 1=wrap 2=mirror 3=clamp 4=border 5=clamp to edge) + pb_push1(p,NV20_TCL_PRIMITIVE_3D_TX_FILTER(0),0x02022000); p+=2;//set stage 0 texture filters (no AA, stage not even used) + pb_end(p); + + printf("TEX Deactivated\n"); + + } +#endif + + // Disable other texture stages + + p=pb_begin(); + + pb_push1(p,NV20_TCL_PRIMITIVE_3D_TX_ENABLE(1),0x0003ffc0); p+=2;//set stage 1 texture enable flags (bit30 disabled) + pb_push1(p,NV20_TCL_PRIMITIVE_3D_TX_WRAP(1),0x00030303); p+=2;//set stage 1 texture modes (0x0W0V0U wrapping: 1=wrap 2=mirror 3=clamp 4=border 5=clamp to edge) + pb_push1(p,NV20_TCL_PRIMITIVE_3D_TX_FILTER(1),0x02022000); p+=2;//set stage 1 texture filters (no AA, stage not even used) + + pb_push1(p,NV20_TCL_PRIMITIVE_3D_TX_ENABLE(2),0x0003ffc0); p+=2;//set stage 2 texture enable flags (bit30 disabled) + pb_push1(p,NV20_TCL_PRIMITIVE_3D_TX_WRAP(2),0x00030303); p+=2;//set stage 2 texture modes (0x0W0V0U wrapping: 1=wrap 2=mirror 3=clamp 4=border 5=clamp to edge) + pb_push1(p,NV20_TCL_PRIMITIVE_3D_TX_FILTER(2),0x02022000); p+=2;//set stage 2 texture filters (no AA, stage not even used) + + pb_push1(p,NV20_TCL_PRIMITIVE_3D_TX_ENABLE(3),0x0003ffc0); p+=2;//set stage 3 texture enable flags (bit30 disabled) + pb_push1(p,NV20_TCL_PRIMITIVE_3D_TX_WRAP(3),0x00030303); p+=2;//set stage 3 texture modes (0x0W0V0U wrapping: 1=wrap 2=mirror 3=clamp 4=border 5=clamp to edge) + pb_push1(p,NV20_TCL_PRIMITIVE_3D_TX_FILTER(3),0x02022000); p+=2;//set stage 3 texture filters (no AA, stage not even used) + + pb_end(p); +#endif + // Setup matrix { @@ -562,14 +671,20 @@ static void prepare_vertices(void) { pb_push1(p, NV097_SET_TRANSFORM_CONSTANT_LOAD, 96); p+=2; /* Send the transformation matrix */ - float c2[4] = {1, 320, -240, 0}; - float c3[4] = {320, 240, 65536, 1}; - pb_push(p++, NV097_SET_TRANSFORM_CONSTANT, 4 * 4); +#ifdef USE_TEXTURES + float tex0Scale[4] = { texture_2d->width, texture_2d->height, 0, 0 }; +#else + float tex0Scale[4] = { 1, 1, 0, 0 }; +#endif + float c3[4] = {1, 320, -240, 0}; + float c4[4] = {320, 240, 65536, 1}; + pb_push(p++, NV097_SET_TRANSFORM_CONSTANT, 5 * 4); memset(p, 0x00, (4 * 4) *4); memcpy(p, clipScale, 3*4); p+=4; // c0 memcpy(p, clipOffset, 3*4); p+=4; // c1 - memcpy(p, c2, 4*4); p+=4; - memcpy(p, c3, 4*4); p+=4; + memcpy(p, tex0Scale, 4*4); p+=4; // c2 + memcpy(p, c3, 4*4); p+=4; // c3 + memcpy(p, c4, 4*4); p+=4; // c4 pb_end(p); } @@ -578,10 +693,14 @@ static void prepare_vertices(void) { p = pb_begin(); #if 1 - // Set up wireframe mode - pb_push2(p,NV20_TCL_PRIMITIVE_3D_POLYGON_MODE_FRONT,0x1B01,0x1B01); p+=3; //FillMode="solid" BackFillMode="point" + //FIXME: Debug hack to set up wireframe mode + unsigned int fill_mode = (g_Pads[pad].CurrentButtons.ucAnalogButtons[XPAD_WHITE] > 0x20) ? 0x1B01 : 0x1B02; + + pb_push2(p,NV20_TCL_PRIMITIVE_3D_POLYGON_MODE_FRONT,fill_mode,fill_mode); p+=3; //FillMode="solid" BackFillMode="point" + + pb_push1(p,NV20_TCL_PRIMITIVE_3D_CULL_FACE_ENABLE,0); p+=2;//CullModeEnable=TRUE - pb_push1(p,NV20_TCL_PRIMITIVE_3D_DEPTH_TEST_ENABLE,0); p+=2; //ZEnable=TRUE or FALSE (But don't use W, see below) + pb_push1(p,NV20_TCL_PRIMITIVE_3D_DEPTH_TEST_ENABLE,0); p+=2; //ZEnable=TRUE or FALSE (But don't use W) #endif /* Clear all attributes */ @@ -595,7 +714,7 @@ static void prepare_vertices(void) { size_t stride = 4 * 4 + 4 + 4 + 2 * 4; //FIXME: Is this right? our sample doesn't use phys address... - uint8_t* buf = MmGetPhysicalAddress(array_buffer); + uint8_t* buf = MmGetPhysicalAddress(array_buffer); //FIXME: & 0x03ffffff ? /* Set vertex position attribute */ @@ -608,9 +727,10 @@ static void prepare_vertices(void) { set_attrib_pointer(4, NV097_SET_VERTEX_DATA_ARRAY_FORMAT_TYPE_UB_D3D, 4, stride, &buf[0+4*4+4]); /* Set vertex uv0 attribute */ - set_attrib_pointer(8, NV097_SET_VERTEX_DATA_ARRAY_FORMAT_TYPE_F, 2, stride, &buf[0*4*4+4+4]); + set_attrib_pointer(8, NV097_SET_VERTEX_DATA_ARRAY_FORMAT_TYPE_F, 2, stride, &buf[0+4*4+4+4]); } +#endif GLAPI void GLAPIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count) { printf("%s\n", __func__); @@ -629,9 +749,11 @@ debugPrint("heh.. fuck!\n"); pb_kill(); while(1); +#ifdef MARK_VERTICES for(unsigned int i = 0; i < count; i++) { drawVertex(first + i); } +#endif return; } @@ -652,22 +774,36 @@ GLAPI void GLAPIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, c assert(type == GL_UNSIGNED_SHORT); uint16_t* i16 = (uint16_t*)((uintptr_t)element_array_buffer + (uintptr_t)indices); - //FIXME: Why doesn't this work? +#ifdef GPU + + //FIXME: Why doesn't this work? still only draws some of them #if 1 //FIXME: Split into multiple of 60 [divisible by 1, 2, 3, 4, 5] element batches - if (count > 60) { - glDrawElements(mode, 60, type, indices); - glDrawElements(mode, count - 60, type, (uintptr_t)indices + 2*60); + unsigned int batch = 60; + if (count > batch) { + printf("...batch: %d\n", count); + + //FIXME: Debug hack to only draw last vertices + if (!(g_Pads[pad].CurrentButtons.ucAnalogButtons[XPAD_BLACK] > 0x20)) { + glDrawElements(mode, batch, type, indices); + } + + glDrawElements(mode, count - batch, type, ((uintptr_t)indices) + 2*batch); return; } #endif -#ifdef GPU prepare_vertices(); //FIXME: Make sure this is always the right mode! - int gpu_mode = NV097_SET_BEGIN_END_OP_TRIANGLES; + int gpu_mode = 0; + if (mode == GL_TRIANGLES) { + gpu_mode = NV097_SET_BEGIN_END_OP_TRIANGLES; + } else { + printf("Oops! mode %d\n", mode); + assert(false); + } uint32_t *p = pb_begin(); @@ -698,9 +834,11 @@ while(1); #endif #endif +#ifdef MARK_VERTICES for(unsigned int i = 0; i < count; i++) { drawVertex(i16[i]); } +#endif return; } @@ -712,6 +850,19 @@ GLAPI void GLAPIENTRY glEnable (GLenum cap) { GLAPI void GLAPIENTRY glGenTextures (GLsizei n, GLuint *textures) { printf("%s\n", __func__); + + assert(n == 1); + +#ifdef USE_TEXTURES + + Texture* texture = malloc(sizeof(Texture)); + memset(texture, 0x00, sizeof(Texture)); + + textures[0] = texture; + + printf("TEX Created %p\n", texture); +#endif + return; } @@ -733,36 +884,24 @@ GLAPI void GLAPIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height GLAPI void GLAPIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) { printf("%s\n", __func__); - //FIXME: Add support for PBOs - if (pixels == NULL) { - return; - } + assert(target == GL_TEXTURE_2D); - switch(type) { - case GL_UNSIGNED_BYTE: { - FILE* f = fopen("rgba8888.bin", "wb"); - fwrite(pixels, width * height * 4, 1, f); - fclose(f); - break; - } - case GL_UNSIGNED_SHORT_1_5_5_5_REV: { - FILE* f = fopen("rgba5551.bin", "wb"); - fwrite(pixels, width * height * 2, 1, f); - fclose(f); - break; - } - case GL_UNSIGNED_SHORT_4_4_4_4_REV: { - FILE* f = fopen("rgba4444.bin", "wb"); - fwrite(pixels, width * height * 2, 1, f); - fclose(f); - break; - } - default: - assert(false); - break; - } +#ifdef USE_TEXTURES + assert(texture_2d != NULL); // Texture should be set + + assert(pixel_unpack_buffer != NULL); // PBO should be set + assert(*pixel_unpack_buffer != NULL); // PBO should contain data + + assert(pixels == NULL); // PBO data should always be at base + + // Point texture at PBO, so we can find the data + texture_2d->pbo = pixel_unpack_buffer; + texture_2d->type = type; // Keep track of type + texture_2d->width = width; + texture_2d->height = height; - printf("%s done\n", __func__); + printf("TEX Image %p %d x %d, type: %d, PBO: %p\n", texture_2d, width, height, type, pixel_unpack_buffer); +#endif return; } @@ -795,6 +934,13 @@ GLAPI void GLAPIENTRY _glAttachShader(GLuint program, GLuint shader) { GLAPI void GLAPIENTRY _glBindBuffer(GLenum target, GLuint buffer) { printf("%s\n", __func__); + +#ifdef USE_TEXTURES + if (target == GL_PIXEL_UNPACK_BUFFER) { + pixel_unpack_buffer = buffer; + } +#endif + return; } @@ -822,7 +968,25 @@ GLAPI void GLAPIENTRY _glBufferData(GLenum target, GLsizeiptr size, const void* array_buffer = MmAllocateContiguousMemoryEx(size, 0, 0x3ffb000, 0, 0x404); memcpy(array_buffer, data, size); } else if (target == GL_PIXEL_UNPACK_BUFFER) { - //FIXME: !!! +#ifdef USE_TEXTURES + assert(pixel_unpack_buffer != NULL); // PBO must be bound + +#ifdef SAME_TEXTURE + static void* large_pbo = NULL; + { + size_t fake_size = 640*480*4; + assert(size <= fake_size); + if (large_pbo == NULL) { + large_pbo = MmAllocateContiguousMemoryEx(fake_size, 0, 0x3ffb000, 0, 0x404); + } + } + *pixel_unpack_buffer = large_pbo; +#else + *pixel_unpack_buffer = MmAllocateContiguousMemoryEx(size, 0, 0x3ffb000, 0, 0x404); + if (*pixel_unpack_buffer != NULL) { MmFreeContiguousMemory(*pixel_unpack_buffer); } +#endif + memcpy(*pixel_unpack_buffer, data, size); +#endif } else { assert(false); } @@ -859,8 +1023,18 @@ GLAPI void GLAPIENTRY _glEnableVertexAttribArray(GLuint index) { return; } -GLAPI void GLAPIENTRY _glGenBuffers(int a0, unsigned int* a1) { +GLAPI void GLAPIENTRY _glGenBuffers(GLsizei n, GLuint * buffers) { + printf("%s\n", __func__); + + assert(n == 1); + + // Allocate a pointer to buffer + void** ptr = malloc(sizeof(void*)); + *ptr = NULL; + + buffers[0] = ptr; + return; } @@ -876,11 +1050,25 @@ GLAPI GLint GLAPIENTRY _glGetAttribLocation(GLuint program, const GLchar *name) GLAPI void * GLAPIENTRY _glMapBuffer(GLenum target, GLenum access) { printf("%s\n", __func__); - return 0; + + assert(target == GL_PIXEL_UNPACK_BUFFER); + +#ifdef USE_TEXTURES + + assert(pixel_unpack_buffer != NULL); // PBO should be set + assert(*pixel_unpack_buffer != NULL); // PBO should contain data + + return *pixel_unpack_buffer; +#else + return NULL; +#endif } GLAPI GLboolean GLAPIENTRY _glUnmapBuffer(GLenum target) { printf("%s\n", __func__); + + assert(target == GL_PIXEL_UNPACK_BUFFER); + return 0; } @@ -1075,9 +1263,9 @@ const Uint8* SDL_GetKeyboardState(int* numkeys) { //FIXME: Poll input - This is a hack! because of shitty USB code XInput_GetEvents(); - keys[SDL_SCANCODE_ESCAPE] |= g_Pads[pad].CurrentButtons.ucAnalogButtons[XPAD_B] >> 7; - keys[SDL_SCANCODE_RETURN] |= g_Pads[pad].CurrentButtons.ucAnalogButtons[XPAD_A] >> 7; - keys[SDL_SCANCODE_SPACE] |= g_Pads[pad].CurrentButtons.ucAnalogButtons[XPAD_X] >> 7; + keys[SDL_SCANCODE_ESCAPE] |= (g_Pads[pad].CurrentButtons.ucAnalogButtons[XPAD_B] > 0x20)? 1 : 0; + keys[SDL_SCANCODE_RETURN] |= (g_Pads[pad].CurrentButtons.ucAnalogButtons[XPAD_A] > 0x20)? 1 : 0; + keys[SDL_SCANCODE_SPACE] |= (g_Pads[pad].CurrentButtons.ucAnalogButtons[XPAD_X] > 0x20)? 1 : 0; keys[SDL_SCANCODE_UP] |= (g_Pads[pad].CurrentButtons.usDigitalButtons & XPAD_DPAD_UP) ? 1 : 0; keys[SDL_SCANCODE_DOWN] |= (g_Pads[pad].CurrentButtons.usDigitalButtons & XPAD_DPAD_DOWN) ? 1 : 0; keys[SDL_SCANCODE_LEFT] |= (g_Pads[pad].CurrentButtons.usDigitalButtons & XPAD_DPAD_LEFT) ? 1 : 0; @@ -1185,7 +1373,7 @@ void SDL_GL_SwapWindow(SDL_Window* window) { pb_print("Pad: %d %d\n", g_Pads[pad].sRThumbX, g_Pads[pad].sRThumbY); pb_draw_text_screen(); - + pb_erase_text_screen(); // Finish current frame @@ -1206,7 +1394,7 @@ void SDL_GL_SwapWindow(SDL_Window* window) { pb_wait_for_vbl(); pb_reset(); - pb_target_back_buffer(); + //pb_target_back_buffer(); #else From 4e5164aacd98a4bc8d50e4089f281367679c6fad Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 6 Jun 2019 00:12:55 +0200 Subject: [PATCH 59/64] Fixups: Fix native non-Xbox compilation --- Makefile.nxdk | 2 +- xbox.c | 80 ++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 65 insertions(+), 17 deletions(-) diff --git a/Makefile.nxdk b/Makefile.nxdk index 6a8babd..d64c2d8 100644 --- a/Makefile.nxdk +++ b/Makefile.nxdk @@ -32,7 +32,7 @@ CFLAGS += -I$(SDL_DIR)/include CFLAGS += -Wno-inconsistent-dllimport #FIXME: Slow mode for pbkit! remove! -CFLAGS += -DGPU=1 +CFLAGS += -DXBOX_GPU=1 CFLAGS += -DDBG=1 # We are short on memory, so reduce binary footprint diff --git a/xbox.c b/xbox.c index d068937..509e675 100644 --- a/xbox.c +++ b/xbox.c @@ -4,6 +4,14 @@ // Some of these will likely be stubbed / disabled in OpenSWE1R. // However, it's currently not known which parts exactly; so this is a hack. +#ifndef XBOX +#ifdef XBOX_GPU +#error Disable XBOX_GPU when XBOX is not enabled +#endif +#endif + + + @@ -18,6 +26,15 @@ + + +#ifndef XBOX_GPU +#ifdef USE_TEXTURES +#warning USE_TEXTURES was disabled because XBOX_GPU is not active +#undef USE_TEXTURES +#endif +#endif + #include #include @@ -37,13 +54,18 @@ #include "SDL.h" +#ifdef XBOX #include +#endif + static int SCREEN_WIDTH = 0; static int SCREEN_HEIGHT = 0; static int SCREEN_BPP = 0; +#ifdef XBOX #include static const int pad = 0; +#endif static int mouse_x = 0; static int mouse_y = 0; @@ -68,14 +90,13 @@ static int mouse_y = 0; #include #include -#ifdef GPU +#ifdef XBOX_GPU #include #include #include #include #include #include -#endif #define MASK(mask, val) (((val) << (ffs(mask)-1)) & (mask)) @@ -187,7 +208,6 @@ static void draw_arrays(unsigned int mode, int start, int count) - void initialize_screen(void) { static bool initialized = false; @@ -202,7 +222,7 @@ void initialize_screen(void) { SCREEN_HEIGHT = vm.height; SCREEN_BPP = vm.bpp; -#ifdef GPU +#ifdef XBOX_GPU // Set up rendering pb_show_front_screen(); int width = pb_back_buffer_width(); @@ -230,6 +250,8 @@ void initialize_screen(void) { initialized = true; } +#endif + // unistd.. thanks SDL void _exit(int status) { @@ -318,7 +340,7 @@ extern float clipScale[]; extern float clipOffset[]; -#ifndef GPU +#ifndef XBOX_GPU uint8_t buffer[640*480] = {0}; #endif @@ -368,7 +390,7 @@ GLAPI void GLAPIENTRY glClearDepth (GLclampd depth) { GLAPI void GLAPIENTRY glClear (GLbitfield mask) { printf("%s\n", __func__); -#ifdef GPU +#ifdef XBOX_GPU /* Clear depth & stencil buffers */ @@ -387,7 +409,9 @@ GLAPI void GLAPIENTRY glClear (GLbitfield mask) { //FIXME: Clear color?! memset(buffer, 0x00, sizeof(buffer)); +#ifdef XBOX debugClearScreen(); +#endif #endif @@ -420,7 +444,7 @@ GLAPI void GLAPIENTRY glDisable (GLenum cap) { } -#ifndef GPU +#ifndef XBOX_GPU static void saveBuffer() { static int t = 0; @@ -497,7 +521,7 @@ static void drawVertex(int i) { //if ((z < 0) || (z > 0xFF)) { return; } z = 0xFF; -#ifdef GPU +#ifdef XBOX_GPU pb_fill(x, y, 1, 1, 0xFF00FFFF); // Cyan @@ -507,7 +531,7 @@ static void drawVertex(int i) { buffer[y * 640 + x] = 0x80 + z / 2; - +#ifdef XBOX // Draw to actual Xbox framebuffer unsigned char *videoBuffer = XVideoGetFB(); videoBuffer += (y * SCREEN_WIDTH + x) * (SCREEN_BPP >> 3); @@ -520,13 +544,14 @@ static void drawVertex(int i) { *((short*)videoBuffer) = 0xFFFF; break; } +#endif #endif } #endif -#ifdef GPU +#ifdef XBOX_GPU static void prepare_vertices(void) { uint32_t *p; @@ -735,7 +760,7 @@ static void prepare_vertices(void) { GLAPI void GLAPIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count) { printf("%s\n", __func__); -#ifdef GPU +#ifdef XBOX_GPU prepare_vertices(); debugPrint("array {\n"); @@ -745,8 +770,12 @@ debugPrint("}\n"); #endif +#ifdef XBOX debugPrint("heh.. fuck!\n"); pb_kill(); +#else +printf("heh.. fuck!\n"); +#endif while(1); #ifdef MARK_VERTICES @@ -774,7 +803,7 @@ GLAPI void GLAPIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, c assert(type == GL_UNSIGNED_SHORT); uint16_t* i16 = (uint16_t*)((uintptr_t)element_array_buffer + (uintptr_t)indices); -#ifdef GPU +#ifdef XBOX_GPU //FIXME: Why doesn't this work? still only draws some of them #if 1 @@ -957,7 +986,9 @@ GLAPI void GLAPIENTRY _glBufferData(GLenum target, GLsizeiptr size, const void* element_array_buffer = realloc(element_array_buffer, size); memcpy(element_array_buffer, data, size); } else if (target == GL_ARRAY_BUFFER) { - // Xbox accesses vertices with GPU, so must be non-paged + // Xbox accesses vertices with XBOX_GPU, so must be non-paged + +#ifdef XBOX_GPU //FIXME: Only wait if buffer is in use while(pb_busy()) { @@ -966,8 +997,18 @@ GLAPI void GLAPIENTRY _glBufferData(GLenum target, GLsizeiptr size, const void* if (array_buffer != NULL) { MmFreeContiguousMemory(array_buffer); } array_buffer = MmAllocateContiguousMemoryEx(size, 0, 0x3ffb000, 0, 0x404); + +#else + + array_buffer = realloc(array_buffer, size); memcpy(array_buffer, data, size); + +#endif + + memcpy(array_buffer, data, size); + } else if (target == GL_PIXEL_UNPACK_BUFFER) { + #ifdef USE_TEXTURES assert(pixel_unpack_buffer != NULL); // PBO must be bound @@ -987,6 +1028,7 @@ GLAPI void GLAPIENTRY _glBufferData(GLenum target, GLsizeiptr size, const void* #endif memcpy(*pixel_unpack_buffer, data, size); #endif + } else { assert(false); } @@ -1258,7 +1300,7 @@ const Uint8* SDL_GetKeyboardState(int* numkeys) { static unsigned char keys[256]; memset(keys, 0x00, sizeof(keys)); - int pad = 0; +#ifdef XBOX //FIXME: Poll input - This is a hack! because of shitty USB code XInput_GetEvents(); @@ -1303,6 +1345,8 @@ const Uint8* SDL_GetKeyboardState(int* numkeys) { keys[SDL_SCANCODE_LALT] |= 0; keys[SDL_SCANCODE_RALT] |= 0; +#endif + return keys; } @@ -1313,12 +1357,14 @@ Uint32 SDL_GetMouseState(int* x, int* y) { //mouse_x += dx * dt; //mouse_y += dy * dt; +#ifdef XBOX //FIXME: Poll input - This is a hack! because of shitty USB code XInput_GetEvents(); //FIXME: This is just a dirty hack.. remove mouse_x = SCREEN_WIDTH / 2 + g_Pads[pad].sRThumbX / 64; mouse_y = -40 + SCREEN_HEIGHT / 2 - g_Pads[pad].sRThumbY / 64; // Hack to pre-select single player +#endif if (mouse_x < 0) { mouse_x = 0; } if (mouse_y < 0) { mouse_y = 0; } @@ -1360,7 +1406,7 @@ int SDL_GL_SetAttribute(SDL_GLattr attr, int value) { void SDL_GL_SwapWindow(SDL_Window* window) { printf("%s\n", __func__); -#ifdef GPU +#ifdef XBOX_GPU //FIXME: Poll input - This is a hack! because of shitty USB code XInput_GetEvents(); @@ -1402,7 +1448,9 @@ void SDL_GL_SwapWindow(SDL_Window* window) { #endif - //saveBuffer(); +#ifndef XBOX + saveBuffer(); +#endif return; } From 0dfe700912b265c3a12856cff8f556ea92deebaa Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Thu, 6 Jun 2019 16:00:02 +0200 Subject: [PATCH 60/64] Dummy allocator for heap --- .gitmodules | 3 ++ CMakeLists.txt | 1 + alloc.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++++ alloc.h | 5 ++ emulation.c | 28 ++++------ tinyalloc | 1 + 6 files changed, 159 insertions(+), 17 deletions(-) create mode 100644 .gitmodules create mode 100644 alloc.c create mode 100644 alloc.h create mode 160000 tinyalloc diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..5d8e2bd --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "tinyalloc"] + path = tinyalloc + url = https://github.com/thi-ng/tinyalloc diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ddd145..ddb9243 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,7 @@ add_executable(openswe1r emulation.c export.c shader.c + alloc.c dll/kernel32.c diff --git a/alloc.c b/alloc.c new file mode 100644 index 0000000..fe90ed5 --- /dev/null +++ b/alloc.c @@ -0,0 +1,138 @@ +// Copyright 2019 OpenSWE1R Maintainers +// Licensed under GPLv2 or any later version +// Refer to the included LICENSE.txt file. + +// This is a temporary placeholder for a memory allocator. + +#include "alloc.h" + +#include +#include +#include +#include +#include + +static unsigned int block_count = 0; +static uint32_t block_size = 0; +static uint8_t* block_usage = NULL; + +static void mark_used(unsigned int block, bool used) { + uint8_t mask = 1 << (block % 8); + if (used) { + block_usage[block / 8] |= mask; + } else { + block_usage[block / 8] &= ~mask; + } +} + +static bool is_used(unsigned int block) { + uint8_t mask = 1 << (block % 8); + return block_usage[block / 8] & mask; +} + +static unsigned int get_block_count(uint32_t size) { + return (size + block_size - 1) / block_size; +} + +static unsigned int count_blocks(unsigned int block, bool used) { + unsigned int count = 0; + while(block < block_count) { + if (is_used(block) != used) { + break; + } + block++; + count++; + } + return count; +} + +static unsigned int find_free_blocks(unsigned int needed_blocks) { + + unsigned int best_count = 0; + unsigned int best_block = 0; + + unsigned int block = 0; + while(block < block_count) { + + bool block_used = is_used(block); + unsigned int available_blocks = count_blocks(block, block_used); + + // Only look at unused blocks that are large enough + if (!block_used && (available_blocks >= needed_blocks)) { + + // Check if we don't have a result yet, or if this is a better fit + if ((best_count == 0) || (available_blocks < best_count)) { + + // Update result + best_block = block; + best_count = available_blocks; + + // If we have an exact fit, use that + if (best_count == needed_blocks) { + break; + } + + } + } + + block += available_blocks; + } + + // Assert that we have a result + assert(best_count != 0); + + // Returns best block address + return best_block; +} + +void alloc_initialize(uint32_t size, uint32_t _block_size) { + + // Sanity check arguments, we expect proper alignment + assert((size % _block_size) == 0); + + // Store settings + block_size = _block_size; + block_count = get_block_count(size); + + // Allocate flags which tell us wether a block is used + size_t used_flag_size = (block_count + 7) / 8; + block_usage = malloc(used_flag_size); + memset(block_usage, 0x00, used_flag_size); + +} + +uint32_t alloc_allocate(uint32_t size) { + + // Don't allow zero-size allocations (breaks algorithm) + assert(size > 0); + + unsigned int needed_blocks = get_block_count(size); + + //FIXME: `+ 2` is a hack, so we can recognize block splits + unsigned int block = find_free_blocks(needed_blocks + 2) + 1; + + printf("Allocated %u blocks (0x%X / 0x%X bytes)\n", needed_blocks, needed_blocks * block_size, size); + + for(unsigned int i = 0; i < needed_blocks; i++) { + mark_used(block + i, true); + } + + return block * block_size; +} + +void alloc_free(uint32_t offset) { + + // Only free addresses that are block-aligned + assert(offset % block_size == 0); + unsigned int block = offset / block_size; + + unsigned int used_blocks = count_blocks(block, true); + + // Avoid double-free + assert(used_blocks > 0); + + for(unsigned int i = 0; i < used_blocks; i++) { + mark_used(block + i, false); + } + +} diff --git a/alloc.h b/alloc.h new file mode 100644 index 0000000..0ac2a07 --- /dev/null +++ b/alloc.h @@ -0,0 +1,5 @@ +#include + +void alloc_initialize(uint32_t size, uint32_t _block_size); +uint32_t alloc_allocate(uint32_t size); +void alloc_free(uint32_t offset); diff --git a/emulation.c b/emulation.c index 3b14110..ce5723a 100644 --- a/emulation.c +++ b/emulation.c @@ -27,6 +27,8 @@ #include #include #endif +#else +#include "alloc.h" #endif //FIXME: These are hacks (register when mapping instead!)! @@ -340,22 +342,14 @@ Address Allocate(Size size) { #ifdef UC_NATIVE Address ret = aligned_malloc(0x1000, size); #else - static uint32_t address = HEAP_ADDRESS; - -#if 1 - //FIXME: This is a hack to fix alignment + to avoid too small allocations - address += 0xFFF; - address &= 0xFFFFF000; -#endif - - Address ret = address; - - address += size; - //FIXME: Proper allocator - - assert(address < (HEAP_ADDRESS + heapSize)); - int use = (address - HEAP_ADDRESS); - printf("%u / %u = %u percent\n", use, heapSize, (use * 100) / heapSize); + static bool initialized = false; + if (!initialized) { + alloc_initialize(heapSize, 0x1000); + initialized = true; + } + uint32_t offset = alloc_allocate(size); + Address ret = heapAddress + offset; + printf("0x%X + 0x%X = 0x%X\n", heapAddress, offset, ret); #endif assert(ret != 0); @@ -372,7 +366,7 @@ void Free(Address address) { #ifdef UC_NATIVE aligned_free(address); #else - //FIXME! + alloc_free(address - heapAddress); #endif } diff --git a/tinyalloc b/tinyalloc new file mode 160000 index 0000000..9ebd4a4 --- /dev/null +++ b/tinyalloc @@ -0,0 +1 @@ +Subproject commit 9ebd4a406bf783a68b0e0ba57545f11f12bf5827 From a910671479e2f9b115a7bf2cbae252f151200522 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 4 Jan 2020 04:55:42 +0100 Subject: [PATCH 61/64] debug.h moved --- main.c | 2 +- xbox.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/main.c b/main.c index efcd1a3..7b6add2 100644 --- a/main.c +++ b/main.c @@ -35,7 +35,7 @@ //FIXME: REMOVE THIS BLOCK! Only used during development #ifdef XBOX -#include +#include #define XboxHackyDebugPrint(fmt, ...) \ do { \ char buf[4096]; \ diff --git a/xbox.c b/xbox.c index 509e675..626fc00 100644 --- a/xbox.c +++ b/xbox.c @@ -96,7 +96,7 @@ static int mouse_y = 0; #include #include #include -#include +#include #define MASK(mask, val) (((val) << (ffs(mask)-1)) & (mask)) From 611d03fdbb1c79866162983278f081f0caebbce6 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 4 Jan 2020 04:55:59 +0100 Subject: [PATCH 62/64] Doesn't work with pbkit DBG because too many commands in push --- Makefile.nxdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.nxdk b/Makefile.nxdk index d64c2d8..887c6f3 100644 --- a/Makefile.nxdk +++ b/Makefile.nxdk @@ -33,7 +33,7 @@ CFLAGS += -Wno-inconsistent-dllimport #FIXME: Slow mode for pbkit! remove! CFLAGS += -DXBOX_GPU=1 -CFLAGS += -DDBG=1 +#CFLAGS += -DDBG=1 #FIXME: !!! # We are short on memory, so reduce binary footprint #CFLAGS += -Os From 186155945aebbf4453472c6c5f59ce6dc0053d51 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 4 Jan 2020 04:56:24 +0100 Subject: [PATCH 63/64] Allocate framebuffer (so debugPrint doesn't corrupt us) --- main.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/main.c b/main.c index 7b6add2..6569801 100644 --- a/main.c +++ b/main.c @@ -4351,6 +4351,17 @@ int main(int argc, char* argv[]) { // Set display mode (16bpp to save memory) //FIXME: Temporarily switched to 32bpp, as I got weird issues at 16bpp XVideoSetMode(640, 480, 32, REFRESH_DEFAULT); + +#if 1 + // We consume a lot of memory, so we need to claim the framebuffer + size_t fb_size = 640 * 480 * 4; + extern uint8_t* _fb; + _fb = (uint8_t*)MmAllocateContiguousMemoryEx(fb_size, 0, 0xFFFFFFFF, 0x1000, PAGE_READWRITE | PAGE_WRITECOMBINE); + memset(_fb, 0x00, fb_size); +#define _PCRTC_START 0xFD600800 + *(unsigned int*)(_PCRTC_START) = (unsigned int)_fb & 0x03FFFFFF; + debugPrint("FB: 0x%X\n", _fb); +#endif // Startup pbkit pb_init(); From e908beca001f9a74ef97bacdff85aa383f9b4181 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Sat, 4 Jan 2020 06:53:25 +0100 Subject: [PATCH 64/64] improve clear --- xbox.c | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/xbox.c b/xbox.c index 626fc00..5b8c00d 100644 --- a/xbox.c +++ b/xbox.c @@ -387,6 +387,12 @@ GLAPI void GLAPIENTRY glClearDepth (GLclampd depth) { return; } +static GLint scissor_x = 0; +static GLint scissor_y = 0; +static GLsizei scissor_w = 0; +static GLsizei scissor_h = 0; +static bool scissor_enable = false; + GLAPI void GLAPIENTRY glClear (GLbitfield mask) { printf("%s\n", __func__); @@ -394,11 +400,25 @@ GLAPI void GLAPIENTRY glClear (GLbitfield mask) { /* Clear depth & stencil buffers */ - //FIXME: Check flag - erase_depth_stencil_buffer(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); + unsigned int x = 0; + unsigned int y = 0; + unsigned int w = 640; + unsigned int h = 480; + if (scissor_enable) { + x = scissor_x; + y = scissor_y; + w = scissor_w; + h = scissor_h; + } - //FIXME: Check flag - pb_fill(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0xff202020); //FIXME: Use proper color + if ((mask & GL_DEPTH_BUFFER_BIT) || (mask & GL_STENCIL_BUFFER_BIT)) { + //FIXME: Avoid flags collision (where we only want to clear one of them) + erase_depth_stencil_buffer(x, y, w, h); + } + + if (mask & GL_COLOR_BUFFER_BIT) { + pb_fill(x, y, w, h, 0xff202020); //FIXME: Use proper color + } //FIXME: Why? while(pb_busy()) { @@ -440,6 +460,10 @@ GLAPI void GLAPIENTRY glDepthMask (GLboolean flag) { GLAPI void GLAPIENTRY glDisable (GLenum cap) { printf("%s\n", __func__); + switch(cap) { + case GL_SCISSOR_TEST: scissor_enable = false; break; + default: break; + } return; } @@ -874,6 +898,10 @@ while(1); GLAPI void GLAPIENTRY glEnable (GLenum cap) { printf("%s\n", __func__); + switch(cap) { + case GL_SCISSOR_TEST: scissor_enable = true; break; + default: break; + } return; } @@ -907,6 +935,10 @@ GLAPI void GLAPIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei hei GLAPI void GLAPIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height) { printf("%s\n", __func__); + scissor_x = x; + scissor_y = y; + scissor_w = width; + scissor_h = height; return; }