PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
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
15extern struct irx_export_table _exp_excepman;
16
17#ifdef _IOP
18IRX_ID("Exception_Manager", 1, 1);
19#endif
20// Based on the module from SCE SDK 1.3.4.
21
22static uiptr *exception_table;
23static exception_handler_t exception_handlers[16];
24static u32 *default_handler_funccode;
25static exception_handler_t exception_list;
26
27extern u32 exception_handler_shellcode_start[];
28extern u32 exception_handler_shellcode_end[];
29extern exception_handler_struct_t default_exception_handler;
30
31static void update_exception_handler_table(void);
32static exception_handler_t unlink_head_of_list(void);
33static void link_to_head_of_list(exception_handler_t handler);
34static void allocate_list(void);
35
36int _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
71{
72 return RegisterPriorityExceptionHandler(exception, 2, handler);
73}
74
75int 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
109int 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
119int ReleaseExceptionHandler(int exception, exception_handler_t handler)
120{
121 exception_handler_t exception_handler;
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
145int 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
167void *GetExHandlersTable(void)
168{
169 return &exception_table;
170}
171
172static 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
200static 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
212static void link_to_head_of_list(exception_handler_t handler)
213{
214 handler->next = exception_list;
215 exception_list = handler;
216}
217
218static 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
int RegisterExceptionHandler(int exception, exception_handler_t handler)
Definition excepman.c:70