Created
May 29, 2020 18:03
-
-
Save RSDuck/a28c41add2177a5604439884e732feef to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Include the most common headers from the C standard library | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <malloc.h> | |
#include <stdint.h> | |
// Include the main libnx system header, for Switch development | |
#include <switch.h> | |
#include <arm_neon.h> | |
typedef uintptr_t mem_handle_t; | |
mem_handle_t vmem_fd = -1; | |
mem_handle_t vmem_fd_page = -1; | |
mem_handle_t vmem_fd_codememory = -1; | |
static mem_handle_t shmem_fd2 = -1; | |
#define PAGE_SIZE (4096) | |
const int RAM_SIZE_MAX = 4096*1024; | |
void *mem_region_reserve(void *start, size_t len) | |
{ | |
#ifdef HAVE_LIBNX | |
return virtmemReserve(len); | |
#else | |
void *p = mmap(start, len, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0); | |
if (p == MAP_FAILED) | |
{ | |
perror("mmap"); | |
return NULL; | |
} | |
else | |
return p; | |
#endif // HAVE_LIBNX | |
} | |
static mem_handle_t allocate_shared_filemem(unsigned size) { | |
int fd = -1; | |
#if defined(_ANDROID) | |
// Use Android's specific shmem stuff. | |
fd = ashmem_create_region(0, size); | |
#elif defined(HAVE_LIBNX) | |
void* mem = memalign(0x1000, size); | |
return (uintptr_t)mem; | |
#else | |
#if HOST_OS != OS_DARWIN | |
fd = shm_open("/dcnzorz_mem", O_CREAT | O_EXCL | O_RDWR, S_IREAD | S_IWRITE); | |
shm_unlink("/dcnzorz_mem"); | |
#endif | |
// if shmem does not work (or using OSX) fallback to a regular file on disk | |
if (fd < 0) { | |
string path = get_writable_data_path("/dcnzorz_mem"); | |
fd = open(path.c_str(), O_CREAT|O_RDWR|O_TRUNC, S_IRWXU|S_IRWXG|S_IRWXO); | |
unlink(path.c_str()); | |
} | |
// If we can't open the file, fallback to slow mem. | |
if (fd < 0) | |
return -1; | |
// Finally make the file as big as we need! | |
if (ftruncate(fd, size)) { | |
// Can't get as much memory as needed, fallback. | |
close(fd); | |
return -1; | |
} | |
#endif | |
return fd; | |
} | |
static void *reserved_base; | |
static size_t reserved_size; | |
#define PAGE_MASK 0xFFF | |
void vmem_platform_init(void **vmem_base_addr, void **sh4rcb_addr) { | |
#ifdef HAVE_LIBNX | |
const unsigned size_aligned = ((RAM_SIZE_MAX + PAGE_SIZE) & (~(PAGE_SIZE-1))); | |
vmem_fd_page = allocate_shared_filemem(size_aligned); | |
vmem_fd_codememory = (uintptr_t)virtmemReserve(size_aligned); | |
if(R_FAILED(svcMapProcessCodeMemory(envGetOwnProcessHandle(), (u64) vmem_fd_codememory, (u64) vmem_fd_page, size_aligned))) | |
printf("Failed to Map memory (platform_int)...\n"); | |
if(R_FAILED(svcSetProcessMemoryPermission(envGetOwnProcessHandle(), vmem_fd_codememory, size_aligned, Perm_Rx))) | |
printf("Failed to set perms (platform_int)...\n"); | |
#else | |
// Firt let's try to allocate the shm-backed memory | |
vmem_fd = allocate_shared_filemem(RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX); | |
if (vmem_fd < 0) | |
return MemTypeError; | |
#endif // HAVE_LIBNX | |
// Now try to allocate a contiguous piece of memory. | |
{ | |
reserved_size = 512*1024*1024 + 0x10000; | |
reserved_base = mem_region_reserve(NULL, reserved_size); | |
if (!reserved_base) { | |
#ifndef HAVE_LIBNX | |
close(vmem_fd); | |
#endif // HAVE_LIBNX | |
return; | |
} | |
} | |
// Align pointer to 64KB too, some Linaro bug (no idea but let's just be safe I guess). | |
uintptr_t ptrint = (uintptr_t)reserved_base; | |
ptrint = (ptrint + 0x10000 - 1) & (~0xffff); | |
*vmem_base_addr = (void*)(ptrint); | |
} | |
bool mem_region_lock(void *start, size_t len) | |
{ | |
size_t inpage = (uintptr_t)start & PAGE_MASK; | |
#ifdef HAVE_LIBNX | |
len += inpage; | |
size_t inlen = len & PAGE_MASK; | |
if(inlen) | |
len = (len + PAGE_SIZE) & (~(PAGE_SIZE-1)); | |
Result rc; | |
uintptr_t start_addr = ((uintptr_t)start - inpage); | |
for(uintptr_t addr = start_addr; addr < (start_addr + len); addr += PAGE_SIZE) | |
{ | |
rc = svcSetMemoryPermission((void*)addr, PAGE_SIZE, Perm_R); | |
if(R_FAILED(rc)) | |
{ | |
printf("Failed to SetPerm Perm_R on %p len 0x%x rc 0x%x\n", (void*)addr, PAGE_SIZE, rc); | |
} | |
} | |
#else | |
if (mprotect((u8*)start - inpage, len + inpage, PROT_READ)) | |
die("mprotect failed..."); | |
#endif // HAVE_LIBNX | |
return true; | |
} | |
bool mem_region_unlock(void *start, size_t len) | |
{ | |
size_t inpage = (uintptr_t)start & PAGE_MASK; | |
#ifdef HAVE_LIBNX | |
len += inpage; | |
size_t inlen = len & PAGE_MASK; | |
if(inlen) | |
len = (len + PAGE_SIZE) & (~(PAGE_SIZE-1)); | |
Result rc; | |
uintptr_t start_addr = ((uintptr_t)start - inpage); | |
for(uintptr_t addr = start_addr; addr < (start_addr + len); addr += PAGE_SIZE) | |
{ | |
rc = svcSetMemoryPermission((void*)addr, PAGE_SIZE, Perm_Rw); | |
if(R_FAILED(rc)) | |
{ | |
printf("Failed to SetPerm Perm_Rw on %p len 0x%x rc 0x%x\n", (void*)addr, PAGE_SIZE, rc); | |
} | |
} | |
#else | |
if (mprotect((u8*)start - inpage, len + inpage, PROT_READ | PROT_WRITE)) | |
// Add some way to see why it failed? gdb> info proc mappings | |
die("mprotect failed..."); | |
#endif // HAVE_LIBNX | |
return true; | |
} | |
void *mem_region_map_file(void *file_handle, void *dest, size_t len, size_t offset, bool readwrite) | |
{ | |
#ifdef HAVE_LIBNX | |
Result rc = svcMapProcessMemory(dest, envGetOwnProcessHandle(), (u64)(vmem_fd_codememory + offset), len); | |
if(R_FAILED(rc)) | |
{ | |
printf("Fatal error creating the view... base: %p offset: 0x%x size: 0x%x src: %p err: 0x%x\n", vmem_fd, offset, len, vmem_fd_codememory + offset, rc); | |
} else { | |
printf("Created the view... base: %p offset: 0x%x size: 0x%x src: %p err: 0x%x\n", vmem_fd, offset, len, vmem_fd_codememory + offset, rc); | |
} | |
return dest; | |
#else | |
int flags = MAP_SHARED | MAP_NOSYNC | (dest != NULL ? MAP_FIXED : 0); | |
void *p = mmap(dest, len, PROT_READ | (readwrite ? PROT_WRITE : 0), flags, (int)(uintptr_t)file_handle, offset); | |
if (p == MAP_FAILED) | |
{ | |
perror("mmap"); | |
return NULL; | |
} | |
else | |
return p; | |
#endif // HAVE_LIBNX | |
} | |
// Main program entrypoint | |
int main(int argc, char* argv[]) | |
{ | |
// This example uses a text console, as a simple way to output text to the screen. | |
// If you want to write a software-rendered graphics application, | |
// take a look at the graphics/simplegfx example, which uses the libnx Framebuffer API instead. | |
// If on the other hand you want to write an OpenGL based application, | |
// take a look at the graphics/opengl set of examples, which uses EGL instead. | |
socketInitializeDefault(); | |
nxlinkStdio(); | |
printf("hallo 1\n"); | |
void* blarg; | |
vmem_platform_init(&blarg, NULL); | |
mem_region_map_file(vmem_fd, blarg, 0x1000, 0, true); | |
((u8*)blarg)[0] = 42; | |
mem_region_lock(blarg, 0x1000); | |
// Other initialization goes here. As a demonstration, we print hello world. | |
printf("Hello World! %d\n", ((u8*)blarg)[0]); | |
// Deinitialize and clean up resources used by the console (important!) | |
socketExit(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment