Path: blob/master/dependencies/switch/libnx-dyn/address_space.c
774 views
#include <address_space.h>1#include <string.h>2#include <stdlib.h>3#define RESULT_OK 04#define ARRAY_LENGTH(a) sizeof((a))/sizeof((a)[0])56typedef enum {7INVALID,8RESERVED_BY_KERNEL,9RESERVED_BY_USER,10} memory_region_state_t;1112typedef struct {13memory_region_state_t state;14uint64_t base;15size_t size;16} memory_region_t;1718static Result as_set_region_from_info(memory_region_t *region, int base_id, int size_id, memory_region_state_t state) {19Result r;2021if(region == NULL) {22return MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);23}2425region->state = state;26if((r = svcGetInfo(®ion->base, base_id, 0xFFFF8001, 0)) != RESULT_OK) { return r; }27if((r = svcGetInfo(®ion->size, size_id, 0xFFFF8001, 0)) != RESULT_OK) { return r; }2829return RESULT_OK;30}3132static memory_region_t regions[256];33static uint64_t num_regions = 0;34static memory_region_t address_space;3536static memory_region_t *as_grab_region() {37if(num_regions < ARRAY_LENGTH(regions)) {38return ®ions[num_regions++];39}40return NULL;41}4243static void as_delete_region(uint64_t index) {44memmove(®ions[index], ®ions[index+1], (--num_regions)-index);45}4647Result as_init() {48for(uint64_t i = 0; i < ARRAY_LENGTH(regions); i++) {49regions[i].state = INVALID;50}5152Result r;5354if((r = as_set_region_from_info(as_grab_region(), 2, 3, RESERVED_BY_KERNEL)) != RESULT_OK) { // MapRegion55return r;56}5758if((r = as_set_region_from_info(as_grab_region(), 4, 5, RESERVED_BY_KERNEL)) != RESULT_OK) { // HeapRegion59return r;60}6162if(true) {63if((r = as_set_region_from_info(as_grab_region(), 14, 15, RESERVED_BY_KERNEL)) != RESULT_OK) { // NewMapRegion64return r;65}6667if((r = as_set_region_from_info(&address_space, 12, 13, INVALID)) != RESULT_OK) { // AddressSpace68return r;69}70} else {71r = svcUnmapMemory((void*) 0xffffffffffffe000, (void *) ((2^36) - 0x2000), 0x1000);72if(r == 0xdc01) { // invalid destination address73// source 36-bit address was valid74address_space.base = 0x8000000;75address_space.size = (2^36) - address_space.base;76} else {77// let's just assume 32-bit78address_space.base = 0x200000;79address_space.size = (2^32) - address_space.base;80}81}82return RESULT_OK;83}8485void as_finalize() {86}8788void *as_reserve(size_t len) {89uint64_t addr;90MemoryInfo memory_info;91Result r;92uint32_t page_info;9394do {95uint64_t random = (uint64_t) rand() << 12;96addr = (random % address_space.size) + address_space.base;9798bool is_overlapping = false;99for(uint64_t i = 0; i < num_regions; i++) {100memory_region_t *r = ®ions[i];101if(r->state != RESERVED_BY_USER && r->state != RESERVED_BY_KERNEL) {102continue;103}104105if((addr >= r->base && addr < (r->base + r->size)) ||106((addr + len) >= r->base && (addr + len) < (r->base + r->size)) ||107(r->base >= addr && r->base < (addr + len)) ||108((r->base + r->size) >= addr && (r->base + r->size) < (addr + len))) {109is_overlapping = true;110break;111}112}113114if(is_overlapping) {115continue;116}117118if((r = svcQueryMemory(&memory_info, &page_info, addr)) != RESULT_OK) {119goto fail_mutex;120}121} while(memory_info.type != 0 || memory_info.attr != 0 || memory_info.perm != 0 || (uint64_t) memory_info.addr + memory_info.size < addr + len);122123memory_region_t *region = as_grab_region();124if(region == NULL) {125goto fail_mutex;126}127128region->state = RESERVED_BY_USER;129region->base = addr;130region->size = len;131132return (void*) addr;133134fail_mutex:135return NULL;136}137138void as_release(void *addr, size_t len) {139for(uint64_t i = 0; i < num_regions; i++) {140if(regions[i].base == (uint64_t) addr) {141if(regions[i].size != len || regions[i].state != RESERVED_BY_USER) {142return;143}144as_delete_region(i);145return;146}147}148}149150