PS2SDK
PS2 Homebrew Libraries
sysmem.c
1 /*
2 # _____ ___ ____ ___ ____
3 # ____| | ____| | | |____|
4 # | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5 #-----------------------------------------------------------------------
6 # Copyright ps2dev - http://www.ps2dev.org
7 # Licenced under Academic Free License version 2.0
8 # Review ps2sdk README & LICENSE files for further details.
9 */
10 
11 #include "sysmem.h"
12 #include "xsysmem.h"
13 
14 extern struct irx_export_table _exp_sysmem;
15 
16 #ifdef _IOP
17 IRX_ID("System_Memory_Manager", 2, 3);
18 #endif
19 // Based on the module from SCE SDK 3.1.0.
20 
21 static sysmem_internals_t g_sysmem_internals;
22 static KprintfHandler_t *g_kprintf_cb;
23 static void *g_kprintf_cb_userdata;
24 
25 extern int sysmem_reinit(void);
26 static int cCpuSuspendIntr(int *state);
27 static int cCpuResumeIntr(int state);
28 static void *allocSysMemory_internal(int flags, int size, const void *mem);
29 static int freeSysMemory_internal(const void *ptr);
30 static void updateSmemCtlBlk(void);
31 static sysmem_alloc_block_t *search_block(const void *address);
32 
33 typedef struct intrman_callbacks_
34 {
35  int (*cbCpuSuspendIntr)(int *state);
36  int (*cbCpuResumeIntr)(int state);
37  // cppcheck-suppress unusedStructMember
38  int (*cbQueryIntrContext)(void);
40 
41 int _start(unsigned int memsize)
42 {
43  memsize = (memsize > 0x7FFF00) ? 0x7FFF00 : memsize;
44  g_sysmem_internals.m_alloclist =
45  ((memsize & 0xFFFFFF00) >= ((((uiptr)((&g_sysmem_internals))) + sizeof(g_sysmem_internals) + 255) >> 8 << 8)
46  + sizeof(sysmem_alloc_table_t)) ?
47  (sysmem_alloc_table_t *)((((uiptr)((&g_sysmem_internals))) + sizeof(g_sysmem_internals) + 255) >> 8 << 8) :
48  NULL;
49  g_sysmem_internals.m_memsize = memsize & 0xFFFFFF00;
50  g_sysmem_internals.m_intr_suspend_tbl = NULL;
51  g_sysmem_internals.m_allocation_count = 0;
52  g_sysmem_internals.m_smemupdate_cur = NULL;
53  return g_sysmem_internals.m_alloclist ? sysmem_reinit() : 0;
54 }
55 
56 int sysmem_reinit(void)
57 {
58  sysmem_alloc_table_t *alloclist;
59  unsigned int i;
60  const sysmem_alloc_block_t *blklist;
61 
62  alloclist = g_sysmem_internals.m_alloclist;
63  if ( !alloclist )
64  return 0;
65  alloclist->m_next = NULL;
66  for ( i = 0; i < (sizeof(alloclist->m_blkarray) / sizeof(alloclist->m_blkarray[0])); i += 1 )
67  {
68  alloclist->m_blkarray[i].m_next = &(alloclist->m_blkarray[i + 1]);
69  alloclist->m_blkarray[i].m_info.m_allocated = 0;
70  alloclist->m_blkarray[i].m_info.m_address = 0;
71  alloclist->m_blkarray[i].m_info.m_pad = 0;
72  alloclist->m_blkarray[i].m_info.m_size = 0;
73  }
74  alloclist->m_blkarray[(sizeof(alloclist->m_blkarray) / sizeof(alloclist->m_blkarray[0])) - 1].m_next = NULL;
75  alloclist->m_blkarray[0].m_info.m_size = g_sysmem_internals.m_memsize >> 8;
76  g_sysmem_internals.m_allocation_count = 1;
77  if (
78  AllocSysMemory(ALLOC_FIRST, (int)alloclist, NULL) != NULL
79  || (sysmem_alloc_table_t *)AllocSysMemory(ALLOC_FIRST, sizeof(*alloclist) - sizeof(alloclist->m_padding), NULL)
80  != alloclist )
81  {
82  g_sysmem_internals.m_alloclist = NULL;
83  return 0;
84  }
85  for ( blklist = alloclist->m_blkarray; blklist; blklist = blklist->m_next )
86  if ( !blklist->m_info.m_allocated )
87  return blklist->m_info.m_address << 8;
88  return 0;
89 }
90 
91 u32 QueryMemSize()
92 {
93  return g_sysmem_internals.m_alloclist ? g_sysmem_internals.m_memsize : 0;
94 }
95 
96 u32 QueryMaxFreeMemSize()
97 {
98  unsigned int retval;
99  const sysmem_alloc_block_t *blklist;
100  int state;
101 
102  retval = 0;
103  if ( !g_sysmem_internals.m_alloclist )
104  return 0;
105  cCpuSuspendIntr(&state);
106  for ( blklist = g_sysmem_internals.m_alloclist->m_blkarray; blklist; blklist = blklist->m_next )
107  if ( !blklist->m_info.m_allocated && retval < blklist->m_info.m_size )
108  retval = blklist->m_info.m_size;
109  cCpuResumeIntr(state);
110  retval <<= 8;
111  return retval;
112 }
113 
114 u32 QueryTotalFreeMemSize()
115 {
116  int retval;
117  const sysmem_alloc_block_t *blklist;
118  int state;
119 
120  if ( !g_sysmem_internals.m_alloclist )
121  return 0;
122  retval = 0;
123  cCpuSuspendIntr(&state);
124  for ( blklist = g_sysmem_internals.m_alloclist->m_blkarray; blklist; blklist = blklist->m_next )
125  retval += !blklist->m_info.m_allocated ? blklist->m_info.m_size : 0;
126  cCpuResumeIntr(state);
127  retval <<= 8;
128  return retval;
129 }
130 
131 void *AllocSysMemory(int mode, int size, void *ptr)
132 {
133  void *retval;
134  int state;
135 
136  if ( !g_sysmem_internals.m_alloclist || (unsigned int)mode >= 3 )
137  return NULL;
138  cCpuSuspendIntr(&state);
139  retval = allocSysMemory_internal(mode, size, ptr);
140  updateSmemCtlBlk();
141  cCpuResumeIntr(state);
142  return retval;
143 }
144 
145 int FreeSysMemory(void *ptr)
146 {
147  const sysmem_alloc_table_t *alloclist;
148  int retval;
149  int state;
150 
151  for ( alloclist = g_sysmem_internals.m_alloclist; alloclist && ptr != alloclist; alloclist = alloclist->m_next )
152  ;
153  if ( alloclist )
154  return -1;
155  cCpuSuspendIntr(&state);
156  retval = freeSysMemory_internal(ptr);
157  if ( !retval )
158  updateSmemCtlBlk();
159  cCpuResumeIntr(state);
160  return retval;
161 }
162 
163 void *QueryBlockTopAddress(void *address)
164 {
165  int retval;
166  const sysmem_alloc_block_t *blk;
167  int state;
168 
169  cCpuSuspendIntr(&state);
170  blk = search_block(address);
171  retval = blk ? ((blk->m_info.m_address << 8) | (int)(!blk->m_info.m_allocated ? FREE : USED)) : -1;
172  cCpuResumeIntr(state);
173  return (void *)retval;
174 }
175 
176 int QueryBlockSize(void *address)
177 {
178  int retval;
179  const sysmem_alloc_block_t *blk;
180  int state;
181 
182  cCpuSuspendIntr(&state);
183  blk = search_block(address);
184  retval = blk ? ((blk->m_info.m_size << 8) | (int)(!blk->m_info.m_allocated ? FREE : USED)) : -1;
185  cCpuResumeIntr(state);
186  return retval;
187 }
188 
189 void GetSysMemoryInfo(int flag, sysmem_info_t *info)
190 {
191  int state;
192 
193  cCpuSuspendIntr(&state);
194  if ( flag )
195  {
196  info->m_meminfo.m_allocation_count = g_sysmem_internals.m_allocation_count;
197  info->m_meminfo.m_memsize = g_sysmem_internals.m_memsize;
198  info->m_meminfo.m_memlist_last = g_sysmem_internals.m_smemupdate_cur;
199  info->m_meminfo.m_memlist_first = (sysmem_alloc_table_t *)g_sysmem_internals.m_alloclist->m_blkarray;
200  cCpuResumeIntr(state);
201  return;
202  }
203  if ( info->m_meminfo.m_memlist_last != g_sysmem_internals.m_smemupdate_cur )
204  {
205  info->m_blockinfo.m_block_address = (void *)-1;
206  info->m_blockinfo.m_flags_memsize = -1;
207  info->m_blockinfo.m_table_info = NULL;
208  cCpuResumeIntr(state);
209  return;
210  }
211  if ( !info->m_blockinfo.m_table_info )
212  {
213  info->m_blockinfo.m_flags_memsize = 1;
214  info->m_blockinfo.m_block_address = (void *)g_sysmem_internals.m_memsize;
215  cCpuResumeIntr(state);
216  return;
217  }
218  info->m_blockinfo.m_block_address =
219  (void *)((((unsigned int)info->m_blockinfo.m_table_info->m_blkarray[0].m_next >> 1) & 0x7FFF) << 8);
220  info->m_blockinfo.m_flags_memsize = (unsigned int)info->m_blockinfo.m_table_info->m_blkarray[0].m_next >> 17 << 8;
221  if ( ((int)info->m_blockinfo.m_table_info->m_blkarray[0].m_next & 1) )
222  {
223  const sysmem_alloc_table_t *alloclist;
224 
225  for ( alloclist = g_sysmem_internals.m_alloclist; alloclist && alloclist != info->m_blockinfo.m_block_address;
226  alloclist = alloclist->m_next )
227  ;
228  info->m_blockinfo.m_flags_memsize |= alloclist ? 2 : 0;
229  }
230  else
231  info->m_blockinfo.m_flags_memsize |= 1;
232  info->m_blockinfo.m_table_info = ((unsigned int)info->m_blockinfo.m_table_info->m_blkarray[0].m_next >> 17) ?
233  info->m_blockinfo.m_table_info->m_next :
234  NULL;
235  cCpuResumeIntr(state);
236 }
237 
238 sysmem_internals_t *GetSysmemInternalData(void)
239 {
240  return &g_sysmem_internals;
241 }
242 
243 static void *allocSysMemory_internal(int flags, int size, const void *mem)
244 {
245  unsigned int size_rounded;
246 
247  size_rounded = (unsigned int)(size + 255) >> 8;
248  if ( !size_rounded )
249  return NULL;
250  switch ( flags )
251  {
252  case ALLOC_FIRST:
253  {
255  sysmem_alloc_block_t *next;
257 
258  // Unofficial: properly check if m_alloclist is not NULL
259  if ( !g_sysmem_internals.m_alloclist )
260  return NULL;
261  for ( i = g_sysmem_internals.m_alloclist->m_blkarray; i; i = i->m_next )
262  if ( !i->m_info.m_allocated && i->m_info.m_size >= size_rounded )
263  break;
264  if ( !i )
265  return NULL;
266  if ( i->m_info.m_size == size_rounded )
267  {
268  i->m_info.m_allocated = 1;
269  return (void *)(uiptr)(i->m_info.m_address << 8);
270  }
271  g_sysmem_internals.m_allocation_count += 1;
272  blkinfo.m_address = i->m_info.m_address + size_rounded;
273  blkinfo.m_size = i->m_info.m_size - size_rounded;
274  blkinfo.m_allocated = i->m_info.m_allocated;
275  blkinfo.m_pad = i->m_info.m_pad;
276  i->m_info.m_allocated = 1;
277  i->m_info.m_size = size_rounded;
278  // Unofficial: check next if not NULL
279  for ( next = i->m_next; next && blkinfo.m_size; next = next->m_next )
280  {
281  sysmem_alloc_block_info_t blkinfo_tmp;
282 
283  blkinfo_tmp = next->m_info;
284  next->m_info = blkinfo;
285  blkinfo = blkinfo_tmp;
286  }
287  return (void *)(uiptr)(i->m_info.m_address << 8);
288  }
289  case ALLOC_LAST:
290  {
292  sysmem_alloc_block_t *list;
293  sysmem_alloc_block_t *next;
294  unsigned int retaddr;
296 
297  // Unofficial: properly check if m_alloclist is not NULL
298  if ( !g_sysmem_internals.m_alloclist )
299  return NULL;
300  i = NULL;
301  for ( list = g_sysmem_internals.m_alloclist->m_blkarray; list; list = list->m_next )
302  if ( !list->m_info.m_allocated && list->m_info.m_size >= size_rounded )
303  i = list;
304  if ( !i )
305  return NULL;
306  if ( i->m_info.m_size == size_rounded )
307  {
308  i->m_info.m_allocated = 1;
309  return (void *)(uiptr)(i->m_info.m_address << 8);
310  }
311  g_sysmem_internals.m_allocation_count += 1;
312  i->m_info.m_size -= size_rounded;
313  retaddr = i->m_info.m_address + i->m_info.m_size;
314  blkinfo.m_address = retaddr;
315  blkinfo.m_size = size_rounded;
316  blkinfo.m_allocated = 1;
317  blkinfo.m_pad = 0;
318  // Unofficial: check next if not NULL
319  for ( next = i->m_next; next && blkinfo.m_size; next = next->m_next )
320  {
321  sysmem_alloc_block_info_t blkinfo_tmp;
322 
323  blkinfo_tmp = next->m_info;
324  next->m_info = blkinfo;
325  blkinfo = blkinfo_tmp;
326  }
327  return (void *)(uiptr)(retaddr << 8);
328  }
329  case ALLOC_ADDRESS:
330  {
332  sysmem_alloc_block_t *next;
333  unsigned int mem_rounded;
335 
336  if ( (((uiptr)mem) & 0xFF) )
337  return NULL;
338  mem_rounded = (unsigned int)mem >> 8;
339  // Unofficial: properly check if m_alloclist is not NULL
340  if ( !g_sysmem_internals.m_alloclist )
341  return NULL;
342  for ( i = g_sysmem_internals.m_alloclist->m_blkarray; i; i = i->m_next )
343  {
344  if ( mem_rounded < i->m_info.m_address )
345  return NULL;
346  if ( !i->m_info.m_allocated && (u32)(i->m_info.m_address + i->m_info.m_size) >= mem_rounded + size_rounded )
347  break;
348  }
349  if ( !i )
350  return NULL;
351  if ( i->m_info.m_address < mem_rounded )
352  {
353  unsigned int sz_tmp;
354  sysmem_alloc_block_t *blk_tmp;
355  sysmem_alloc_block_info_t blkinfo_nest;
356 
357  g_sysmem_internals.m_allocation_count += 1;
358  sz_tmp = i->m_info.m_address + i->m_info.m_size - mem_rounded;
359  i->m_info.m_size -= sz_tmp;
360  blkinfo_nest.m_address = i->m_info.m_address + i->m_info.m_size;
361  blkinfo_nest.m_size = sz_tmp;
362  blkinfo_nest.m_allocated = 0;
363  blkinfo_nest.m_pad = 0;
364  blk_tmp = i->m_next;
365  i = blk_tmp;
366  while ( blkinfo_nest.m_size )
367  {
368  sysmem_alloc_block_info_t blkinfo_tmp;
369 
370  blkinfo_tmp = blk_tmp->m_info;
371  blk_tmp->m_info = blkinfo_nest;
372  blkinfo_nest = blkinfo_tmp;
373  blk_tmp = blk_tmp->m_next;
374  }
375  }
376  if ( i->m_info.m_size == size_rounded )
377  {
378  i->m_info.m_allocated = 1;
379  return (void *)(uiptr)(i->m_info.m_address << 8);
380  }
381  g_sysmem_internals.m_allocation_count += 1;
382  blkinfo.m_address = i->m_info.m_address + size_rounded;
383  blkinfo.m_size = i->m_info.m_size - size_rounded;
384  blkinfo.m_allocated = i->m_info.m_allocated;
385  blkinfo.m_pad = i->m_info.m_pad;
386  i->m_info.m_allocated = 1;
387  i->m_info.m_size = size_rounded;
388  // Unofficial: check next if not NULL
389  for ( next = i->m_next; next && blkinfo.m_size; next = next->m_next )
390  {
391  sysmem_alloc_block_info_t blkinfo_tmp;
392 
393  blkinfo_tmp = next->m_info;
394  next->m_info = blkinfo;
395  blkinfo = blkinfo_tmp;
396  }
397  return (void *)(uiptr)(i->m_info.m_address << 8);
398  }
399  default:
400  return NULL;
401  }
402 }
403 
404 static int freeSysMemory_internal(const void *ptr)
405 {
406  unsigned int ptr_rounded;
407  sysmem_alloc_block_t *blklist;
408  sysmem_alloc_block_t *prev_blk;
409  int blk_modcnt;
410  sysmem_alloc_block_t *merge_blk;
411  const sysmem_alloc_block_t *next;
412  const sysmem_alloc_block_t *i;
413 
414  ptr_rounded = (unsigned int)ptr >> 8;
415  if ( (((uiptr)ptr) & 0xFF) )
416  return -1;
417  prev_blk = NULL;
418  // Unofficial: properly check if m_alloclist is not NULL
419  if ( !g_sysmem_internals.m_alloclist )
420  return -1;
421  for ( blklist = &g_sysmem_internals.m_alloclist->m_blkarray[2]; blklist; blklist = blklist->m_next )
422  {
423  if ( blklist->m_info.m_size && blklist->m_info.m_address == ptr_rounded )
424  break;
425  prev_blk = blklist;
426  }
427  if ( !blklist || !blklist->m_info.m_allocated )
428  return -1;
429  blk_modcnt = 0;
430  merge_blk = NULL;
431  next = blklist->m_next;
432  blklist->m_info.m_allocated = 0;
433  if ( next && next->m_info.m_size && !next->m_info.m_allocated )
434  {
435  blk_modcnt += 1;
436  g_sysmem_internals.m_allocation_count -= 1;
437  merge_blk = blklist->m_next;
438  blklist->m_info.m_size += merge_blk->m_info.m_size;
439  }
440  if ( prev_blk && !prev_blk->m_info.m_allocated )
441  {
442  merge_blk = blklist;
443  blk_modcnt += 1;
444  g_sysmem_internals.m_allocation_count -= 1;
445  prev_blk->m_info.m_size += blklist->m_info.m_size;
446  }
447  if ( !blk_modcnt )
448  return 0;
449  blk_modcnt -= 1;
450  for ( i = merge_blk; blk_modcnt != -1; blk_modcnt -= 1 )
451  i = i->m_next;
452  for ( ; i; i = i->m_next )
453  {
454  merge_blk->m_info = i->m_info;
455  merge_blk = merge_blk->m_next;
456  }
457  return 0;
458 }
459 
460 static void updateSmemCtlBlk(void)
461 {
462  sysmem_alloc_table_t *alloclist;
463 
464  g_sysmem_internals.m_smemupdate_cur += 1;
465  for ( alloclist = g_sysmem_internals.m_alloclist; alloclist->m_next; alloclist = alloclist->m_next )
466  if ( alloclist->m_blkarray[(sizeof(alloclist->m_blkarray) / sizeof(alloclist->m_blkarray[0])) - 4].m_info.m_size )
467  {
468  alloclist->m_next =
469  (sysmem_alloc_table_t *)allocSysMemory_internal(ALLOC_FIRST, sizeof(sysmem_alloc_table_t), NULL);
470  if ( alloclist->m_next )
471  {
472  sysmem_alloc_table_t *next;
473  unsigned int i;
474 
475  next = alloclist->m_next;
476  alloclist->m_blkarray[(sizeof(alloclist->m_blkarray) / sizeof(alloclist->m_blkarray[0])) - 1].m_next =
477  &(next->m_blkarray[0]);
478  next->m_next = NULL;
479  for ( i = 0; i < (sizeof(next->m_blkarray) / sizeof(next->m_blkarray[0])); i += 1 )
480  {
481  next->m_blkarray[i].m_next = &(next->m_blkarray[i + 1]);
482  next->m_blkarray[i].m_info.m_allocated = 0;
483  next->m_blkarray[i].m_info.m_address = 0;
484  next->m_blkarray[i].m_info.m_pad = 0;
485  next->m_blkarray[i].m_info.m_size = 0;
486  }
487  next->m_blkarray[(sizeof(next->m_blkarray) / sizeof(next->m_blkarray[0])) - 1].m_next = NULL;
488  }
489  }
490  alloclist = g_sysmem_internals.m_alloclist;
491  // Unofficial: properly check if m_alloclist is not NULL
492  if ( alloclist && alloclist->m_next )
493  {
494  sysmem_alloc_table_t *next;
495 
496  for ( ; alloclist->m_next->m_next; alloclist = alloclist->m_next )
497  ;
498  next = alloclist->m_next;
499  if (
500  next
501  && !alloclist->m_blkarray[(sizeof(alloclist->m_blkarray) / sizeof(alloclist->m_blkarray[0])) - 4].m_info.m_size )
502  {
503  alloclist->m_blkarray[(sizeof(alloclist->m_blkarray) / sizeof(alloclist->m_blkarray[0])) - 1].m_next = NULL;
504  alloclist->m_next = NULL;
505  freeSysMemory_internal(next);
506  }
507  }
508 }
509 
510 static sysmem_alloc_block_t *search_block(const void *address)
511 {
512  sysmem_alloc_block_t *blklist;
513 
514  // Unofficial: properly check if m_alloclist is not NULL
515  if ( !g_sysmem_internals.m_alloclist )
516  return NULL;
517  for ( blklist = g_sysmem_internals.m_alloclist->m_blkarray; blklist; blklist = blklist->m_next )
518  if (
519  (uiptr)address >= (uiptr)(blklist->m_info.m_address << 8)
520  && (uiptr)address < (uiptr)((blklist->m_info.m_address + blklist->m_info.m_size) << 8) )
521  break;
522  return blklist;
523 }
524 
525 static int cCpuSuspendIntr(int *state)
526 {
527  intrman_callbacks_t *intrman_callbacks = (intrman_callbacks_t *)(g_sysmem_internals.m_intr_suspend_tbl);
528  return (intrman_callbacks && intrman_callbacks->cbCpuSuspendIntr) ? intrman_callbacks->cbCpuSuspendIntr(state) : 0;
529 }
530 
531 static int cCpuResumeIntr(int state)
532 {
533  intrman_callbacks_t *intrman_callbacks = (intrman_callbacks_t *)(g_sysmem_internals.m_intr_suspend_tbl);
534  return (intrman_callbacks && intrman_callbacks->cbCpuResumeIntr) ? intrman_callbacks->cbCpuResumeIntr(state) : 0;
535 }
536 
537 #if 0
538 static int cQueryIntrContext(void)
539 {
540  intrman_callbacks_t *intrman_callbacks = (intrman_callbacks_t *)(g_sysmem_internals.m_intr_suspend_tbl);
541  return ( intrman_callbacks && intrman_callbacks->cbQueryIntrContext ) ? intrman_callbacks->cbQueryIntrContext() : 0;
542 }
543 #endif
544 
545 int Kprintf(const char *format, ...)
546 {
547  int ret;
548  va_list va;
549 
550  if ( !g_kprintf_cb )
551  return 0;
552  va_start(va, format);
553  ret = g_kprintf_cb(g_kprintf_cb_userdata, format, va);
554  va_end(va);
555  return ret;
556 }
557 
558 void KprintfSet(KprintfHandler_t *new_cb, void *context)
559 {
560  if ( g_kprintf_cb && new_cb )
561  new_cb(context, (const char *)(uiptr)Kprintf(NULL), NULL);
562  g_kprintf_cb = new_cb;
563  g_kprintf_cb_userdata = context;
564 }
sysmem_alloc_block_
Definition: sysmem.h:44
sysmem_info_
Definition: xsysmem.h:48
sysmem_alloc_table_
Definition: sysmem.h:50
s_info
Definition: xprintf.c:78
sysmem_alloc_block_info_
Definition: sysmem.h:36
sysmem_internals_
Definition: sysmem.h:58
irx_export_table
Definition: irx.h:90
xsysmem.h
intrman_callbacks_
Definition: loadcore.c:209