← index
PSP.Homebrew/apps/crossgta/Examples/KnightsTour/utils.c
Source: PSP.Homebrew/apps/crossgta/Examples/KnightsTour/utils.c
/*
Utils for PSP v2.0 exploit
(w) 24/09/2005 by Groepaz/Hitmen
additions 28/9/05 by Fanjita
http://www.fanjita.org
*/

#include <pspctrl.h>

#include <pspdisplay.h>

#include <pspsysmem.h>

#include <pspthreadman.h>

#include <pspmodulemgr.h>


#define USE_MISSING_NIDS   0


#define SCREEN_HEIGHT 272

#define SCREEN_WIDTH  512


typedef unsigned char BOOL;
#define TRUE  1

#define FALSE 0

#define NULL  0


typedef unsigned int UINT;
typedef void VOID;

typedef struct {
  UINT left;
  UINT right;
  UINT top;
  UINT bottom;
} RECT;

typedef struct {
  UINT cx;
  UINT cy;
} SIZE;

typedef struct {
  UINT x;
  UINT y;
} POINT;


void Main(void);

void _start(void) __attribute__ ((section (".text.start")));
// this is our "crt0". not real, very fake. but enough for now :=P


void _start(void)
{
  initial_setup(0x08800000L, 0x01800000L);
	Main();
	while(1){}; // wait forever

} 

void flashscreen(int cola, int colb)
{
  /***************************************************************************/
  /* Flash screen 10 times                                                   */
  /***************************************************************************/
  {
    int i;

    for (i=0; i<10; i++)
    {
      {
        long *lptr = 0x44000000;
        
        while (lptr < 0x44200000)
        {
          *lptr++ = cola;
        }
    
        lptr = 0x44000000;
        
        while (lptr < 0x44200000)
        {
          *lptr++ = colb;
        }
      }
    }
  }
}

void memcpy(char *dest, char *src, int size)
{
  while (size--)
  {
    *dest++ = *src++;
  }
}

// font data

const unsigned char font[]={

    // much better charset, by eddie!

    // this is actually the 8x8 neuromancer

    // vga/ega mode font :)

    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,   // 0x20 

    0x30,0x78,0x78,0x30,0x30,0x00,0x30,0x00,   // 0x21 

    0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00,   // 0x22 

    0x6C,0x6C,0xFE,0x6C,0xFE,0x6C,0x6C,0x00,   // 0x23 

    0x30,0x7C,0xC0,0x78,0x0C,0xF8,0x30,0x00,   // 0x24 

    0x00,0xC6,0xCC,0x18,0x30,0x66,0xC6,0x00,   // 0x25 

    0x38,0x6C,0x38,0x76,0xDC,0xCC,0x76,0x00,   // 0x26 

    0x60,0x60,0xC0,0x00,0x00,0x00,0x00,0x00,   // 0x27 

    0x18,0x30,0x60,0x60,0x60,0x30,0x18,0x00,   // 0x28 

    0x60,0x30,0x18,0x18,0x18,0x30,0x60,0x00,   // 0x29 

    0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00,   // 0x2A 

    0x00,0x30,0x30,0xFC,0x30,0x30,0x00,0x00,   // 0x2B 

    0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x60,   // 0x2C 

    0x00,0x00,0x00,0xFC,0x00,0x00,0x00,0x00,   // 0x2D 

    0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,   // 0x2E 

    0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x00,   // 0x2F 

    0x7C,0xC6,0xCE,0xDE,0xF6,0xE6,0x7C,0x00,   // 0x30 

    0x30,0x70,0x30,0x30,0x30,0x30,0xFC,0x00,   // 0x31 

    0x78,0xCC,0x0C,0x38,0x60,0xCC,0xFC,0x00,   // 0x32 

    0x78,0xCC,0x0C,0x38,0x0C,0xCC,0x78,0x00,   // 0x33 

    0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x1E,0x00,   // 0x34 

    0xFC,0xC0,0xF8,0x0C,0x0C,0xCC,0x78,0x00,   // 0x35 

    0x38,0x60,0xC0,0xF8,0xCC,0xCC,0x78,0x00,   // 0x36 

    0xFC,0xCC,0x0C,0x18,0x30,0x30,0x30,0x00,   // 0x37 

    0x78,0xCC,0xCC,0x78,0xCC,0xCC,0x78,0x00,   // 0x38 

    0x78,0xCC,0xCC,0x7C,0x0C,0x18,0x70,0x00,   // 0x39 

    0x00,0x30,0x30,0x00,0x00,0x30,0x30,0x00,   // 0x3A 

    0x00,0x30,0x30,0x00,0x00,0x30,0x30,0x60,   // 0x3B 

    0x18,0x30,0x60,0xC0,0x60,0x30,0x18,0x00,   // 0x3C 

    0x00,0x00,0xFC,0x00,0x00,0xFC,0x00,0x00,   // 0x3D 

    0x60,0x30,0x18,0x0C,0x18,0x30,0x60,0x00,   // 0x3E 

    0x78,0xCC,0x0C,0x18,0x30,0x00,0x30,0x00,   // 0x3F 

    0x7C,0xC6,0xDE,0xDE,0xDE,0xC0,0x78,0x00,   // 0x40 

    0x30,0x78,0xCC,0xCC,0xFC,0xCC,0xCC,0x00,   // 0x41 

    0xFC,0x66,0x66,0x7C,0x66,0x66,0xFC,0x00,   // 0x42 

    0x3C,0x66,0xC0,0xC0,0xC0,0x66,0x3C,0x00,   // 0x43 

    0xF8,0x6C,0x66,0x66,0x66,0x6C,0xF8,0x00,   // 0x44 

    0xFE,0x62,0x68,0x78,0x68,0x62,0xFE,0x00,   // 0x45 

    0xFE,0x62,0x68,0x78,0x68,0x60,0xF0,0x00,   // 0x46 

    0x3C,0x66,0xC0,0xC0,0xCE,0x66,0x3E,0x00,   // 0x47 

    0xCC,0xCC,0xCC,0xFC,0xCC,0xCC,0xCC,0x00,   // 0x48 

    0x78,0x30,0x30,0x30,0x30,0x30,0x78,0x00,   // 0x49 

    0x1E,0x0C,0x0C,0x0C,0xCC,0xCC,0x78,0x00,   // 0x4A 

    0xE6,0x66,0x6C,0x78,0x6C,0x66,0xE6,0x00,   // 0x4B 

    0xF0,0x60,0x60,0x60,0x62,0x66,0xFE,0x00,   // 0x4C 

    0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0x00,   // 0x4D 

    0xC6,0xE6,0xF6,0xDE,0xCE,0xC6,0xC6,0x00,   // 0x4E 

    0x38,0x6C,0xC6,0xC6,0xC6,0x6C,0x38,0x00,   // 0x4F 

    0xFC,0x66,0x66,0x7C,0x60,0x60,0xF0,0x00,   // 0x50 

    0x78,0xCC,0xCC,0xCC,0xDC,0x78,0x1C,0x00,   // 0x51 

    0xFC,0x66,0x66,0x7C,0x6C,0x66,0xE6,0x00,   // 0x52 

    0x78,0xCC,0xE0,0x70,0x1C,0xCC,0x78,0x00,   // 0x53 

    0xFC,0xB4,0x30,0x30,0x30,0x30,0x78,0x00,   // 0x54 

    0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xFC,0x00,   // 0x55 

    0xCC,0xCC,0xCC,0xCC,0xCC,0x78,0x30,0x00,   // 0x56 

    0xC6,0xC6,0xC6,0xD6,0xFE,0xEE,0xC6,0x00,   // 0x57 

    0xC6,0xC6,0x6C,0x38,0x38,0x6C,0xC6,0x00,   // 0x58 

    0xCC,0xCC,0xCC,0x78,0x30,0x30,0x78,0x00,   // 0x59 

    0xFE,0xC6,0x8C,0x18,0x32,0x66,0xFE,0x00,   // 0x5A 

    0x78,0x60,0x60,0x60,0x60,0x60,0x78,0x00,   // 0x5B 

    0xC0,0x60,0x30,0x18,0x0C,0x06,0x02,0x00,   // 0x5C 

    0x78,0x18,0x18,0x18,0x18,0x18,0x78,0x00,   // 0x5D 

    0x10,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,   // 0x5E 

    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,   // 0x5F 

    0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,   // 0x60 

    0x00,0x00,0x78,0x0C,0x7C,0xCC,0x76,0x00,   // 0x61 

    0xE0,0x60,0x60,0x7C,0x66,0x66,0xDC,0x00,   // 0x62 

    0x00,0x00,0x78,0xCC,0xC0,0xCC,0x78,0x00,   // 0x63 

    0x1C,0x0C,0x0C,0x7C,0xCC,0xCC,0x76,0x00,   // 0x64 

    0x00,0x00,0x78,0xCC,0xFC,0xC0,0x78,0x00,   // 0x65 

    0x38,0x6C,0x60,0xF0,0x60,0x60,0xF0,0x00,   // 0x66 

    0x00,0x00,0x76,0xCC,0xCC,0x7C,0x0C,0xF8,   // 0x67 

    0xE0,0x60,0x6C,0x76,0x66,0x66,0xE6,0x00,   // 0x68 

    0x30,0x00,0x70,0x30,0x30,0x30,0x78,0x00,   // 0x69 

    0x0C,0x00,0x0C,0x0C,0x0C,0xCC,0xCC,0x78,   // 0x6A 

    0xE0,0x60,0x66,0x6C,0x78,0x6C,0xE6,0x00,   // 0x6B 

    0x70,0x30,0x30,0x30,0x30,0x30,0x78,0x00,   // 0x6C 

    0x00,0x00,0xCC,0xFE,0xFE,0xD6,0xC6,0x00,   // 0x6D 

    0x00,0x00,0xF8,0xCC,0xCC,0xCC,0xCC,0x00,   // 0x6E 

    0x00,0x00,0x78,0xCC,0xCC,0xCC,0x78,0x00,   // 0x6F 

    0x00,0x00,0xDC,0x66,0x66,0x7C,0x60,0xF0,   // 0x70 

    0x00,0x00,0x76,0xCC,0xCC,0x7C,0x0C,0x1E,   // 0x71 

    0x00,0x00,0xDC,0x76,0x66,0x60,0xF0,0x00,   // 0x72 

    0x00,0x00,0x7C,0xC0,0x78,0x0C,0xF8,0x00,   // 0x73 

    0x10,0x30,0x7C,0x30,0x30,0x34,0x18,0x00,   // 0x74 

    0x00,0x00,0xCC,0xCC,0xCC,0xCC,0x76,0x00,   // 0x75 

    0x00,0x00,0xCC,0xCC,0xCC,0x78,0x30,0x00,   // 0x76 

    0x00,0x00,0xC6,0xD6,0xFE,0xFE,0x6C,0x00,   // 0x77 

    0x00,0x00,0xC6,0x6C,0x38,0x6C,0xC6,0x00,   // 0x78 

    0x00,0x00,0xCC,0xCC,0xCC,0x7C,0x0C,0xF8,   // 0x79 

    0x00,0x00,0xFC,0x98,0x30,0x64,0xFC,0x00,   // 0x7A 

    0x1C,0x30,0x30,0xE0,0x30,0x30,0x1C,0x00,   // 0x7B 

    0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x00,   // 0x7C 

    0xE0,0x30,0x30,0x1C,0x30,0x30,0xE0,0x00,   // 0x7D 

    0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,   // 0x7E    

    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

};

#define CMAX_X 60

#define CMAX_Y 38

#define PIXELSIZE 3				//in short

#define LINESIZE 	512				//in short

#define FRAMESIZE  0xAA000			//in byte


#define TEXTCOLOUR 0x00FFFFFF

#define BLUE       0x00FF0000

#define RED        0x000000FF

#define GREEN      0x0000FF00


unsigned char *vramtop=(unsigned char *)0x04000000;
unsigned long drawframe;

// get vram address for character position

unsigned char *GetVramAddr(unsigned long x,unsigned long y)
{
	return vramtop+(drawframe?FRAMESIZE:0)+x*4+y*LINESIZE*4+0x40000000;
}

struct timeval {
  long tv_sec;
  long tv_usec;
};

struct timezone {
  int tz_minuteswest;
  int tz_dsttime;
};

int sceKernelLibcGettimeofday(struct timeval *tp, struct timezone *tzp)
{
  register int lret asm("$2");
  register struct timeval * ltp asm("$4") = tp;
  register struct timezone * ltzp asm("$5") = tzp;

  // This number is not accurate, but it doesn't matter because it will be fixed up

  asm ("syscall 0x2109" : "=r" (lret) : "r" (ltp), "r" (ltzp) );

  return(lret);
}


/*****************************************************************************/
/* A very basic rand()                                                       */
/*****************************************************************************/
int rand()
{
  struct timeval tp;
  struct timezone tz;
  
  sceKernelLibcGettimeofday(&tp, &tz);

  return tp.tv_usec;
}

// print a single character

void PutChar(unsigned long x,unsigned long y,unsigned long color,unsigned long bgcolor,unsigned char ch,char drawfg,char drawbg,char mag)
{
	unsigned char *vptr0;		//pointer to vram

	unsigned char *vptr;		//pointer to vram

	const unsigned char *cfont;		//pointer to font

	unsigned long cx,cy;
	unsigned long b;
	char mx,my;

	cfont=font+ch*8;

	vptr0=GetVramAddr(x,y);

	for (cy=0; cy<8; cy++)
	{
		for (my=0; my<mag; my++)
		{
			vptr=vptr0;
			b=0x80;
			for (cx=0; cx<8; cx++)
			{
				for (mx=0; mx<mag; mx++)
				{
					if ((*cfont&b)!=0)
					{
						if (drawfg)
            {
              *(unsigned long *)vptr=color;
            }
					}
          else
          {
						if (drawbg)
            {
              *(unsigned long *)vptr=bgcolor;
            }
					}
					vptr+=4; // PIXELSIZE*2;

				}
				b=b>>1;
			}
			vptr0+=LINESIZE*4; // 2

		}
		cfont++;
	}
}

// print a string

void Print(unsigned long x,unsigned long y,unsigned long color,const char *str)
{
	while (*str!=0 && x<CMAX_X && y<CMAX_Y) {
		PutChar(x*8,y*8,color,0,*str,1,1,1);
		str++;
		x++;
		if (x>=CMAX_X) {
			x=0;
			y++;
		}
	}
}
 
// x is in pixels rather than character cells

void PrintFine(unsigned long x,unsigned long y,unsigned long color,const char *str)
{
	while (*str!=0 && x<(CMAX_X*8) && y<CMAX_Y) {
		PutChar(x,y*8,color,0,*str,1,1,1);
		str++;
		x+=8;
		if (x>=(CMAX_X*8)) {
			x=0;
			y++;
		}
	}
}
 
// clear video ram

void Fillvram(unsigned long color)
{
	unsigned char *vptr0;		//pointer to vram

	unsigned long i;

	vptr0=GetVramAddr(0,0);

	for (i=0; i<(FRAMESIZE/4); i++) 
	{
		*(unsigned long *)vptr0=color;
		vptr0+=4;
	}
}

SceCtrlData gpaddata;

int sceCtrlReadBufferPositive(SceCtrlData *pad_data, int count)
{
  register int lret asm("$2");
  register SceCtrlData * lpaddata asm("$4") = pad_data;
  register SceCtrlData * lcount   asm("$5") = count;
  asm __volatile__ ("syscall 0x215F;"
                    : "=r" (lret)
                    : "r" (lpaddata), "r" (lcount)
                   );
  return(lret);
}

int sceCtrlSetSamplingCycle(int cycle)
{
  register int lret asm("$2");
  register int lcycle asm("$4") = cycle;
  asm __volatile__ ("syscall 0x2150;"
                    : // no output regs 

                    : "r" (lcycle)
                   );
  return(lret);
}

int sceCtrlSetSamplingMode(int mode)
{
  register int lret asm("$2");
  register int lmode asm("$4") = mode;
  asm __volatile__ ("syscall 0x215D;"
                    : "=r" (lret)
                    : "r" (lmode)
                   );
  return(lret);
}

int sceDisplayWaitVblank(void)
{
  register int lret asm("$2");
  asm __volatile__ ("syscall 0x2154" : "=r" (lret));
  return(lret);
}

int sceDisplayWaitVblankStart(void)
{
  register int lret asm("$2");
  asm __volatile__ ("syscall 0x2156" : "=r" (lret));
  return(lret);
}

void WriteNibble(int x, int y, unsigned char val)
{
  if (val > 9)
  {
    val = 'A' + val - 10;
  }
  else
  {
    val = '0' + val;
  }
	PutChar(x*8,y*8,TEXTCOLOUR,0,val,1,1,1);
}

void WriteByte(int x, int y, unsigned char val)
{
  char lchr;

  lchr = (val & 0xF0) >> 4;
  WriteNibble(x,y,lchr);
  lchr = (val & 0xF);
  WriteNibble(x+1,y,lchr);
}

void WriteDword(int x, int y, unsigned long val)
{
  WriteByte(x,y,(val & 0xFF000000L) >> 24);
  WriteByte(x+2,y,(val & 0xFF0000L) >> 16);
  WriteByte(x+4,y,(val & 0xFF00L) >> 8);
  WriteByte(x+6,y,(val & 0xFFL));
}

void WriteNibbleDummy(int x, int y, unsigned char val)
{
  if (val > 9)
  {
    val = 'A' + val - 10;
  }
  else
  {
    val = '0' + val;
  }
	PutChar(x*8,y*8,0,0,val,1,1,1);
}

void WriteByteDummy(int x, int y, unsigned char val)
{
  char lchr;

  lchr = (val & 0xF0) >> 4;
  WriteNibbleDummy(x,y,lchr);
  lchr = (val & 0xF);
  WriteNibbleDummy(x+1,y,lchr);
}

void WriteDwordDummy(int x, int y, unsigned long val)
{
  WriteByteDummy(x,y,(val & 0xFF000000L) >> 24);
  WriteByteDummy(x+2,y,(val & 0xFF0000L) >> 16);
  WriteByteDummy(x+4,y,(val & 0xFF00L) >> 8);
  WriteByteDummy(x+6,y,(val & 0xFFL));
}

int sceDisplaySetMode(int mode, int width, int height)
{
  register int lret asm("$2");
  register int lmode asm("$4") = mode;
  register int lwidth asm("$5") = width;
  register int lheight asm("$6") = height;
  asm __volatile__ ("syscall 0x2146;"
                    : "=r" (lret)
                    : "r" (lmode), "r" (lwidth), "r" (lheight)
                   );
  return(lret);
}

void sceDisplaySetFrameBuf(void *topaddr, int bufferwidth, int pixelformat, int sync)
{
  register void * ltop asm("$4") = topaddr;
  register int lwidth asm("$5") = bufferwidth;
  register int lformat asm("$6") = pixelformat;
  register int lsync asm("$7") = sync;
  asm __volatile__ ("syscall 0x214C;"
                    : // no output regs 

                    : "r" (ltop), "r" (lwidth), "r" (lformat), "r" (lsync)
                   );
}

void FillRect(RECT *xirect, unsigned long xicolour)
{
  unsigned long *vptrl;
  unsigned char *vptrc;
  int      y;

  for (y = xirect->top; y < xirect->bottom; y++)
  {
    int x = xirect->left;
    vptrc = GetVramAddr(x,y);
    vptrl = (unsigned long*)vptrc;

    while (x < xirect->right)
    {
      *vptrl++ = xicolour;
      x++;
    }
  }
}

POINT gcursor;

void MoveToEx(short x, short y)
{
  gcursor.x = x;
  gcursor.y = y;
}

void LineTo(short x, short y)
{
  // XXX to do

}

void changeBuffer()
{
  sceDisplayWaitVblank();
  
	sceDisplaySetFrameBuf(
      (void*)GetVramAddr(0,0),
      512,
    	PSP_DISPLAY_PIXEL_FORMAT_8888
      ,0);

	drawframe=(drawframe?0:1);
}
                    
void DebugValue(int y, char * label, unsigned long val)
{
  Print(0,y,TEXTCOLOUR,label);
  WriteDword(10,y,val);
}

void WriteDecimal(int x, int y, unsigned long val)
{
  unsigned long divisor = 10000000L;
  unsigned char nibble;

  val = val % 100000000L;

  while (divisor > 0)
  {
    nibble = val / divisor;

    WriteNibble(x, y, nibble);

    val = val - (nibble * divisor);
    x++;
    divisor /= 10;
  }
}

void initScreenAndCtrl()
{
  drawframe = 0;
	sceDisplaySetMode(0,SCREEN_WIDTH,SCREEN_HEIGHT);

	sceDisplaySetFrameBuf(
      (void*)vramtop,
      512,
    	PSP_DISPLAY_PIXEL_FORMAT_8888
      ,1);
	Fillvram(0x00000000);
  drawframe = 1;
	Fillvram(0x00000000);
  sceCtrlSetSamplingCycle(0);
  sceCtrlSetSamplingMode(1);
}

int strlen(char * xistr)
{
  int i = 0;
  while (*xistr)
  {
    i++;
  }
  return(i);
}

#define O_RDONLY 1

#define O_WRONLY 2

#define O_RDWR   3

#define O_CREAT  0x200

#define O_TRUNC  0x400

#define O_APPEND 0x100


SceUID sceIoOpen(const char *file, int flags, int mode)
{
	register const char * lfile   asm ("$4") = file;
	register int          lflags  asm ("$5") = flags;
	register int          lmode   asm ("$6") = mode;
	register SceUID       lret    asm ("$2");

	asm __volatile__ (
		"syscall 0x208F;"
		: "=r" (lret)
		: "r" (lfile), "r" (lflags), "r" (lmode)
		);

	return lret;
}

int  sceIoClose(SceUID fd)
{
	register SceUID       lfd     asm ("$4") = fd;
  register int          lret    asm ("$2");

	asm __volatile__ (
		"syscall 0x208D;"
		: "=r" (lret)
		: "r" (lfd)
		);
}

int sceIoRead(int fd,char *buf,int sz)
{
	register int    lfd    asm ("$4") = fd;
	register char * ldata  asm ("$5") = buf;
	register int    lcount asm ("$6") = sz;
	register int    lret   asm ("$2");

	asm __volatile__ (
		"syscall 0x2091;"
		: "=r" (lret)
		: "r" (lfd), "r" (ldata), "r" (lcount)
		);

	return lret;
}

int sceIoWrite(SceUID fd, const void *data, SceSize size)
{
	register SceUID       lfd    asm ("$4") = fd;
	register const void * ldata  asm ("$5") = data;
	register SceSize      lcount asm ("$6") = size;
	register int          lret   asm ("$2");

	asm __volatile__ (
		"syscall 0x2093;"
		: "=r" (lret)
		: "r" (lfd), "r" (ldata), "r" (lcount)
		);

	return lret;
}

int sceKernelExitGame()
{
	asm("syscall 0x20F2");
}

int sceKernelTerminateDeleteThread(SceUID thid)
{
	register int lret asm("$2");
	register int lthid asm("$4") = thid;

	asm ("syscall 0x2074;"
		: "=r" (lret)
		: "r" (lthid)
		);

	return(lret);
}

int sceKernelDeleteCallback(SceUID cbid)
{
	register int lret asm("$2");
	register int lthid asm("$4") = cbid;

	asm ("syscall 0x200E;"
		: "=r" (lret)
		: "r" (lthid)
		);

	return(lret);
}

#if USE_MISSING_NIDS==1

int sceKernelReferCallbackStatus(SceUID cb, SceKernelCallbackInfo *info)
{
	register int lret asm("$2");
	register int lthid asm("$4") = cb;
	register int linfo asm("$5") = info;

	asm("syscall 0x2013"
		: "=r" (lret)
		: "r" (lthid), "r" (linfo)
		);

	return(lret);	
}

int sceKernelReferThreadStatus(int thid, SceKernelThreadInfo *info)
{
	register int lret asm("$2");
	register int lthid asm("$4") = thid;
	register int linfo asm("$5") = info;

	asm("syscall 0x2080"
		: "=r" (lret)
		: "r" (lthid), "r" (linfo)
		);

	return(lret);
}

int sceKernelCancelCallback(SceUID cbid)
{
	register int lret asm("$2");
	register int lthid asm("$4") = cbid;

	asm ("syscall 0x2010"
		: "=r" (lret)
		: "r" (lthid)
		);

	return(lret);
}

int sceKernelDeleteEventFlag(SceUID vplid)
{
	register int lret asm("$2");
	register int lthid asm("$4") = vplid;

	asm ("syscall 0x2029"
		: "=r" (lret)
		: "r" (lthid)
		);

	return(lret);
}

int sceKernelIcacheInvalidateAll() {
	asm("syscall 0x20cd");
}

SceSize sceKernelTotalFreeMemSize(void)
{
	register SceSize lreturn asm ("$2") = 0;

	asm __volatile__ ("syscall 0x20E0;"
		: "=r" (lreturn)
		);
	return(lreturn);
}
 
int sceKernelDisableSubIntr(SceUID intno, SceUID no)
{
  register int lret asm("$2");
  register int lfplid asm("$4") = intno;
  register void* linfo asm("$5") = no;

   asm("syscall 0x2003"
     : "=r" (lret)
     : "r" (lfplid), "r" (linfo)
   );

  return(lret);
}

// 0x644395e2

int sceKernelGetModuleIdList(SceUID *readbuf, int readbufsize, int *idcount)
{
  register int lret asm("$2");
  register SceUID *lbuf asm("$4") = readbuf;
  register int lsize asm("$5") = readbufsize;
  register int* lidcount asm("$6") = idcount;

  asm __volatile__ ("syscall 0x20DB"
      : "=r" (lret)
      : "r" (lbuf), "r" (lsize), "r" (lidcount)
      );

  return(lret);
}

// 0x748cbed9

int sceKernelQueryModuleInfo(SceUID modid, SceKernelModuleInfo *info)
{
  register int lret asm("$2");
  register SceUID lid asm("$4") = modid;
  register void* linfo asm("$5") = info;

  asm __volatile__ ("syscall 0x20DC"
      : "=r" (lret)
      : "r" (lid), "r" (linfo)
      );

  return(lret);
}

#endif


void sceKernelDelayThread(SceUInt delay)
{
	register unsigned long lsecs asm("$4") = delay;

	asm __volatile__ ("syscall 0x201c;"
		: 
	: "r" (lsecs)
		);
}

int sceKernelGetThreadId()
{
	register int lret asm("$2");
	asm("syscall 0x207B"
		: "=r" (lret));

	return(lret);
}

#if USE_MISSING_NIDS==1

int sceKernelGetThreadmanIdList(enum SceKernelIdListType type, SceUID *readbuf, int readbufsize, int *idcount)
{
  register int ltype asm("$4") = type;
  register int * lbuf asm("$5") = readbuf;
  register int lsize asm("$6") = readbufsize;
  register int *lcount asm("$7") = idcount;
  register int lret asm("$2");

	asm("syscall 0x2083"
      : "=r" (lret)
      : "r" (ltype), "r" (lbuf), "r" (lsize), "r" (lcount)
  );
 
  return(lret);
}
#endif


SceUID sceKernelAllocPartitionMemory(SceUID partitionid, const char *name, int type, SceSize size, void *addr)
{
	register SceUID lreturn asm ("$2");
	register SceUID lpart asm ("$4") = partitionid;
	register const char * lname asm ("$5") = name;
	register int ltype asm ("$6") = type;
	register SceSize lsize asm ("$7") = size;
	register void* laddr asm("$8") = addr;

	asm __volatile__ ("syscall 0x2169;"   // fake : exitgame

		: "=r" (lreturn)
		: "r" (lpart), "r" (lname), "r" (ltype), "r" (lsize), "r" (laddr)
	);
	return(lreturn);
}

int sceKernelFreePartitionMemory(SceUID blockid)
{
  register int lreturn asm ("$2");
  register SceUID lblockid asm ("$4") = blockid;

  asm __volatile__ ("syscall 0x20E2;"
                    : "=r" (lreturn)
                    : "r" (lblockid)
                   );
  return(lreturn);
}

void * sceKernelGetBlockHeadAddr(SceUID blockid)
{
	register void *lreturn asm ("$2");
	register SceUID lblockid asm ("$4") = blockid;

	asm __volatile__ ("syscall 0x20e3;"
		: "=r" (lreturn)
		: "r" (lblockid)
		);
	return(lreturn);
}

int sceKernelCreateThread(const char *name, SceKernelThreadEntry entry, int initPriority,
						  int stackSize, SceUInt attr, SceKernelThreadOptParam *option) {
	asm("syscall 0x206d");
}

int sceKernelStartThread(SceUID thid, SceSize args, void *argp) {
	asm("syscall 0x206f");
}

SceSize sceKernelMaxFreeMemSize(void)
{
	register SceSize lreturn asm ("$2") = 0;

	asm __volatile__ ("syscall 0x20DF;"
		: "=r" (lreturn)
		);
	return(lreturn);
}

int sceKernelDcacheWritebackInvalidateAll() {
	asm("syscall 0x20c7");
}

int sceKernelDeleteFpl(SceUID fplid)
{
	register int lret asm("$2");
	register int lthid asm("$4") = fplid;

	asm ("syscall 0x204C"
		: "=r" (lret)
		: "r" (lthid)
		);

	return(lret);
}

int sceKernelDeleteSema(SceUID vplid)
{
	register int lret asm("$2");
	register int lthid asm("$4") = vplid;

	asm ("syscall 0x2021"
		: "=r" (lret)
		: "r" (lthid)
		);

	return(lret);
}

int sceKernelReleaseSubIntrHandler(SceUID intno, SceUID no)
{
  register int lret asm("$2");
  register int lfplid asm("$4") = intno;
  register void* linfo asm("$5") = no;

   asm("syscall 0x2001"
     : "=r" (lret)
     : "r" (lfplid), "r" (linfo)
   );

  return(lret);
}

// sceKernelStopModule   0xd1ff982a

int sceKernelStopModule( SceUID modid, SceSize argsize, void* argp, int* status, SceKernelSMOption* option)
{
	register SceUID lreturn asm ("$2");
	register SceUID lmodid asm ("$4") = modid;
	register SceSize largsize asm ("$5") = argsize;
	register void* largp asm("$6") = argp;
	register int* lstatus asm("$7") = status;
	register SceKernelSMOption* loption asm("$8") = option;

	asm __volatile__ ("syscall 0x20D7"
		: "=r" (lreturn)
		: "r" (lmodid), "r" (largsize), "r" (largp), "r" (lstatus), "r" (loption)
	);
	return(lreturn);
}

// sceKernelUnloadModule 0x2e0911aa

int sceKernelUnloadModule( SceUID modid )
{
	register int lret asm("$2");
	register int lthid asm("$4") = modid;

	asm ("syscall 0x20D8"
		: "=r" (lret)
		: "r" (lthid)
		);

	return(lret);
}

int sceKernelSelfStopUnloadModule (int modid, SceSize argsize, void *argp)
{
	register SceUID lreturn asm ("$2");
	register SceUID lmodid asm ("$4") = modid;
	register SceSize largsize asm ("$5") = argsize;
	register void* largp asm("$6") = argp;

	asm __volatile__ ("syscall 0x20D9"
		: "=r" (lreturn)
		: "r" (lmodid), "r" (largsize), "r" (largp)
	);
	return(lreturn);
}

int sceKernelVolatileMemUnlock(int unknown)
{
	register int lret asm("$2");
	register int lunknown asm("$4") = unknown;

	asm __volatile__ ("syscall 0x20EF"
		: "=r" (lret)
		: "r" (lunknown)
		);

	return(lret);
}

int sceUmdUnRegisterUMDCallBack() {
	asm("syscall 0x21BF");
}

int scePowerUnregisterCallback() {
	asm("syscall 0x219B");
}

int sceGeUnsetCallback() {
	asm("syscall 0x2107");
}

int sceUtilitySavedataShutdownStart()
{
	register int lret asm("$2");

	asm ("syscall 0x2201"
		: "=r" (lret)
		);

	return(lret);
}

int sceUtilitySavedataGetStatus()
{
	register int lret asm("$2");

	asm ("syscall 0x2203"
		: "=r" (lret)
		);

	return(lret);
}

int sceUtilitySavedataUpdate( SceUID modid )
{
	register int lret asm("$2");
	register int lthid asm("$4") = modid;

	asm ("syscall 0x2202"
		: "=r" (lret)
		: "r" (lthid)
		);

	return(lret);
}

int sceAudioChRelease( SceUID modid )
{
	register int lret asm("$2");
	register int lthid asm("$4") = modid;

	asm ("syscall 0x2135"
		: "=r" (lret)
		: "r" (lthid)
		);

	return(lret);
}

/*****************************************************************************/
/* NID resolution starts here                                                */
/*****************************************************************************/
/*
typedef struct {
    unsigned long l1;             // unknown 0xd632acdb
    unsigned long l2;             // unknown 0xf01d73a7
    unsigned long startAddress;   // address of _start
    unsigned long moduleInfoAddr; // address of sceModuleInfo struct
} SceResidentData;
*/

#define OFFSET_MODULE_INFO_ADDR 0x1C // 28 bytes


/*
typedef struct {
    unsigned char c1, c2, c3, c4;
    char name[28];
    unsigned long gp;           // ptr to somewhere after executable
    unsigned long libEnt;       // ptr to .lib.ent section
    unsigned long libEntBtm;    // ptr to end of .lib.ent section
    unsigned long libStub;      // ptr to .lib.stub section
    unsigned long libStubBtm;   // ptr to end of .lib.stub section
} __attribute__((packed)) SceModuleInfo;
*/

#define OFFSET_LIB_ENT_TOP_ADDR    0x2C // 44 bytes

#define OFFSET_LIB_ENT_BOTTOM_ADDR 0x30 // 48 bytes


/*
typedef struct {
    const char *libname;	       // Library name.
    unsigned int flags;		       // Flags.
    unsigned char ent_len; 	       // Number of DWORDs in this entry. The size of the entry is ent_len * 4.
    unsigned char var_ent_count;   // Number of variable entries following function entries.
    unsigned short func_ent_count; // Number of function entries.
    unsigned int lib_loc  // I've added this, havn't found doc on it - Ditlew
    unsigned int func_loc // I've added this, havn't found doc on it - Ditlew
} SceLibEntData;
*/

#define OFFSET_FUNC_COUNT    0x0A // 10 bytes

#define OFFSET_LIB_LOC_ADDR  0x0C // 12 bytes

#define OFFSET_FUNC_LOC_ADDR 0x10 // 16 bytes


typedef struct
{
	unsigned int NID;
	unsigned int pLoc;
	unsigned char *pLibName;
  unsigned int syscall;
} FUNCTIONS_TABLE;

#if USE_MISSING_NIDS==1

typedef struct
{
	unsigned int NID;
	unsigned int pLoc;
	unsigned int referenceNID;
  signed   int offsetFromReference20;
  signed   int offsetFromReference25;
  signed   int offsetFromReference26;
} MISSING_FUNCTIONS_TABLE;
#endif


int gDetectedFirmware;   // 200, 250, 260


unsigned char IoFileMgrForUser[] = "IoFileMgrForUser";
unsigned char Threadman[]        = "ThreadManForUser";
unsigned char sceDisplay[]       = "sceDisplay";
unsigned char sceCtrl[]          = "sceCtrl";
unsigned char SysMem[]           = "SysMemUserForUser";
unsigned char ge[]               = "sceGe_user";
unsigned char UtilsForUser[]     = "UtilsForUser";
unsigned char InterruptManager[] = "InterruptManager";
unsigned char ModuleMgrForUser[] = "ModuleMgrForUser";
unsigned char SuspendForUser[]   = "sceSuspendForUser";
unsigned char UMDForUser[]       = "sceUmdUser";
unsigned char Power[]            = "scePower";
unsigned char sceAudio[]         = "sceAudio";
unsigned char sceUtility[]       = "sceUtility";
unsigned char LoadExecForUser[]  = "LoadExecForUser";

#if USE_MISSING_NIDS==1

MISSING_FUNCTIONS_TABLE missing_functions[] =
{
	{ 0x94416130, (unsigned int)&sceKernelGetThreadmanIdList,  0x293b45b8,  8, 8, 0 }, 
	{ 0x17c1684e, (unsigned int)&sceKernelReferThreadStatus,   0x293b45b8,  5, 5, 0 },
	{ 0xba4051d6, (unsigned int)&sceKernelCancelCallback,      0x293b45b8, -107, -107, 0 },
	{ 0x730ed8bc, (unsigned int)&sceKernelReferCallbackStatus, 0x293b45b8, -104, -104, 0 },
	{ 0xef9e4c70, (unsigned int)&sceKernelDeleteEventFlag,     0x293b45b8, -82,  -82,  0 },

	{ 0x920f104a, (unsigned int)&sceKernelIcacheInvalidateAll, 0xb435dec5,  6, 6, 0 },

	{ 0xf919f628, (unsigned int)&sceKernelTotalFreeMemSize,    0x237dbd4f,  -1,   -8,  0 },

	{ 0x8a389411, (unsigned int)&sceKernelDisableSubIntr,      0xd61e6961,  2,   2,    0 },

	{ 0x748cbed9, (unsigned int)&sceKernelQueryModuleInfo,     0x2e0911aa,  4,   4,    0 },
	{ 0x644395e2, (unsigned int)&sceKernelGetModuleIdList,     0x2e0911aa,  3,   3,    0 },

  { 0, NULL, 0, 0 }  // terminator

};
#endif


/*****************************************************************************/
/* You can set pLoc to 0 to just retrieve the syscall, but not update the    */
/* code.                                                                     */
/*****************************************************************************/
FUNCTIONS_TABLE functions[] = {
	{	0x109f50bc, (unsigned int)&sceIoOpen,  &IoFileMgrForUser, 0 },
	{	0x810c4bc3, (unsigned int)&sceIoClose, &IoFileMgrForUser, 0 },
	{	0x6a638d83, (unsigned int)&sceIoRead,  &IoFileMgrForUser, 0 },
	{	0x42ec03ac, (unsigned int)&sceIoWrite, &IoFileMgrForUser, 0 },

	{	0x2e0911aa, (unsigned int)&sceKernelUnloadModule,           &ModuleMgrForUser, 0 },
	{	0xd1ff982a, (unsigned int)&sceKernelStopModule,             &ModuleMgrForUser, 0 },
	{	0xd675ebb8, (unsigned int)&sceKernelSelfStopUnloadModule,   &ModuleMgrForUser, 0 },
	
	{ 0x237dbd4f, (unsigned int)&sceKernelAllocPartitionMemory,  &SysMem, 0 },
	{ 0xb6d61d02, (unsigned int)&sceKernelFreePartitionMemory,   &SysMem, 0 },
	{ 0x9D9A5BA1, (unsigned int)&sceKernelGetBlockHeadAddr,      &SysMem, 0 },
	{ 0xa291f107, (unsigned int)&sceKernelMaxFreeMemSize,        &SysMem, 0 },

	{ 0x383f7bcc, (unsigned int)&sceKernelTerminateDeleteThread, &Threadman, 0 },
	{ 0x293b45b8, (unsigned int)&sceKernelGetThreadId,           &Threadman, 0 },
	{ 0x446D8DE6, (unsigned int)&sceKernelCreateThread,          &Threadman, 0 },
	{ 0xF475845D, (unsigned int)&sceKernelStartThread,           &Threadman, 0 },
	{ 0xceadeb47, (unsigned int)&sceKernelDelayThread,           &Threadman, 0 },
	{ 0xedba5844, (unsigned int)&sceKernelDeleteCallback,        &Threadman, 0 },
	{ 0xed1410e0, (unsigned int)&sceKernelDeleteFpl,             &Threadman, 0 },
	{ 0x28b6489c, (unsigned int)&sceKernelDeleteSema,            &Threadman, 0 },
	
	{ 0xd61e6961, (unsigned int)&sceKernelReleaseSubIntrHandler,&InterruptManager, 0 },
	{ 0xca04a2b9, (unsigned int)0,                              &InterruptManager, 0 },
	{ 0xfb8e22ec, (unsigned int)0,                              &InterruptManager, 0 },

	{ 0xb435dec5, (unsigned int)&sceKernelDcacheWritebackInvalidateAll, &UtilsForUser, 0 },
  { 0x71ec4271, (unsigned int)&sceKernelLibcGettimeofday,      &UtilsForUser, 0 },

	{ 0xa569e425, (unsigned int)&sceKernelVolatileMemUnlock, &SuspendForUser, 0 },

	{ 0xBD2BDE07, (unsigned int)&sceUmdUnRegisterUMDCallBack, &UMDForUser, 0 },

	{ 0xDFA8BAF8, (unsigned int)&scePowerUnregisterCallback, &Power, 0 },

	{ 0x05DB22CE, (unsigned int)&sceGeUnsetCallback, &ge, 0 },

  { 0x9790B33C, (unsigned int)&sceUtilitySavedataShutdownStart, &sceUtility, 0 },
  { 0xd4b95ffb, (unsigned int)&sceUtilitySavedataUpdate,        &sceUtility, 0 },
  { 0x8874dbe0, (unsigned int)&sceUtilitySavedataGetStatus,     &sceUtility, 0 },

  { 0x6a2774f3, (unsigned int)&sceCtrlSetSamplingCycle,         &sceCtrl,  0 },
  { 0x1f4011e6, (unsigned int)&sceCtrlSetSamplingMode,          &sceCtrl,  0 },
  { 0x1f803938, (unsigned int)&sceCtrlReadBufferPositive,       &sceCtrl,  0 },

  { 0x984c27e7, (unsigned int)&sceDisplayWaitVblankStart,       &sceDisplay, 0 },
  { 0x0e20f177, (unsigned int)&sceDisplaySetMode,               &sceDisplay, 0 },
  { 0x289d82fe, (unsigned int)&sceDisplaySetFrameBuf,           &sceDisplay, 0 },

  { 0x6fc46853, (unsigned int)&sceAudioChRelease,               &sceAudio, 0 },

  { 0x05572a5f, (unsigned int)&sceKernelExitGame,               &LoadExecForUser, 0 },

	{	0x00000000, NULL, NULL, 0	}  // list terminator

};

// This is how 20 first bytes of the GTA .rodata.sceResident looks like - Ditlew

unsigned char hash_values[0x14] = {
	0xDB, 0xAC, 0x32, 0xD6, // module_start (little-endian) - Ditlew

	0x3C, 0x59, 0xE8, 0xCE, // module_stop  (little-endian) - Ditlew

	0xA7, 0x73, 0x1D, 0xF0, // module_info  (little-endian) - Ditlew

	0x6C, 0x27, 0x7C, 0x0F,
	0x97, 0xC6, 0x0C, 0xCF
};

unsigned int find_gta_sceResident(unsigned char *data, unsigned int length)
{
	unsigned int i, j, found = 0;

	// find the gta .rodata.sceResident location

	for (i = 0, j = 0; i < length; i++)
	{
		// check a byte

		if (*(unsigned char *)(data + i) == hash_values[j])
		{
			// initialize pointer to beginning

			if (found == 0)
				found = i;

			// increase pointer in hash_values

			if (++j == 0x14)
				return found;
		}
		else
		{
			// not found

			j = found = 0;
		}
	}
	return 0;
}

int numfailed = 0;
int failednids[50];

int findKnownSyscall(unsigned long xiNID)
{
  int i; 
  int lret = 0;

  for (i=0; functions[i].NID; i++)
  {
    if (functions[i].NID == xiNID)
    {
      lret = functions[i].syscall;
      break;
    }
  }

  return(lret);
}

#define USER_PARTITION_START  0x08800000

#define USER_PARTITION_LENGTH 0x01800000


void findNIDs(unsigned char *data, unsigned int length, unsigned int lib_stub_top, unsigned int lib_stub_bottom)
{
	unsigned short int num_funcs;
	unsigned int i, j, k, lib_loc, name_loc, func_loc, syscall_opcode;
	int lfound;

	// process all functions

	for (i = 0; functions[i].NID; i++)
	{
		// process all libraries

		// 20 bytes (0x14) used on each library - Ditlew

		for (j = lib_stub_top; j < lib_stub_bottom; j += 0x14)
		{
			// check if this is the one we want

			name_loc = *(unsigned int *)&data[j] - USER_PARTITION_START;
			if (!strcmp((unsigned char *)&data[name_loc], functions[i].pLibName))
			{
				lfound = 0;

				// process all NIDs

				num_funcs = *(unsigned short int *)(&data[j + OFFSET_FUNC_COUNT]);
				lib_loc   = *(unsigned int *)      (&data[j + OFFSET_LIB_LOC_ADDR ]) - USER_PARTITION_START;
				func_loc  = *(unsigned int *)      (&data[j + OFFSET_FUNC_LOC_ADDR]) - USER_PARTITION_START;

				for (k = 0; k < num_funcs; k++)
				{
					syscall_opcode = 0;
					// check if this is the one we want

					if (*(unsigned int *)(&data[lib_loc + (k * 0x04)]) == functions[i].NID)
					{
						// patch the syscall to what it should be

						syscall_opcode = *(unsigned int *)(&data[func_loc + (k * 0x08) + 0x04]);

            functions[i].syscall = syscall_opcode >> 6;

            /*****************************************************************/
            /* Only actually modify the code if pLoc is non-null             */
            /*****************************************************************/
            if (functions[i].pLoc)
            {
  						// force the address to be uncached

  						functions[i].pLoc |= 0x40000000;
  
  						// find the syscall opcode, and replace it

  						{
  							int l;
  							unsigned int opcode;
  							for (l=0; l<20; l++)
  							{
  								opcode = ((unsigned int *)(functions[i].pLoc))[l];
  								if ((opcode & 0xFF00000FL) == 0x0000000CL)
  								{
  									((unsigned int *)(functions[i].pLoc))[l] = syscall_opcode;
  									lfound = 1;
  									break;
  								}
  							}
  						}
            }
            else
            {
              lfound = 1;
            }
					}
				}
				if (!lfound)
				{
					failednids[numfailed++] = functions[i].NID;
				}
				break;
			}
		}
	}

  /***************************************************************************/
  /* Decide which firmware version we're on, based on known NIDs             */
  /***************************************************************************/
  if (findKnownSyscall(0x293b45b8L) == 0x207b)
  {
    gDetectedFirmware = 200;
  }
  else if ((findKnownSyscall(0xfb8e22ecL) - findKnownSyscall(0xca04a2b9)) == 2)
  {
    gDetectedFirmware = 250;
  }
  else
  {
    gDetectedFirmware = 260;
  }

#if USE_MISSING_NIDS==1

  /***************************************************************************/
  /* Now fix up the ones that we have to do by inference                     */
  /***************************************************************************/
	for (i = 0; missing_functions[i].NID; i++)
	{
    unsigned int syscall = findKnownSyscall(missing_functions[i].referenceNID);
    unsigned int syscall_opcode;

    lfound = 0;

    switch (gDetectedFirmware)
    {
      case 200:
        syscall += missing_functions[i].offsetFromReference20;
        break;
      case 250:
        syscall += missing_functions[i].offsetFromReference25;
        break;
      case 260:
        syscall += missing_functions[i].offsetFromReference26;
        break;
    }

    syscall_opcode = (syscall << 6) | 0x0c;
    missing_functions[i].pLoc |= 0x40000000;
    
    // find the syscall opcode, and replace it

    {
    	int l;
    	unsigned int opcode;
    	for (l=0; l<20; l++)
    	{
    		opcode = ((unsigned int *)(missing_functions[i].pLoc))[l];
    		if ((opcode & 0xFF00000FL) == 0x0000000CL)
    		{
    			((unsigned int *)(missing_functions[i].pLoc))[l] = syscall_opcode;
    			lfound = 1;
    			break;
    		}
    	}
    }

 		if (!lfound)
 		{
 			failednids[numfailed++] = missing_functions[i].NID;
 		}
  }
#endif

}

void initial_setup(unsigned char *data, unsigned long length)
{
	unsigned int sceRes, module_info, lib_ent_top, lib_ent_bottom;

	// find sceResident

	sceRes = find_gta_sceResident(data, length);
	if (sceRes > 0)
	{
		// setup the necessary locations

		module_info     = *(unsigned int *)(&data[sceRes]     + OFFSET_MODULE_INFO_ADDR    ) - USER_PARTITION_START;
		lib_ent_top     = *(unsigned int *)(&data[module_info + OFFSET_LIB_ENT_TOP_ADDR   ]) - USER_PARTITION_START;
		lib_ent_bottom  = *(unsigned int *)(&data[module_info + OFFSET_LIB_ENT_BOTTOM_ADDR]) - USER_PARTITION_START;

		// start finding the NID's

		findNIDs(data, length, lib_ent_top, lib_ent_bottom);
	}
}