PS2SDK
PS2 Homebrew Libraries
excepman.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 "excepman.h"
12 #include "irx_imports.h"
13 #include "kerr.h"
14 
15 extern struct irx_export_table _exp_excepman;
16 
17 #ifdef _IOP
18 IRX_ID("Exception_Manager", 1, 1);
19 #endif
20 // Based on the module from SCE SDK 1.3.4.
21 
22 static uiptr *exception_table;
23 static exception_handler_t exception_handlers[16];
24 static u32 *default_handler_funccode;
25 static exception_handler_t exception_list;
26 
27 extern u32 exception_handler_shellcode_start[];
28 extern u32 exception_handler_shellcode_end[];
29 extern exception_handler_struct_t default_exception_handler;
30 
31 static void update_exception_handler_table(void);
32 static exception_handler_t unlink_head_of_list(void);
33 static void link_to_head_of_list(exception_handler_t handler);
34 static void allocate_list(void);
35 
36 int _start(int ac, char **av)
37 {
38  unsigned int i;
39  u32 *dst_ptr;
40 
41  (void)ac;
42  (void)av;
43 
44  for ( i = 0; i < (sizeof(exception_handlers) / sizeof(exception_handlers[0])); i += 1 )
45  {
46  exception_handlers[i] = NULL;
47  }
48  default_handler_funccode = NULL;
49  allocate_list();
50  dst_ptr = 0;
51  exception_table = (void *)0x440;
52  // cppcheck-suppress comparePointers
53  for ( i = 0; i < (unsigned int)(exception_handler_shellcode_end - exception_handler_shellcode_start); i += 1 )
54  {
55  u32 cur_instruction;
56 
57  cur_instruction = exception_handler_shellcode_start[i];
58  if ( cur_instruction == 0x8F5A0000 || cur_instruction == 0x8F7B0000 )
59  {
60  cur_instruction |= (u16)(uiptr)exception_table;
61  }
62  // cppcheck-suppress nullPointer
63  dst_ptr[i] = cur_instruction;
64  }
65  RegisterDefaultExceptionHandler(&default_exception_handler);
66  RegisterLibraryEntries(&_exp_excepman);
67  return 0;
68 }
69 
70 int RegisterExceptionHandler(int exception, exception_handler_t handler)
71 {
72  return RegisterPriorityExceptionHandler(exception, 2, handler);
73 }
74 
75 int RegisterPriorityExceptionHandler(int exception, int priority, exception_handler_t handler)
76 {
77  exception_handler_t exception_handler_new;
78  int priority_masked;
79  exception_handler_t *eh_ptr;
80  exception_handler_t eh_cur1;
81  exception_handler_t eh_cur2;
82 
83  if ( handler->next )
84  return KE_EXPHANDLER_USED;
85  if ( (unsigned int)exception >= (sizeof(exception_handlers) / sizeof(exception_handlers[0])) )
86  return KE_ILLEGAL_EXPCODE;
87  priority_masked = priority & 3;
88  exception_handler_new = unlink_head_of_list();
89  eh_ptr = &exception_handlers[exception];
90  exception_handler_new->info = ((uiptr)handler & 0xFFFFFFFC) | priority_masked;
91  eh_cur1 = *eh_ptr;
92  if ( *eh_ptr )
93  {
94  do
95  {
96  eh_cur2 = *eh_ptr;
97  if ( ((*eh_ptr)->info & 3) >= priority_masked )
98  break;
99  eh_ptr = (exception_handler_t *)*eh_ptr;
100  } while ( eh_cur2->next );
101  eh_cur1 = *eh_ptr;
102  }
103  exception_handler_new->next = eh_cur1;
104  *eh_ptr = exception_handler_new;
105  update_exception_handler_table();
106  return 0;
107 }
108 
109 int RegisterDefaultExceptionHandler(exception_handler_t handler)
110 {
111  if ( handler->next )
112  return KE_EXPHANDLER_USED;
113  handler->next = (exception_handler_t)default_handler_funccode;
114  default_handler_funccode = handler->funccode;
115  update_exception_handler_table();
116  return 0;
117 }
118 
119 int ReleaseExceptionHandler(int exception, exception_handler_t handler)
120 {
121  exception_handler_t exception_handler;
122  exception_handler_t next;
123 
124  if ( (unsigned int)exception >= (sizeof(exception_handlers) / sizeof(exception_handlers[0])) )
125  return KE_ILLEGAL_EXPCODE;
126  exception_handler = (exception_handler_t)&exception_handlers[exception];
127  if ( !exception_handler->next )
128  return KE_EXPHANDLER_NOUSE;
129  while ( 1 )
130  {
131  next = exception_handler->next;
132  if ( (exception_handler_t)(exception_handler->next->info & 0xFFFFFFFC) == handler )
133  break;
134  exception_handler = exception_handler->next;
135  if ( !next->next )
136  return KE_EXPHANDLER_NOUSE;
137  }
138  exception_handler->next = next->next;
139  *(u32 *)(next->info & 0xFFFFFFFC) = 0;
140  link_to_head_of_list(next);
141  update_exception_handler_table();
142  return 0;
143 }
144 
145 int ReleaseDefaultExceptionHandler(exception_handler_t handler)
146 {
147  exception_handler_t cur_handler;
148 
149  if ( !default_handler_funccode )
150  return KE_EXPHANDLER_NOUSE;
151  // Unofficial: The original was referencing the funccode member, but we need the beginning of the struct
152  cur_handler = (exception_handler_t)(((char *)default_handler_funccode) - 8);
153  while ( 1 )
154  {
155  if ( cur_handler->funccode == handler->funccode )
156  break;
157  cur_handler = cur_handler->next;
158  if ( !cur_handler )
159  return KE_EXPHANDLER_NOUSE;
160  }
161  default_handler_funccode = cur_handler->next->funccode;
162  cur_handler->next = 0;
163  update_exception_handler_table();
164  return 0;
165 }
166 
167 void *GetExHandlersTable(void)
168 {
169  return &exception_table;
170 }
171 
172 static void update_exception_handler_table(void)
173 {
174  exception_handler_t exception_handler;
175  unsigned int i;
176 
177  for ( i = 0; i < (sizeof(exception_handlers) / sizeof(exception_handlers[0])); i += 1 )
178  {
179  exception_handler = exception_handlers[i];
180  if ( exception_handler )
181  {
182  while ( exception_handler->next )
183  {
184  *(u32 *)(exception_handler->info & 0xFFFFFFFC) = (exception_handler->next->info & 0xFFFFFFFC) + 8;
185  exception_handler = exception_handler->next;
186  }
187  *(u32 *)(exception_handler->info & 0xFFFFFFFC) = (uiptr)default_handler_funccode;
188  }
189  }
190  for ( i = 0; i < (sizeof(exception_handlers) / sizeof(exception_handlers[0])); i += 1 )
191  {
192  exception_handler = exception_handlers[i];
193  if ( exception_handler )
194  exception_table[i] = (exception_handler->info & 0xFFFFFFFC) + 8;
195  else
196  exception_table[i] = (uiptr)default_handler_funccode;
197  }
198 }
199 
200 static exception_handler_t unlink_head_of_list(void)
201 {
202  exception_handler_struct_t *exception_list_save;
203 
204  if ( !exception_list )
205  allocate_list();
206  exception_list_save = exception_list;
207  if ( exception_list )
208  exception_list = exception_list->next;
209  return exception_list_save;
210 }
211 
212 static void link_to_head_of_list(exception_handler_t handler)
213 {
214  handler->next = exception_list;
215  exception_list = handler;
216 }
217 
218 static void allocate_list(void)
219 {
220  unsigned int i;
221 
222  exception_list = (exception_handler_struct_t *)AllocSysMemory(0, 256, 0);
223  for ( i = 0; i < 0x1F; i += 1 )
224  {
225  exception_list[i].next = &exception_list[i + 1];
226  }
227  exception_list[i].next = NULL;
228 }
229 
230 // clang-format off
231 __asm__ (
232  "\t" ".set push" "\n"
233  "\t" ".set noat" "\n"
234  "\t" ".set noreorder" "\n"
235  "\t" "exception_handler_shellcode_start:" "\n"
236  "\t" "nop" "\n"
237  "\t" "nop" "\n"
238  "\t" "nop" "\n"
239  "\t" "nop" "\n"
240  "\t" "break 1" "\n"
241  "\t" "break 1" "\n"
242  "\t" "break 1" "\n"
243  "\t" "break 1" "\n"
244  "\t" "break 1" "\n"
245  "\t" "break 1" "\n"
246  "\t" "break 1" "\n"
247  "\t" "break 1" "\n"
248  "\t" "break 1" "\n"
249  "\t" "break 1" "\n"
250  "\t" "break 1" "\n"
251  "\t" "break 1" "\n"
252  "\t" "sw $k0, 0x420($zero)" "\n" // memory[0x420] = k0
253  "\t" "mfc0 $k1, $14" "\n" // k1 = EPC (k1 never saved!)
254  "\t" "mfc0 $k0, $13" "\n" // k0 = Cause
255  "\t" "sw $k1, 0x424($zero)" "\n" // memory[0x424] = k1 = EPC
256  "\t" "sw $k0, 0x428($zero)" "\n" // memory[0x428] = k0 = Cause
257  "\t" "mfc0 $k1, $12" "\n" // k1 = Status
258  "\t" "mfc0 $k0, $7" "\n" // k0 = Breakpoint Control
259  "\t" "sw $k1, 0x42C($zero)" "\n" // memory[0x42C] = k1 = Status
260  "\t" "sw $k0, 0x430($zero)" "\n" // memory[0x430] = k0 = Breakpoint Control
261  "\t" "addiu $k1, $zero, 0x3C" "\n" // k1 = 0x3C
262  "\t" "lw $k1, 0x0($k1)" "\n" // k1 = exception_table[15] (this instruction gets modified to have exception_table address as immediate)
263  "\t" "mtc0 $zero, $7" "\n" // Breakpoint Control = 0
264  "\t" "jr $k1" "\n" // (exception_table[15])()
265  "\t" " nop" "\n"
266  "\t" "nop" "\n"
267  "\t" "nop" "\n"
268  "\t" "sw $at, 0x400($zero)" "\n" // memory[0x400] = at
269  "\t" "sw $k0, 0x410($zero)" "\n" // memory[0x410] = k0
270  "\t" "mfc0 $k0, $14" "\n" // k0 = EPC
271  "\t" "mfc0 $at, $12" "\n" // at = Status
272  "\t" "sw $k0, 0x404($zero)" "\n" // memory[0x404] = k0 = EPC
273  "\t" "sw $at, 0x408($zero)" "\n" // memory[0x408] = at = Status
274  "\t" "mfc0 $k0, $13" "\n" // k0 = Cause
275  "\t" "nop" "\n"
276  "\t" "sw $k0, 0x40C($zero)" "\n" // memory[0x40C] = k0 = Cause
277  "\t" "andi $k0, $k0, 0x3C" "\n" // k0 &= 0x3C
278  "\t" "lw $k0, 0x0($k0)" "\n" // k0 = exception_table[k0 / sizeof(exception_table[0])] (this instruction gets modified to have exception_table address as immediate)
279  "\t" "nop" "\n"
280  "\t" "jr $k0" "\n" // (exception_table[(Cause & 0x3C) / sizeof(exception_table[0])])()
281  "\t" " nop" "\n"
282  "\t" "nop" "\n"
283  "\t" "nop" "\n"
284  "\t" "nop" "\n"
285  "\t" "nop" "\n"
286  "\t" "nop" "\n"
287  "\t" "nop" "\n"
288  "\t" "exception_handler_shellcode_end:" "\n"
289  "\t" ".set pop" "\n"
290 );
291 
292 __asm__ (
293  "\t" ".set push" "\n"
294  "\t" ".set noat" "\n"
295  "\t" ".set noreorder" "\n"
296  "\t" "default_exception_handler:" "\n"
297  "\t" ".word 0" "\n"
298  "\t" ".word 0" "\n"
299  "\t" "exception_handler_infloop:" "\n"
300  "\t" "b exception_handler_infloop" "\n"
301  "\t" " nop" "\n"
302  "\t" ".set pop" "\n"
303 );
304 // clang-format on
excepman.h
RegisterExceptionHandler
int RegisterExceptionHandler(int exception, exception_handler_t handler)
Definition: excepman.c:70
irx_export_table
Definition: irx.h:90
_exception_handler_struct_t
Definition: excepman.h:60
kerr.h