Skip to content

Instantly share code, notes, and snippets.

@RSDuck
Created May 29, 2020 18:03
Show Gist options
  • Save RSDuck/a28c41add2177a5604439884e732feef to your computer and use it in GitHub Desktop.
Save RSDuck/a28c41add2177a5604439884e732feef to your computer and use it in GitHub Desktop.
// 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