Skip to content

Commit

Permalink
Start work on the new but swapchain-based Zink, based on the old patc…
Browse files Browse the repository at this point in the history
…hes for Mesa
  • Loading branch information
artdeell committed Jun 5, 2023
1 parent 2e17542 commit 7f05281
Show file tree
Hide file tree
Showing 12 changed files with 323 additions and 775 deletions.
17 changes: 16 additions & 1 deletion app_pojavlauncher/src/main/jni/Android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,24 @@ LOCAL_SRC_FILES := \
environ/environ.c \
input_bridge_v3.c \
jre_launcher.c \
utils.c
utils.c \
driver_helper/nsbypass.c
ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
LOCAL_CFLAGS += -DADRENO_POSSIBLE
LOCAL_LDLIBS += -lEGL -lGLESv2
endif
include $(BUILD_SHARED_LIBRARY)

#ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
include $(CLEAR_VARS)
LOCAL_MODULE := linkerhook
LOCAL_SRC_FILES := driver_helper/hook.c
LOCAL_LDLIBS := -llog
LOCAL_LDFLAGS := -z global
include $(BUILD_SHARED_LIBRARY)
#endif


include $(CLEAR_VARS)
LOCAL_MODULE := istdio
LOCAL_SHARED_LIBRARIES := xhook
Expand Down
2 changes: 1 addition & 1 deletion app_pojavlauncher/src/main/jni/Application.mk
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# NDK_TOOLCHAIN_VERSION := 4.9
APP_PLATFORM := android-21
APP_STL := system
APP_STL := c++_static
# APP_ABI := armeabi-v7a arm64-v8a x86 x86_64
11 changes: 9 additions & 2 deletions app_pojavlauncher/src/main/jni/ctxbridges/osmesa_loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,20 @@
#include <stdlib.h>
#include <dlfcn.h>
#include "osmesa_loader.h"

#include <android/log.h>
GLboolean (*OSMesaMakeCurrent_p) (OSMesaContext ctx, void *buffer, GLenum type,
GLsizei width, GLsizei height);
OSMesaContext (*OSMesaGetCurrentContext_p) (void);
OSMesaContext (*OSMesaCreateContext_p) (GLenum format, OSMesaContext sharelist);
void (*OSMesaDestroyContext_p) (OSMesaContext ctx);
void (*OSMesaFlushFrontbuffer_p) ();
void (*OSMesaPixelStore_p) ( GLint pname, GLint value );
GLubyte* (*glGetString_p) (GLenum name);
void (*glFinish_p) (void);
void (*glClearColor_p) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
void (*glClear_p) (GLbitfield mask);
void (*glReadPixels_p) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void * data);
void (*glReadBuffer_p) (GLenum mode);

void dlsym_OSMesa() {
char* main_path = NULL;
Expand All @@ -28,15 +30,20 @@ void dlsym_OSMesa() {
void* dl_handle = NULL;
dl_handle = dlopen(alt_path, RTLD_GLOBAL);
if(dl_handle == NULL) dl_handle = dlopen(main_path, RTLD_GLOBAL);
if(dl_handle == NULL) abort();
if(dl_handle == NULL) {
__android_log_print(ANDROID_LOG_INFO, "osmesa_loader", "failed to load OSMesa %s", dlerror());
abort();
}
OSMesaMakeCurrent_p = dlsym(dl_handle, "OSMesaMakeCurrent");
OSMesaGetCurrentContext_p = dlsym(dl_handle,"OSMesaGetCurrentContext");
OSMesaCreateContext_p = dlsym(dl_handle, "OSMesaCreateContext");
OSMesaDestroyContext_p = dlsym(dl_handle, "OSMesaDestroyContext");
OSMesaFlushFrontbuffer_p = dlsym(dl_handle, "OSMesaFlushFrontbuffer");
OSMesaPixelStore_p = dlsym(dl_handle,"OSMesaPixelStore");
glGetString_p = dlsym(dl_handle,"glGetString");
glClearColor_p = dlsym(dl_handle, "glClearColor");
glClear_p = dlsym(dl_handle,"glClear");
glFinish_p = dlsym(dl_handle,"glFinish");
glReadPixels_p = dlsym(dl_handle,"glReadPixels");
glReadBuffer_p = dlsym(dl_handle, "glReadBuffer");
}
2 changes: 2 additions & 0 deletions app_pojavlauncher/src/main/jni/ctxbridges/osmesa_loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ extern GLboolean (*OSMesaMakeCurrent_p) (OSMesaContext ctx, void *buffer, GLenum
extern OSMesaContext (*OSMesaGetCurrentContext_p) (void);
extern OSMesaContext (*OSMesaCreateContext_p) (GLenum format, OSMesaContext sharelist);
extern void (*OSMesaDestroyContext_p) (OSMesaContext ctx);
extern void (*OSMesaFlushFrontbuffer_p) ();
extern void (*OSMesaPixelStore_p) ( GLint pname, GLint value );
extern GLubyte* (*glGetString_p) (GLenum name);
extern void (*glFinish_p) (void);
extern void (*glClearColor_p) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
extern void (*glClear_p) (GLbitfield mask);
extern void (*glReadPixels_p) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void * data);
extern void (*glReadBuffer_p) (GLenum mode);
void dlsym_OSMesa();
#endif //POJAVLAUNCHER_OSMESA_LOADER_H
43 changes: 43 additions & 0 deletions app_pojavlauncher/src/main/jni/driver_helper/hook.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//
// Created by maks on 05.06.2023.
//
#include <android/dlext.h>
#include <android/log.h>
#include <string.h>

typedef void* (*android_dlopen_ext_t)(const char *filename, int flags, const android_dlextinfo *extinfo);
typedef struct android_namespace_t* (*android_get_exported_namespace_t)(const char* name);

static void* ready_handle;
static android_dlopen_ext_t original_func;
static android_get_exported_namespace_t android_get_exported_namespace;

static const char *sphal_namespaces[3] = {
"sphal", "vendor", "default"
};


__attribute__((visibility("default"))) void app__pojav_linkerhook_set_data(void* data, void* data1, void* data2) {
ready_handle = data;
original_func = data1;
android_get_exported_namespace = data2;
}

__attribute__((visibility("default"))) void *android_dlopen_ext(const char *filename, int flags, const android_dlextinfo *extinfo) {
if(!strstr(filename, "vulkan."))
return original_func(filename, flags, extinfo);
return ready_handle;
}

__attribute__((visibility("default"))) void *android_load_sphal_library(const char *filename, int flags) {
if(strstr(filename, "vulkan.")) return ready_handle;
struct android_namespace_t* androidNamespace;
for(int i = 0; i < 3; i++) {
androidNamespace = android_get_exported_namespace(sphal_namespaces[i]);
if(androidNamespace != NULL) break;
}
android_dlextinfo info;
info.flags = ANDROID_DLEXT_USE_NAMESPACE;
info.library_namespace = androidNamespace;
return original_func(filename, flags, &info);
}
164 changes: 164 additions & 0 deletions app_pojavlauncher/src/main/jni/driver_helper/nsbypass.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
//
// Created by maks on 05.06.2023.
//
#include "nsbypass.h"
#include <dlfcn.h>
#include <android/dlext.h>
#include <android/log.h>
#include <sys/mman.h>
#include <sys/user.h>
#include <string.h>
#include <stdio.h>
#include <linux/limits.h>
#include <errno.h>
#include <unistd.h>
#include <asm/unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <elf.h>

/* upper 6 bits of an ARM64 instruction are the instruction name */
#define OP_MS 0b11111100000000000000000000000000

This comment has been minimized.

Copy link
@SolDev69

SolDev69 Jun 13, 2023

Contributor

At the moment this is 64bit only, will there be a 32bit version?

This comment has been minimized.

Copy link
@AjTheOpsuGamer

AjTheOpsuGamer via email Jun 13, 2023

/* Branch Label instruction opcode and immediate mask */
#define BL_OP 0b10010100000000000000000000000000
#define BL_IM 0b00000011111111111111111111111111
/* Library search path */
#define SEARCH_PATH "/system/lib64"
#define ELF_EHDR Elf64_Ehdr
#define ELF_SHDR Elf64_Shdr
#define ELF_HALF Elf64_Half
#define ELF_XWORD Elf64_Xword
#define ELF_DYN Elf64_Dyn

//#define ADRENO_POSSIBLE

typedef void* (*loader_dlopen_t)(const char* filename, int flags, const void* caller_addr);

typedef struct android_namespace_t* (*ld_android_create_namespace_t)(
const char* name, const char* ld_library_path, const char* default_library_path, uint64_t type,
const char* permitted_when_isolated_path, struct android_namespace_t* parent, const void* caller_addr);

typedef struct android_namespace_t* (*ld_android_get_exported_namespace_t)(const char* name, const void* caller_addr);

static ld_android_create_namespace_t android_create_namespace;
static ld_android_get_exported_namespace_t android_get_exported_namespace;
static struct android_namespace_t* namespace;

struct android_namespace_t* local_android_create_namespace(
const char* name, const char* ld_library_path, const char* default_library_path, uint64_t type,
const char* permitted_when_isolated_path, struct android_namespace_t* parent) {
void* caller = __builtin_return_address(0);
return android_create_namespace(name, ld_library_path, default_library_path, type, permitted_when_isolated_path, parent, caller);
}

struct android_namespace_t* ns_android_get_exported_namespace(
const char* name) {
void* caller = __builtin_return_address(0);
return android_get_exported_namespace(name, caller);
}


bool linker_ns_load(const char* lib_search_path) {
#ifndef ADRENO_POSSIBLE
return false;
#endif
uint32_t *dlext_bl_addr = (uint32_t*)&dlopen;
while((*dlext_bl_addr & OP_MS) !=
BL_OP) dlext_bl_addr++; //walk through the function until we find the label that we need to go to
__android_log_print(ANDROID_LOG_INFO, "nsbypass", "found branch label: %u", *dlext_bl_addr);
loader_dlopen_t loader_dlopen;
loader_dlopen = (loader_dlopen_t)(((char *) dlext_bl_addr) + (*dlext_bl_addr & BL_IM)*4);
mprotect(loader_dlopen, PAGE_SIZE, PROT_WRITE | PROT_READ | PROT_EXEC); // reprotecting the function removes protection from indirect jumps
void* ld_android_handle = loader_dlopen("ld-android.so", RTLD_LAZY, &dlopen);
__android_log_print(ANDROID_LOG_INFO, "nsbypass", "ld-android.so handle: %p", ld_android_handle);
if(ld_android_handle == NULL) return false;
android_create_namespace = dlsym(ld_android_handle, "__loader_android_create_namespace");
android_get_exported_namespace = dlsym(ld_android_handle, "__loader_android_get_exported_namespace");
if(android_create_namespace == NULL || android_get_exported_namespace == NULL) {
dlclose(ld_android_handle);
return false;
}
char full_path[strlen(SEARCH_PATH) + strlen(lib_search_path) + 2 + 1];
sprintf(full_path, "%s:%s", SEARCH_PATH, lib_search_path);
namespace = local_android_create_namespace("pojav-driver",
full_path,
full_path,
3 /* TYPE_SHAFED | TYPE_ISOLATED */,
"/system/:/data/:/vendor/:/apex/", NULL);
return true;
}

void* linker_ns_dlopen(const char* name, int flag) {
#ifndef ADRENO_POSSIBLE
return NULL;
#endif
android_dlextinfo dlextinfo;
dlextinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
dlextinfo.library_namespace = namespace;
return android_dlopen_ext(name, flag, &dlextinfo);
}

bool patch_elf_soname(int patchfd, int realfd, uint16_t patchid) {
struct stat realstat;
if(fstat(realfd, &realstat)) return false;
if(ftruncate(patchfd, realstat.st_size) == -1) return false;
char* target = mmap(NULL, realstat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, patchfd, 0);
if(!target) return false;
if(read(realfd, target, realstat.st_size) != realstat.st_size) {
munmap(target, realstat.st_size);
return false;
}
close(realfd);


ELF_EHDR *ehdr = (ELF_EHDR*)target;
ELF_SHDR *shdr = (ELF_SHDR*)(target + ehdr->e_shoff);
for(ELF_HALF i = 0; i < ehdr->e_shnum; i++) {
ELF_SHDR *hdr = &shdr[i];
if(hdr->sh_type == SHT_DYNAMIC) {
char* strtab = target + shdr[hdr->sh_link].sh_offset;
ELF_DYN *dynEntries = (ELF_DYN*)(target + hdr->sh_offset);
for(ELF_XWORD k = 0; k < (hdr->sh_size / hdr->sh_entsize);k++) {
ELF_DYN* dynEntry = &dynEntries[k];
if(dynEntry->d_tag == DT_SONAME) {
char* soname = strtab + dynEntry->d_un.d_val;
char sprb[4];
snprintf(sprb, 4, "%03x", patchid);
memcpy(soname, sprb, 3);
munmap(target, realstat.st_size);
return true;
}
}
}
}
return false;
}

void* linker_ns_dlopen_unique(const char* tmpdir, const char* name, int flags) {
#ifndef ADRENO_POSSIBLE
return NULL;
#endif
char pathbuf[PATH_MAX];
static uint16_t patch_id;
int patch_fd, real_fd;
snprintf(pathbuf,PATH_MAX,"%s/%d_p.so", tmpdir, patch_id);
patch_fd = open(pathbuf, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if(patch_fd == -1) return NULL;
snprintf(pathbuf,PATH_MAX,"%s/%s", SEARCH_PATH, name);
real_fd = open(pathbuf, O_RDONLY);
if(real_fd == -1) {
close(patch_fd);
return NULL;
}
if(!patch_elf_soname(patch_fd, real_fd, patch_id)) {
close(patch_fd);
close(real_fd);
return NULL;
}
android_dlextinfo extinfo;
extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE | ANDROID_DLEXT_USE_LIBRARY_FD;
extinfo.library_fd = patch_fd;
extinfo.library_namespace = namespace;
snprintf(pathbuf, PATH_MAX, "/proc/self/fd/%d", patch_fd);
return android_dlopen_ext(pathbuf, flags, &extinfo);
}
15 changes: 15 additions & 0 deletions app_pojavlauncher/src/main/jni/driver_helper/nsbypass.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// Created by maks on 05.06.2023.
//

#ifndef POJAVLAUNCHER_NSBYPASS_H
#define POJAVLAUNCHER_NSBYPASS_H

#include <stdbool.h>

bool linker_ns_load(const char* lib_search_path);
void* linker_ns_dlopen(const char* name, int flag);
void* linker_ns_dlopen_unique(const char* tmpdir, const char* name, int flag);
struct android_namespace_t* ns_android_get_exported_namespace(const char*);

#endif //POJAVLAUNCHER_NSBYPASS_H
Loading

0 comments on commit 7f05281

Please sign in to comment.