taiHEN  1.0
CFW framework for PS Vita
proc_map.c
1 /* proc_map.c -- map structure for organizing patches
2  *
3  * Copyright (C) 2016 Yifan Lu
4  *
5  * This software may be modified and distributed under the terms
6  * of the MIT license. See the LICENSE file for details.
7  */
8 #include <psp2kern/types.h>
9 #include <psp2kern/kernel/sysmem.h>
10 #include <psp2kern/kernel/threadmgr.h>
11 #include <string.h>
12 #include "taihen_internal.h"
13 #include "proc_map.h"
14 #include "slab.h"
15 
23 #define MAP_POOL_SIZE 1024
24 
26 extern const size_t g_exe_slab_item_size;
27 
29 static SceUID g_map_pool;
30 
38 int proc_map_init(void) {
39  SceKernelMemPoolCreateOpt opt;
40  memset(&opt, 0, sizeof(opt));
41  opt.size = sizeof(opt);
42  opt.uselock = 1;
43  g_map_pool = sceKernelMemPoolCreate("tai_maps", MAP_POOL_SIZE, &opt);
44  if (g_map_pool < 0) {
45  return g_map_pool;
46  } else {
47  return 0;
48  }
49 }
50 
56 void proc_map_deinit(void) {
57  sceKernelMemPoolDestroy(g_map_pool);
58  g_map_pool = 0;
59 }
60 
70  tai_proc_map_t *map;
71 
72  map = sceKernelMemPoolAlloc(g_map_pool, sizeof(tai_proc_map_t) + sizeof(tai_proc_t *) * nbuckets);
73  if (map == NULL) {
74  return NULL;
75  }
76  map->nbuckets = nbuckets;
77  map->lock = sceKernelCreateMutexForKernel("tai_map", SCE_KERNEL_MUTEX_ATTR_RECURSIVE, 0, NULL);
78  for (int i = 0; i < nbuckets; i++) {
79  map->buckets[i] = NULL;
80  }
81  return map;
82 }
83 
90  sceKernelDeleteMutexForKernel(map->lock);
91  sceKernelMemPoolFree(g_map_pool, map);
92 }
93 
115  int idx;
116  int overlap;
117  tai_proc_t **item, *proc;
118  tai_patch_t **cur, *tmp;
119 
120  idx = patch->pid % map->nbuckets;
121  *existing = NULL;
122 
123  // get proc structure if found
124  sceKernelLockMutexForKernel(map->lock, 1, NULL);
125  item = &map->buckets[idx];
126  while (*item != NULL && (*item)->pid < patch->pid) {
127  item = &(*item)->next;
128  }
129  if (*item != NULL && (*item)->pid == patch->pid) {
130  // existing block
131  proc = *item;
132  } else {
133  // new block
134  proc = sceKernelMemPoolAlloc(g_map_pool, sizeof(tai_proc_t));
135  proc->pid = patch->pid;
136  proc->head = NULL;
137  proc->next = *item;
138  slab_init(&proc->slab, g_exe_slab_item_size, patch->pid);
139  *item = proc;
140  }
141 
142  // now insert into range if needed
143  cur = &proc->head;
144  overlap = 0;
145  while (*cur != NULL) {
146  tmp = *cur;
147  if (tmp->addr < patch->addr) {
148  if (tmp->addr + tmp->size <= patch->addr) {
149  // cur block is completely before our block
150  cur = &(*cur)->next;
151  continue;
152  } else {
153  // cur block's end overlaps with our block's start
154  overlap = 1;
155  }
156  } else if (patch->addr < tmp->addr) {
157  if (patch->addr + patch->size > tmp->addr) {
158  // cur block's start over overlaps with our block's end
159  overlap = 1;
160  } else {
161  // cur block is completely after our block, this is where we insert
162  }
163  } else { // tmp->addr == patch->addr
164  if (patch->size == tmp->size) {
165  // completely overlap
166  overlap = 1;
167  *existing = tmp;
168  }
169  }
170  break;
171  }
172  if (!overlap) {
173  patch->next = *cur;
174  patch->slab = &proc->slab;
175  *cur = patch;
176  }
177  sceKernelUnlockMutexForKernel(map->lock, 1);
178  return !overlap;
179 }
180 
202 int proc_map_remove_all_pid(tai_proc_map_t *map, SceUID pid, tai_patch_t **head) {
203  int idx;
204  tai_proc_t **cur, *tmp;
205 
206  idx = pid % map->nbuckets;
207  *head = NULL;
208  sceKernelLockMutexForKernel(map->lock, 1, NULL);
209  cur = &map->buckets[idx];
210  while (*cur != NULL && (*cur)->pid < pid) {
211  cur = &(*cur)->next;
212  }
213  if (*cur != NULL && (*cur)->pid == pid) {
214  tmp = *cur;
215  *cur = tmp->next;
216  *head = tmp->head;
217  slab_destroy(&tmp->slab);
218  sceKernelMemPoolFree(g_map_pool, tmp);
219  }
220  sceKernelUnlockMutexForKernel(map->lock, 1);
221  return *head != NULL;
222 }
223 
234  int idx;
235  int found;
236  tai_proc_t **proc, *next;
237  tai_patch_t **cur;
238 
239  idx = patch->pid % map->nbuckets;
240  found = 0;
241  sceKernelLockMutexForKernel(map->lock, 1, NULL);
242  proc = &map->buckets[idx];
243  while (*proc != NULL && (*proc)->pid < patch->pid) {
244  proc = &(*proc)->next;
245  }
246  if (*proc != NULL && (*proc)->pid == patch->pid) {
247  cur = &(*proc)->head;
248  while (*cur != NULL && *cur != patch) {
249  cur = &(*cur)->next;
250  }
251  if (*cur != NULL) {
252  *cur = patch->next;
253  found = 1;
254  }
255  }
256  if (*proc != NULL && (*proc)->head == NULL) { // it's now empty
257  patch->slab = NULL; // remove reference
258  next = (*proc)->next;
259  slab_destroy(&(*proc)->slab);
260  sceKernelMemPoolFree(g_map_pool, *proc);
261  *proc = next;
262  }
263  sceKernelUnlockMutexForKernel(map->lock, 1);
264  return found;
265 }
SceUID lock
Mutex for accessing buckets.
Definition: proc_map.h:25
tai_proc_map_t * proc_map_alloc(int nbuckets)
Allocates a new map.
Definition: proc_map.c:69
struct _tai_proc * next
Next process in this map bucket.
void proc_map_deinit(void)
Cleans up the map system.
Definition: proc_map.c:56
The actual map in memory.
Definition: proc_map.h:23
size_t size
Size of the patch.
struct _tai_patch * next
Next patch in the linked list for this process.
uintptr_t addr
Address being patched.
Internal data for a process.
int proc_map_remove(tai_proc_map_t *map, tai_patch_t *patch)
Remove a single patch from the map.
Definition: proc_map.c:233
void proc_map_free(tai_proc_map_t *map)
Frees a map.
Definition: proc_map.c:89
tai_proc_t * buckets[]
Buckets.
Definition: proc_map.h:26
A patch containing either a hook chain or an injection.
struct slab_chain * slab
Slab chain for this process (copied from the owner tai_proc_t)
int proc_map_remove_all_pid(tai_proc_map_t *map, SceUID pid, tai_patch_t **head)
Removes every patch associated with a given pid from the map.
Definition: proc_map.c:202
int nbuckets
Number of buckets set by proc_map_alloc
Definition: proc_map.h:24
SceUID pid
Process owning this object.
struct slab_chain slab
A slab allocator associated with this process.
SceUID pid
Process ID (the key in the map)
tai_patch_t * head
Linked list of patches for this process.
int proc_map_try_insert(tai_proc_map_t *map, tai_patch_t *patch, tai_patch_t **existing)
Inserts into the map if no overlap or get patch that completely overlaps.
Definition: proc_map.c:114
int proc_map_init(void)
Initializes the map system.
Definition: proc_map.c:38