pcsx2/fps2bios/kernel/iopload/excepman/excepman.c

340 lines
7.9 KiB
C

/*
* The IOP exception manager module.
*/
#include <tamtypes.h>
#include "err.h"
#include "kexcepman.h"
#include "kloadcore.h"
#include "iopdebug.h"
#define _dprintf(fmt, args...) \
__printf("excepman: " fmt, ## args)
int _start();
int excepman_reinit();
int excepman_deinit();
void *GetExHandlersTable();
int RegisterExceptionHandler(int code, struct exHandler *handler);
int RegisterPriorityExceptionHandler(int code, int priority, struct exHandler *handler);
int RegisterDefaultExceptionHandler(struct exHandler *handler);
int ReleaseExceptionHandler(int code, struct exHandler *handler);
int ReleaseDefaultExceptionHandler(struct exHandler *handler);
struct export excepman_stub __attribute__((section(".text"))) ={
0x41C00000,
0,
VER(1, 1), // 1.1 => 0x101
0,
"excepman",
(func)_start, // entrypoint
(func)excepman_reinit,
(func)excepman_deinit,
(func)GetExHandlersTable,
(func)RegisterExceptionHandler,
(func)RegisterPriorityExceptionHandler,
(func)RegisterDefaultExceptionHandler,
(func)ReleaseExceptionHandler,
(func)ReleaseDefaultExceptionHandler,
0
};
void* *extable;
struct exHandler *handlers[16];
void *defhandler;
void iopException();
extern void defaultEH();
void defaultEHfunc()
{
__printf("panic: excepman: %s\n", __FUNCTION__);
__printf("EPC=0x%x, cause: %x\n", *(u32*)0x404, *(u32*)0x40C);
__printf("EXECUTION HALTED\n");
for (;;);
}
///////////////////////////////////////////////////////////////////////
void registerEH() {
int i;
_dprintf("%s\n", __FUNCTION__);
// Set up the chain of exception handlers, making sure that each used one is terminated by the
// default exception handler.
for (i=0; i<16; i++) {
if (handlers[i]) {
struct exHandler *eh = handlers[i];
while(eh->next){
struct exHandler *p_handler = (struct exHandler *)(eh->info & ~3);
struct exHandler *p_next_handler = (struct exHandler *)(((struct exHandler *)(eh->next))->info & ~3);
p_handler->next = (void*)p_next_handler + 8;
eh = eh->next;
}
{
struct exHandler *p_handler = (struct exHandler *)(eh->info & ~3);
p_handler->next = defhandler;
}
}
}
for (i=0; i<16; i++) {
if (handlers[i]){
extable[i]=(void*)((handlers[i]->info & ~3) + 8);
} else {
extable[i]=defhandler;
}
}
}
//////////////////////////////entrypoint///////////////////////////////[00]
void Kputc(u8 c) {
*((u8*)0x1f80380c) = c;
}
void Kprintnum(unsigned int n)
{
int i = 0;
while(i < 8) {
u32 a = n>>28;
if( a < 10 ) Kputc('0'+a);
else Kputc('a'+(a-10));
n <<= 4;
++i;
}
}
int _start() {
int *src, *dst;
int i;
_dprintf("%s\n", __FUNCTION__);
for (i=0; i<16; i++){
handlers[i] = NULL;
}
defhandler=NULL;
extable = (void*)0x440;
// Install the exception handler to address 0
for (src=(int*)iopException, dst=0; (u32)dst<0x100; src++, dst++){
*dst = *src;
}
RegisterDefaultExceptionHandler((struct exHandler *)&defaultEH);
RegisterLibraryEntries(&excepman_stub);
return 0;
}
///////////////////////////////////////////////////////////////////////[02]
int excepman_deinit(){
return 0;
}
///////////////////////////////////////////////////////////////////////[01]
int excepman_reinit() {
excepman_deinit();
return _start();
}
///////////////////////////////////////////////////////////////////////[04]
int RegisterExceptionHandler(int code, struct exHandler *handler)
{
return RegisterPriorityExceptionHandler(code, 2, handler);
}
// This is a pool of containers. They form a linked list. The info member of each points
// to a registered handler.
struct exHandler _list[32];
struct exHandler *list = NULL;
void link(struct exHandler *e) {
e->next = list;
list = e;
}
struct exHandler *unlink() {
struct exHandler *e;
if (list == NULL) {
int i;
list = _list;
for (i=0; i<31; i++) {
list[i].next = &list[i+1];
}
list[i].next = 0;
}
e = list;
list = e->next;
return e;
}
///////////////////////////////////////////////////////////////////////[05]
int RegisterPriorityExceptionHandler(int code, int priority, struct exHandler *handler)
{
struct exHandler *n, *p, *p_prev;
_dprintf("%s: code = %d, pri = %d, (handler=%x)\n", __FUNCTION__, code, priority, handler);
if (code >= 16){
_dprintf("%s ERROR_BAD_EXCODE\n", __FUNCTION__);
return ERROR_BAD_EXCODE;
}
if (handler->next){
_dprintf("%s ERROR_USED_EXCODE\n", __FUNCTION__);
return ERROR_USED_EXCODE;
}
n = unlink();
priority &= 3;
n->info = ((u32)handler & ~3) | priority;
n->next = NULL;
p = handlers[code]; p_prev = NULL;
// walk along the chain starting at the handlers[code] root to find our place in the queue
while(p && ((p->info & 3) < priority)){
p_prev = p; p = p->next;
}
n->next = p;
if (p_prev == NULL){
handlers[code] = n;
} else {
p_prev->next = n;
}
registerEH();
return 0;
}
///////////////////////////////////////////////////////////////////////[06]
int RegisterDefaultExceptionHandler(struct exHandler *handler)
{
_dprintf("%s\n", __FUNCTION__);
if (handler->next){
_dprintf("%s ERROR_USED_EXCODE\n", __FUNCTION__);
return ERROR_USED_EXCODE;
}
handler->next = defhandler;
defhandler = &handler->funccode;
registerEH();
return 0;
}
///////////////////////////////////////////////////////////////////////[07]
int ReleaseExceptionHandler(int code, struct exHandler *handler)
{
struct exHandler *p, *p_prev;
_dprintf("%s: %d\n", __FUNCTION__, code);
if (code>=16) return ERROR_BAD_EXCODE;
p_prev = NULL;
for (p=handlers[code]; p != NULL; p_prev = p, p=p->next) {
if ((struct exHandler *)(p->info & ~3) == handler) {
// found it
// Mark the handler as no longer used
((struct exHandler *)(p->info & ~3))->next = NULL;
if (p == handlers[code]){
// special case, no more list
handlers[code] = NULL;
} else {
// Remove container p from the list
p_prev->next = p->next;
}
link(p); // Add the container back to the pool
registerEH();
return 0;
}
}
return ERROR_EXCODE_NOTFOUND;
}
///////////////////////////////////////////////////////////////////////[08]
int ReleaseDefaultExceptionHandler(struct exHandler *handler)
{
struct exHandler *p;
_dprintf("%s\n", __FUNCTION__);
for (p=defhandler; p->next; p=p->next-8) {
if (p->next == handler->funccode) {
p->next = handler->next;
handler->next = 0;
registerEH();
return 0;
}
}
return ERROR_EXCODE_NOTFOUND;
}
///////////////////////////////////////////////////////////////////////[03]
void *GetExHandlersTable()
{
return extable;
}
// 256 bytes of this code are copied to memory address 0 in order to install the exception handling code.
// Take careful note of the alignment of the code at 0x40 and 0x80 if you change it at all.
void iopException() {
__asm__ (
".set noat\n"
"nop\nnop\nnop\nnop\n"
"nop\nnop\nnop\nnop\n"
"nop\nnop\nnop\nnop\n"
"nop\nnop\nnop\nnop\n"
/* 0x0040 */
/* This the breakpoint exception vector location. */
"sw $26, 0x0420($0)\n"
"mfc0 $27, $14\n"
"mfc0 $26, $13\n"
"sw $27, 0x0424($0)\n"
"sw $26, 0x0428($0)\n"
"mfc0 $27, $12\n"
"mfc0 $26, $7\n"
"sw $27, 0x042C($0)\n"
"sw $26, 0x0430($0)\n"
"lw $27, 0x047C($0)\n"
"mtc0 $0, $7\n"
"jr $27\n"
"nop\n"
"nop\n"
"nop\n"
"nop\n"
/* 0x0080 */
/* This is the general exception vector location. */
"sw $1, 0x0400($0)\n" /* $1 saved at 0x400 */
"sw $26, 0x0410($0)\n" /* $26 saved at 0x410 */
"mfc0 $1, $14\n"
"mfc0 $26, $12\n"
"sw $1 , 0x0404($0)\n" /* EPC -> 0x404 */
"sw $26, 0x0408($0)\n" /* STATUS -> 0x408 */
"mfc0 $1, $13\n"
"sw $1, 0x040C($0)\n" /* CAUSE -> 0x40C */
"andi $1, 0x3C\n" /* Isolate EXECODE */
"lw $1, 0x0440($1)\n"
"jr $1\n" /* jump via EXECODE table at 0x440 */
"nop\n"
"nop\n"
"nop\n"
"nop\n"
"nop\n"
"nop\nnop\nnop\nnop\n"
"nop\nnop\nnop\nnop\n"
"nop\nnop\nnop\nnop\n"
"nop\nnop\nnop\nnop\n"
".set at\n"
);
}