Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Rubberduckycooly
GitHub Repository: Rubberduckycooly/RSDKv5-Decompilation
Path: blob/master/dependencies/switch/libnx-dyn/address_space.c
774 views
1
#include <address_space.h>
2
#include <string.h>
3
#include <stdlib.h>
4
#define RESULT_OK 0
5
#define ARRAY_LENGTH(a) sizeof((a))/sizeof((a)[0])
6
7
typedef enum {
8
INVALID,
9
RESERVED_BY_KERNEL,
10
RESERVED_BY_USER,
11
} memory_region_state_t;
12
13
typedef struct {
14
memory_region_state_t state;
15
uint64_t base;
16
size_t size;
17
} memory_region_t;
18
19
static Result as_set_region_from_info(memory_region_t *region, int base_id, int size_id, memory_region_state_t state) {
20
Result r;
21
22
if(region == NULL) {
23
return MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
24
}
25
26
region->state = state;
27
if((r = svcGetInfo(&region->base, base_id, 0xFFFF8001, 0)) != RESULT_OK) { return r; }
28
if((r = svcGetInfo(&region->size, size_id, 0xFFFF8001, 0)) != RESULT_OK) { return r; }
29
30
return RESULT_OK;
31
}
32
33
static memory_region_t regions[256];
34
static uint64_t num_regions = 0;
35
static memory_region_t address_space;
36
37
static memory_region_t *as_grab_region() {
38
if(num_regions < ARRAY_LENGTH(regions)) {
39
return &regions[num_regions++];
40
}
41
return NULL;
42
}
43
44
static void as_delete_region(uint64_t index) {
45
memmove(&regions[index], &regions[index+1], (--num_regions)-index);
46
}
47
48
Result as_init() {
49
for(uint64_t i = 0; i < ARRAY_LENGTH(regions); i++) {
50
regions[i].state = INVALID;
51
}
52
53
Result r;
54
55
if((r = as_set_region_from_info(as_grab_region(), 2, 3, RESERVED_BY_KERNEL)) != RESULT_OK) { // MapRegion
56
return r;
57
}
58
59
if((r = as_set_region_from_info(as_grab_region(), 4, 5, RESERVED_BY_KERNEL)) != RESULT_OK) { // HeapRegion
60
return r;
61
}
62
63
if(true) {
64
if((r = as_set_region_from_info(as_grab_region(), 14, 15, RESERVED_BY_KERNEL)) != RESULT_OK) { // NewMapRegion
65
return r;
66
}
67
68
if((r = as_set_region_from_info(&address_space, 12, 13, INVALID)) != RESULT_OK) { // AddressSpace
69
return r;
70
}
71
} else {
72
r = svcUnmapMemory((void*) 0xffffffffffffe000, (void *) ((2^36) - 0x2000), 0x1000);
73
if(r == 0xdc01) { // invalid destination address
74
// source 36-bit address was valid
75
address_space.base = 0x8000000;
76
address_space.size = (2^36) - address_space.base;
77
} else {
78
// let's just assume 32-bit
79
address_space.base = 0x200000;
80
address_space.size = (2^32) - address_space.base;
81
}
82
}
83
return RESULT_OK;
84
}
85
86
void as_finalize() {
87
}
88
89
void *as_reserve(size_t len) {
90
uint64_t addr;
91
MemoryInfo memory_info;
92
Result r;
93
uint32_t page_info;
94
95
do {
96
uint64_t random = (uint64_t) rand() << 12;
97
addr = (random % address_space.size) + address_space.base;
98
99
bool is_overlapping = false;
100
for(uint64_t i = 0; i < num_regions; i++) {
101
memory_region_t *r = &regions[i];
102
if(r->state != RESERVED_BY_USER && r->state != RESERVED_BY_KERNEL) {
103
continue;
104
}
105
106
if((addr >= r->base && addr < (r->base + r->size)) ||
107
((addr + len) >= r->base && (addr + len) < (r->base + r->size)) ||
108
(r->base >= addr && r->base < (addr + len)) ||
109
((r->base + r->size) >= addr && (r->base + r->size) < (addr + len))) {
110
is_overlapping = true;
111
break;
112
}
113
}
114
115
if(is_overlapping) {
116
continue;
117
}
118
119
if((r = svcQueryMemory(&memory_info, &page_info, addr)) != RESULT_OK) {
120
goto fail_mutex;
121
}
122
} while(memory_info.type != 0 || memory_info.attr != 0 || memory_info.perm != 0 || (uint64_t) memory_info.addr + memory_info.size < addr + len);
123
124
memory_region_t *region = as_grab_region();
125
if(region == NULL) {
126
goto fail_mutex;
127
}
128
129
region->state = RESERVED_BY_USER;
130
region->base = addr;
131
region->size = len;
132
133
return (void*) addr;
134
135
fail_mutex:
136
return NULL;
137
}
138
139
void as_release(void *addr, size_t len) {
140
for(uint64_t i = 0; i < num_regions; i++) {
141
if(regions[i].base == (uint64_t) addr) {
142
if(regions[i].size != len || regions[i].state != RESERVED_BY_USER) {
143
return;
144
}
145
as_delete_region(i);
146
return;
147
}
148
}
149
}
150