/*
================================ COPYRIGHT ================================
The contents of this file are subject to the VTech Informations Ltd. License
of VT-OS Ver. 1.1 operating system (the "License"); you may not use this 
file except in compliance with the License.  

Software distributed under the License is distributed on an "AS IS" basis, 
WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the License 
for the specific language governing rights and limitations under the License.
  
The Original Code is VT-OS Ver. 1.1 Operating System, released 
on October 1st, 1999
	
The Initial Developer of the Original Code is VTech Informations Ltd.  All 
codes are Copyright (C) VTech Informations Ltd. 1999.  All Rights Reserved.
===========================================================================
*/

/*
===========================================================================
File        :   kernel.c
Author(s)   :   Kenng Ng, Henry fok, Thomas Cheng
Company     :   VTech Informations Ltd.
Project     :   Helio 
Date:	    :   October 1st, 1999
Purpose:	:   Kernel - system core
Revision    :   1.1
Note        :   None
===========================================================================
*/              

//#define DEBUG
//#define DEBUG_INSTALL
//#define DEBUG_HENRY
//#define DEBUG_NUM

#include "stdafx.h"
#include "pr3910.h"
#include "kernel.h"
#include "intc.h"
#include "mmu.h"
#include "tlb.h"
#include "uievent.h"
#include "dm.h"
#include "system.h"
#include "dev_pwr.h"
#include "lcddrv.h"
#include "tmrapi.h"

//#define VER_NO_ADDR 0x9fc10100

#define VER_NO_ADDR 0x9fc10020          /* AH: 991007 */

#define VER_NO_SIZE 16
#define  SYSCALL_BASE_TOTAL        850
#define TOTAL_INSTALLABLE_SYSCALL  300

#ifdef DEBUG
void count_malloc();
extern int counta;
extern int countf;
extern int totala;
extern int totalf;
extern int countqa;
extern int countqf;
#endif

#ifdef PC_SIM
#include <string.h>
#endif

AppID 	prev_appid;
WORD 	prev_launch_cmd;
void 	*prev_launch_cmd_ptr;

UWORD sys_asid[32];
REGISTRY app_reg[APP_MAX];
extern UWORD* user_dynamic_mem_address;
extern EvtQueueType evtQueue;
extern MsgQueueType msgQueue;
extern BYTE GPassCheck;

#ifdef PR31700
extern HOOKTABLE int_hook_table[512];
extern SysCallFptr[];
#endif

BOOLEAN ShellHandleEventWhileLoop();

typedef struct USER_POOL
{
	WORD	   pool_size;         /* in byte */
	WORD	   owner_id;            /* owner id */
	struct USER_POOL  *size_ptr;
} USER_MEMPOOL;

int_lookup_tbl int_lookup_table[HOOKABLE_ADDR];

UWORD *sys_page, *app_page, *int_page;
extern UWORD *app_page_table;
extern UWORD *int_page_table;
extern UWORD mmu_total_free_block;

void (*RunApp)(UWORD cmd, UWORD *cmd_ptr);

extern USER_MEMPOOL *user_free_list;
extern BYTE user_mem_init;
extern UWORD *user_dynamic_mem_address;        /* start address of dynamic memory pool */
extern WORD user_dynamic_mem_size;
extern USHORT dmuser_first_block;

// Thomas 240899
typedef struct
{
	UWORD addr;
	UWORD appid;
} SysCallHookedTable;

SysCallHookedTable SysCallHookedFptr[TOTAL_INSTALLABLE_SYSCALL];
//AppID SysCallAppID[TOTAL_INSTALLABLE_SYSCALL];

InstallAppInf install_app_inf[APP_MAX - TOTAL_PRE_INSTALL_APP];
extern BYTE install_icon_res_data[];
/*      Function        : SysSaveActiveUserDM
*	Purpose		: Save the status for user DM
*  	Scope		: Internel
*	Input		: None
*	Output      	: None
*	Return		: None
*	Comment		:
*/
BYTE save_user_mem_init;
UWORD *save_user_dynamic_mem_address;        /* start address of dynamic memory pool */
WORD save_user_dynamic_mem_size;
USHORT save_dmuser_first_block;
UBYTE run_mode;

struct size_identifier save_user_dynamic_mem_settings[MM_MAX_ORDER];
extern struct size_identifier user_mm_link[];

extern volatile WORD     SndAction;


void SysSaveActiveUserDMStatus()
{
	WORD i;
	
	save_user_mem_init = user_mem_init;
	save_dmuser_first_block = dmuser_first_block;
	save_user_dynamic_mem_address = user_dynamic_mem_address;        /* start address of dynamic memory pool */
	save_user_dynamic_mem_size = user_dynamic_mem_size;
	
	for(i=0;i<MM_MAX_ORDER;i++)
		save_user_dynamic_mem_settings[i] = user_mm_link[i];
	
	user_mm_init();
	
	user_dynamic_mem_address = (UWORD*) 0xFFFFFFFF;
	user_dynamic_mem_size  = 0;
	user_mem_init = 0;
	dmuser_first_block = 0xFFFF;
	
}

/*      Function        : SysRestoreActiveUserDM
*	Purpose		: Restore the status for user DM
*  	Scope		: Internel
*	Input		: None
*	Output      	: None
*	Return		: None
*	Comment		:
*/
void SysRestoreActiveUserDMStatus()
{
	UWORD i;
	
	user_mem_init = save_user_mem_init;
	user_dynamic_mem_address = save_user_dynamic_mem_address;        /* start address of dynamic memory pool */
	user_dynamic_mem_size = save_user_dynamic_mem_size;
	dmuser_first_block = save_dmuser_first_block;
	
	for(i=0;i<MM_MAX_ORDER;i++)
		user_mm_link[i] = save_user_dynamic_mem_settings[i];
}



/*      Function        : SysTotalInstalledApp
*	Purpose		: Count total installed applications
*  	Scope		: All
*	Input		: type		Application type, APP_TYPE_APP, APP_TYPE_DRV or APP_TYPE_ALL
*	Output      	: None
*	Return		: Total application of that type
*	Comment		:
*/
USHORT SysTotalInstalledApp(UBYTE type)
{
	UWORD i;
	USHORT total_app = 0;
	for (i=0; i<APP_MAX; i++)
	{
		if(app_reg[i].app_name[0] != 0)
		{
			if((UBYTE)((UBYTE)app_reg[i].attribute & (UBYTE)type) == (UBYTE)type)
			{
				total_app++;
			}
		}
	}
	return total_app;
}


/*	Function	: SysGetAppName
*	Purpose		: Count total installed applications
*  	Scope		: All
*	Input		: app		Application ID
*	Output      	: app_name
*	Return		: TRUE, FALSE
*	Comment		: app_name MUST be pre-allocated 20 bytes
*/
BOOLEAN SysGetAppName(AppID app, BYTE *app_name)
{
	USHORT index;
	if(SysGetAppEntryIndex(app, &index) != TRUE)
		return FALSE;
	
	strcpy(app_name, app_reg[index].app_name);
	return TRUE;
}


/*	Function	: SysGetAppSize
*	Purpose		: Get Application size
*  	Scope		: All
*	Input		: app		Application ID
*	Output      	: size		Application size, unit: 4KB
*	Return		: TRUE, FALSE
*	Comment		: 
*/
BOOLEAN SysGetAppSize(AppID app, UWORD *size)
{
	USHORT index;
	if(SysGetAppEntryIndex(app, &index) != TRUE)
		return FALSE;
	
	*size = app_reg[index].page_need;
	return TRUE;
	
}


/*	Function	: SysGetAppIDFromIndex
*	Purpose		: Get application ID
*  	Scope		: All
*	Input		: index
*	type		: application type, APP_TYPE_APP, APP_TYPE_DRV or APP_TYPE_ALL
*	Output      	: None
*	Return		: AppID or 0xffff for error
*	Comment		:
*/
AppID SysGetAppIDFromIndex(USHORT index, UBYTE type)
{
	UWORD i;
	if(index >= APP_MAX)
		return 0xffff;
	
	for(i=0;i<APP_MAX;i++)
	{
		if(app_reg[i].app_name[0])
		{
			if((UBYTE)((UBYTE)app_reg[i].attribute & (UBYTE)type) == (UBYTE)type)
			{
				if(!index)
					break;
				index--;
				
			}
		}
	}
	
	if(!index)
		return app_reg[i].app_id;
	else
		return 0xffff;
}	

/*      Function        : SysGetIndexAppID
*	Purpose		: Get application ID
*  	Scope		: All
*	Input		: index
*	Output      	: None
*      Return          : AppID
*	Comment		:
*/
AppID SysGetIndexAppID(USHORT index)
{
	if(index >= APP_MAX)
		return 0xffff;
	
	if(app_reg[index].app_name[0] == 0)
		return 0xffff;
	
	return app_reg[index].app_id;
}





/*      Output          : None
*	Return		: Success or fail
*	Comment		:
*/

UWORD *save_app_page_table;
BOOLEAN SysLoadAppMode1PageTable(AppID index)
{
	UWORD *app_table;
	UWORD *dest_table, data_page_req;
    USHORT i;
	USHORT new_block;
	UWORD *mode1_table;
    USHORT prg_page_req;
	
	/* page table's pre-set total entry = prg code size + 2 data page,
	if data page  > 2, need to allocated dynamically */
#ifdef xxxxxxxx
	if(SysGetAppEntryIndex(app_id, &index) != TRUE)
		return FALSE;	/* app id not found */
#endif
	app_table = app_reg[index].page_table;
	
	if(!app_table)
    {
#ifdef DEBUG
        printf("\nPageTable not init");
#endif
		return FALSE;		/* page table not init. */
    }
	
	app_table -= 1;		/* hack: the total number of page is in page_table - 1 */
	
	data_page_req = (UWORD) ((app_reg[index].data_size) / BLOCK_SIZE  + 1);
	//        if(data_page_req <=2 )
	prg_page_req = app_table[0] - data_page_req; 
	//        else
	//                prg_page_req =  app_table[0] - data_page_req;
#ifdef DEBUG         
	printf("\nData page req = %d ", data_page_req);
	printf("\nProg page req = %d ", prg_page_req);
#endif
	
	if((mode1_table = (UWORD*) pmalloc((prg_page_req + data_page_req + 2) * sizeof(UWORD*))) == NULL)
		return FALSE;
	
	*mode1_table = prg_page_req + data_page_req;
	dest_table = mode1_table + 1;
	
	if(MemoryNewBlock(&mat_info[0], data_page_req,  (DatabaseID) 0,MAT_BLOCK_APP_DATA_MODE1, 0xFFFF, &new_block) != TRUE)
	{
		pfree(mode1_table);
		return FALSE;
	}
	
    for(i=0;i<=prg_page_req - data_page_req ;i++)
	{	/* copy program table */
		dest_table[i] = app_table[i+1];
#ifdef DEBUG
		printf("\nPage %d physical address = %08x ", i, app_table[i+1]);
#endif
	}
	for(i=0;i<data_page_req;i++)
	{	/* allocate bss space */
		dest_table[prg_page_req + i] = BlockAddr1(mat_info[0], new_block);
#ifdef DEBUG
		printf("\nPage %d physical address = %08x ", prg_page_req + i , dest_table[prg_page_req + i]);
#endif
		MemoryNextBlock(&mat_info[0], new_block, &new_block);
	}
	save_app_page_table = app_page_table;
	app_page = dest_table;  /* re-map TLB page table */
	app_page_table = app_page - 1;
#ifdef DEBUG
	printf("\ntotal page in app_page_table = %d", *app_page_table);
#endif
	
	return TRUE;
}

/*	Function	: SysClearAppMode1PageTable
*	Purpose		: Restore suspended app's page table
*  	Scope		: OS
*	Input		: app	Application ID
*	Output      	: None
*	Return		: None
*	Comment		:
*/
void SysClearAppMode1PageTable(AppID app)
{
	pfree(app_page_table);      /* free mode1 page table */
	SysClearMode1AppData(app);      /* clear mode1 bss page */
	app_page_table = save_app_page_table;
	MemoryGetPageTable(NULL, &app_page, NULL); /* restore page table */
}

/*	Function	: SysClearMode1AppData
*	Purpose		: Clear the bss and DM (qmalloc) allocated block when app quit
*      Scope		: OS
*	Input		: app	Application ID
*	Output          : None
*	Comment		:
*/

BOOLEAN SysClearMode1AppData(AppID app)
{
	UWORD i,j;
#ifdef DEBUG
	printf("\nClear Mode1 app data ");
#endif
	
	for(i=0;i<TOTAL_SLOT;i++)
	{
		for(j=0;j<mat_info[i].total_entry;j++)
		{
			if((BlockType(mat_info[i].mat[j].attribute) == MAT_BLOCK_APP_DATA_MODE1)) /* && mat.id = appid */
			{
				SetBlockType(mat_info[i].mat[j].attribute, MAT_BLOCK_FREE);
				mmu_total_free_block++;
            }
		}
	}
	return TRUE;
}

/*      Function        : SysRunMode1App
*	Purpose		: Run the application
*  Scope		: OS
*	Input		: Application ID
*	Output      : None
*	Return		: Success or fail
*	Comment		:
*/

extern UWORD *os_dynamic_mem_address;        /* start address of dynamic memory pool */
extern WORD os_dynamic_mem_size;

BOOLEAN SysRunMode1App(AppID app_id, WORD cmd, void *cmd_ptr)
{
    UWORD i;
	USHORT old_app_index;
	AppID cur_app;
	UWORD *addr;
	//    BYTE buf[20];
	
	
	cur_app = SysGetActiveAppID();
	if(SysGetAppEntryIndex(SysGetActiveAppID(), &old_app_index) == FALSE)  /* get current app index */
		return FALSE;		/* invalid active app id */
	
	for (i=0; i<APP_MAX; i++)
	{
		if (app_reg[i].app_id == app_id)
		{
			SysSaveActiveUserDMStatus();   /* save User DM info */
			run_mode = RUN_MODE_MODE1;
			ClrAttribute(app_reg[old_app_index].attribute, BIT_RUN);
			SetAttribute(app_reg[i].attribute, BIT_RUN);
#ifdef DEBUG
			printf("\nPT B4 mode1 ");
			printf("\nOrg DM %08x %08x %d ", os_dynamic_mem_address, os_dynamic_mem_size, sys_page_table[0]);
#endif
            SysBuildPageTable(i);
            SysLoadAppMode1PageTable(i); /* init the page table for the application */
            TlbInit();
			addr = (UWORD *)*app_page;
			
			if(ChkAttribute(app_reg[i].attribute, BIT_FLASH_PRG))
				memcpy((void *)*(addr+2)+USER_MEM_BASE, (void *)*(addr+1)+*app_page , *(addr+3)-*(addr+2));
			else
			{
				//#ifdef DEBUG
				WORD data_size = *(addr+3)-*(addr+2);
				WORD data_offset = *(addr+1) & 0x00000fff;
				UWORD page_index = *(addr+1) / BLOCK_SIZE;
				UWORD index = 0;
				BYTE *pdest_data;
				WORD remain_size = data_size;
				WORD copy_size;
				WORD total_len = data_offset + data_size;
				
				//                        printf("\nCopying data from %08x to %08x of size %08x",
				//                                *(addr+1)+*app_page,*(addr+2)+USER_MEM_BASE,*(addr+3)-*(addr+2));
				//#endif
				
				//memcpy((void *)*(addr+2)+USER_MEM_BASE, (void *)*(addr+1)+*app_page , *(addr+3)-*(addr+2));
				
				//            for(j=0;j<*(app_page-1);j++)
				//              printf("\napp page %d %08x ",j,  app_page[j]);
				
				pdest_data = (BYTE*)(*(addr+2)+ index * BLOCK_SIZE + USER_MEM_BASE);
				
				if( data_size + data_offset > BLOCK_SIZE)
					copy_size =  BLOCK_SIZE - data_offset;
				else
					copy_size = data_size;
				
				for(index=0;index<total_len/BLOCK_SIZE+1;index++)
				{
					//printf("\noffset = %d ", data_offset);                            
					//printf("\npdest_data = %08x ", pdest_data);
					//printf("\ncopy from %08x to %08x of size %d ", app_reg[i].page_table[page_index] + data_offset, *(addr+2)+ index * BLOCK_SIZE + USER_MEM_BASE, BLOCK_SIZE - data_offset); 
					//                            memcpy((void *)*(addr+2)+ index * BLOCK_SIZE + USER_MEM_BASE , (void *) app_page[page_index++]  + first_offset , BLOCK_SIZE);
					//                            memcpy((void *)*(addr+2)+ index * BLOCK_SIZE + USER_MEM_BASE , (void *) app_reg[i].page_table[page_index++]  + data_offset , BLOCK_SIZE - data_offset);
					//                           data_offset = 0;                           
					
					//                             memcpy((void *)*(addr+2)+ index * BLOCK_SIZE + USER_MEM_BASE , (void *) pdest_data , BLOCK_SIZE - data_offset);
					//#ifdef xxxxxxxxxxxxx
					//                             memcpy((void *) pdest_data , (void *)app_reg[i].page_table[page_index++] + data_offset, BLOCK_SIZE - data_offset);
					//    printf("\ncopy from %08x to %08x of size %d ", app_reg[i].page_table[page_index] + data_offset, pdest_data, copy_size);                             
					memcpy((void *) pdest_data , (void *)app_reg[i].page_table[page_index++] + data_offset,  copy_size);
					pdest_data += copy_size;
					remain_size -= copy_size;                            
					data_offset = 0;
					copy_size = (remain_size>BLOCK_SIZE)? BLOCK_SIZE: remain_size ;                                                         
					//#endif                             
				}
				
			}
#ifdef DEBUG
			printf("\nSet bss at %08x of size %08x",
				(UWORD)*(addr+4)+USER_MEM_BASE,(UWORD)*(addr+5)-*(addr+4));
#endif
			memset(*(addr+4)+USER_MEM_BASE, 0x00, *(addr+5)-*(addr+4));
			
			
			RunApp(cmd, cmd_ptr);
#ifdef DEBUG
			printf("\nMode1AppBack ");
#endif
			SysClearAppMode1PageTable(app_id);
#ifdef DEBUG
			printf("\nRestored DM address %08x %08x %d ", os_dynamic_mem_address, os_dynamic_mem_size, sys_page_table[0]);
#endif
			SysRestoreActiveUserDMStatus();  /* restore user DM info */
			run_mode = RUN_MODE_NORMAL;
			ClrAttribute(app_reg[i].attribute, BIT_RUN);
			SetAttribute(app_reg[old_app_index].attribute, BIT_RUN);
			TlbInit();
#ifdef DEBUG
			printf("\nRestored PT ");
#endif
			return TRUE;
		}
	}
	return FALSE;
}



/*	Function	: SysInit
*	Purpose		: Initialize the system
*  Scope		: OS
*	Input		: None
*	Output      : None
*	Comment		:
*/

void SysInit()
{
	USHORT i;
	for (i=0; i<32; i++)
		sys_asid[i] = 0;
	for (i=0; i<APP_MAX; i++)
	{
		app_reg[i].app_name[0] = 0;
		app_reg[i].data_size = 0;
		app_reg[i].page_table = NULL;
		
	}
	sys_page = NULL;
	app_page = NULL;
	int_page = NULL;
	
    for(i=0;i<APP_MAX - TOTAL_PRE_INSTALL_APP;i++)
    {
		install_app_inf[i].reg_entry_index = 0xff;
		install_app_inf[i].icon_index = 0xff;
    }
	
    for(i=0;i<HOOKABLE_ADDR;i++)
    {
        int_lookup_table[i].page_table = NULL;
        int_lookup_table[i].appid = 0;
    }
	
	RunApp = (void *)0x10000020;
}

/*	Function	: SysLoadAppPageTable
*	Purpose		: Load the page table from registry before application start to run
*  	Scope		: OS
*	Input		: app_id  Application ID
*	Output      	: None
*	Return		: Success or fail
*	Comment		:
*/

BOOLEAN SysLoadAppPageTable(AppID app_id)
{
	UWORD *app_table;
	UWORD *dest_table, data_page_req;
	USHORT index, i;
	USHORT new_block;
	
	
	
	if(SysGetAppEntryIndex(app_id, &index) != TRUE)
		return FALSE;	/* app id not found */
	
	if(!app_page)	/* page table not init. */
		MemoryGetPageTable(NULL, &app_page, NULL);  /* init. application page table */
	
	dest_table = app_page - 1; /* hack: the total number of page is in app_page - 1 */
	app_page_table = dest_table;
	
	app_table = app_reg[index].page_table;
	
	if(!app_table)
		return FALSE;		/* page table not init. */
	
	app_table -= 1;		/* hack: the total number of page is in page_table - 1 */
	
	for(i=0;i<=app_table[0];i++)	/* copy the page table */
	{
		dest_table[i] = app_table[i];
	}
	
	//        if(app_reg[index].data_size < 2 * BLOCK_SIZE)   /* no need to allocate some more space for data/bss */
	//                return TRUE;
	
	data_page_req = (UWORD) ((app_reg[index].data_size ) / BLOCK_SIZE + 1);
	
#ifdef xxxxxxxxxxxxxxxxxxxxxxxxxxx
	
	if(data_page_req <= 2)
		return;
	data_page_req -= 2;
#endif
	
	if(MemoryNewBlock(&mat_info[0], data_page_req,  0xFFFFFFFF,MAT_BLOCK_APP_DATA, 0xFFFF, &new_block) != TRUE)
		return FALSE;
	
	/* 2 data block already allocated during install */
	for(i=0;i<data_page_req; i++)
	{
		//		app_table[app_table[0] - data_page_req + i + 1] = BlockAddr1(mat_info[0], new_block);
		//		dest_table[app_table[0] - data_page_req + i + 1] = app_table[app_table[0] - data_page_req + i + 1];
		dest_table[app_table[0] - data_page_req + i + 1] = BlockAddr1(mat_info[0], new_block);
#ifdef DEBUG
		printf("\npage %d  Phy address: %08x", app_table[0] - data_page_req + i + 1, app_table[app_table[0] - data_page_req + i + 1]);
#endif
		
		MemoryNextBlock(&mat_info[0], new_block, &new_block);
	}
	
	return TRUE;
}


/*	Function	: SysLoadInterruptPageTable
*	Purpose		: Load the page table from registry before interrupt routine start
*  	Scope		: OS
*	Input		: app_id  Application ID
*	Output      	: None
*	Return		: Success or fail
*	Comment		:
*/

BOOLEAN SysLoadInterruptPageTable(AppID app_id)
{
	USHORT index, i;
	USHORT new_block;
	
	UWORD *int_table;
	UWORD *dest_table, data_page_req;
	UWORD *addr;
	
	//        UWORD *ptr;
	
	if(SysGetAppEntryIndex(app_id, &index) != TRUE)
		return FALSE;	/* app id not found */
	
	SysBuildPageTable(app_id);
	
	if(!int_page)	/* page table not init. */
		MemoryGetPageTable(NULL, NULL, &int_page);  /* init. application page table */
	
	dest_table = int_page - 1; /* hack: the total number of page is in app_page - 1 */
	int_page_table = dest_table;
	
	int_table = app_reg[index].page_table;
	
	if(!int_table)
		return FALSE;		/* page table not init. */
	
	int_table -= 1;		/* hack: the total number of page is in page_table - 1 */
	
	//        SysEnableDebug();
	
	for(i=0;i<=int_table[0];i++)	/* copy the page table */
	{
		//                printf("\npage %d  Phy address: %08x", i, int_table[i]);
		dest_table[i] = int_table[i];
		/*
		if(i >= 92)
		{
		int *data = (int*) (int_table[i] + 0x4b0);
		printf("\nData of %08x = %08x ", data, *data);
		}
		*/
	}
	
#ifdef xxxxxxxxxxxxxxxxxxxxxxxxxx
	data_page_req = (UWORD) ((app_reg[index].data_size ) / BLOCK_SIZE + 1);
	
	if(MemoryNewBlock(&mat_info[0], data_page_req,  0xFFFFFFFF ,MAT_BLOCK_INT_DATA, 0xFFFF, &new_block) != TRUE)
		return FALSE;
	
	printf("\ndata_page_req = %d ", data_page_req);
	
	/* 2 data block already allocated during install */
	for(i=0;i<data_page_req; i++)
	{
		int_table[int_table[0] - data_page_req + i + 1] = BlockAddr1(mat_info[0], new_block);
		dest_table[int_table[0] - data_page_req + i + 1] = int_table[int_table[0] - data_page_req + i + 1];
		
		printf("\npage %d  Phy address: %08x", int_table[0] - data_page_req + i + 1, int_table[int_table[0] - data_page_req + i + 1]);
		
		MemoryNextBlock(&mat_info[0], new_block, &new_block);
	}
#endif
	
	//        addr = (UWORD *)*int_page;
	
	//        memcpy((void *)*(addr+2)+ INT_MEM_BASE, (void *)*(addr+1)+*int_page , *(addr+3)-*(addr+2));
	//        memset(*(addr+4)+INT_MEM_BASE, 0x00, *(addr+5)-*(addr+4));
	
	//        ptr = (UWORD*)0x3005db00;
	
	//        printf("\nTry to access 0x3005db00");
	
	//        printf("\nData = %08x ", *ptr);
	
	return TRUE;
}

/*	Function	: SysNewApp
*	Purpose		: Register new application
*  	Scope		: OS
*	Input		: app_name application name
*                        type     APP_TYPE_APP or APP_TYPE_DRV
*                        alarm    Has alaram feature or not
*                        resource virtual address
* 			  page     table pointer
*	Output      	: appid    application ID
*	Return		: ERR_SYS_APP_EXIST
*			  ERR_SYS_REG_FULL
*                        TRUE
*	Comment		:
*/
Err SysNewApp(BYTE app_name[20], UBYTE attr, UWORD prg_addr, UBYTE run_spec, UWORD *res_addr, UWORD data_size, UWORD *page_table, AppID *app)
{
	UWORD i, j;
	
	if(SysGetAppID(app_name, app) == TRUE)
		return ERR_SYS_APP_EXIST;
	
	for (i=0; i<APP_MAX; i++)
	{
		if(app_reg[i].app_name[0] == 0)
		{
			*app = app_reg[i].app_id = SysNextAppID();
			for (j=0; j<20; j++)
				app_reg[i].app_name[j] = app_name[j];
			app_reg[i].res_addr = res_addr;
			app_reg[i].page_table = page_table;
			app_reg[i].data_size = data_size;
			app_reg[i].attribute = 0x00;   /* clear all attribute */
			app_reg[i].attribute = attr;
			app_reg[i].run_spec = run_spec;
			app_reg[i].start_block = prg_addr; /* if flash prg, = phy address of the prg, if not flash prg, = start blk# of the prg */
#ifdef DEBUG
			printf("\nSysNewApp:\n\nstart block = %08x ", app_reg[i].start_block);
#endif
			app_reg[i].page_need = *(page_table-1);
#ifdef DEBUG
			printf("\nPage need = %d ", app_reg[i].page_need);
#endif
			SetAttribute(app_reg[i].attribute, BIT_ALL_APP);
			return TRUE;
		}
	}
	return ERR_SYS_REG_FULL;
}


/*	Function	: SysClearAppData
*	Purpose		: Clear the bss and DM (qmalloc) allocated block when app quit
*      Scope		: OS
*	Input		: app	Application ID  - currently unused
*	Output          : None
*	Comment		:
*/

extern BYTE user_mem_init;
extern USHORT dmuser_first_block;
BOOLEAN SysClearAppData(AppID app)
{
	UWORD i,j;
	
	for(i=0;i<TOTAL_SLOT;i++)
	{
		for(j=0;j<mat_info[i].total_entry;j++)
		{
			if((BlockType(mat_info[i].mat[j].attribute) == MAT_BLOCK_APP_DATA) ||
				(BlockType(mat_info[i].mat[j].attribute) == MAT_BLOCK_APPDMA))  /* && mat.id = appid */
			{
#ifdef DEBUG
                printf("\nClear User DM block ");
#endif
				SetBlockType(mat_info[i].mat[j].attribute, MAT_BLOCK_FREE);
				mmu_total_free_block++;
			}
		}
		UpdateMATCRC((&mat_info[i]));
	}
    app_page_table = NULL;
    user_mem_init = 0;
    dmuser_first_block = 0xFFFF;
    user_dynamic_mem_address = (UWORD*) 0xFFFFFFFF;
	
	return TRUE;
}

/*      Function        : SysClearSysData
*      Purpose         : Clear pmalloc allocated block
*      Scope		: OS
*      Input           : None
*	Output          : None
*	Comment		:
*/

extern UWORD *os_dynamic_mem_address;        /* start address of dynamic memory pool */
extern WORD os_dynamic_mem_size;
extern WORD dm_os_init;
extern ResLnk *openres_table;
extern LinkListForm *main_pointer;
extern LookupTable *lookup_table_ptr;
BOOLEAN SysClearSysData()
{
	UWORD i,j;
	
	for(i=0;i<TOTAL_SLOT;i++)
	{
		for(j=0;j<mat_info[i].total_entry;j++)
		{
			if(BlockType(mat_info[i].mat[j].attribute) == MAT_BLOCK_OSDMA)
			{
#ifdef DEBUG
                printf("\nClear Sys(pmalloc) block ");
#endif
				SetBlockType(mat_info[i].mat[j].attribute, MAT_BLOCK_FREE);
				mmu_total_free_block++;
			}
		}
		UpdateMATCRC((&mat_info[i]));
	}
	opendb_table = NULL;
	openres_table = NULL;
	dmos_first_block = 0xFFFF;
	dmuser_first_block = 0xFFFF;
	run_mode = RUN_MODE_NORMAL;
	os_dynamic_mem_address = (UWORD*) 0xFFFFFFFF;
	os_dynamic_mem_size  = 0;
	dm_os_init = 0;
	main_pointer = NULL;
	lookup_table_ptr = NULL;
	for(i=0;i<APP_MAX;i++)
		app_reg[i].page_table = NULL;
	
	UpdateMATCRC((&mat_info[0]));
	
	return TRUE;
}



/*      Function        : SysClearDBData
*      Purpose         : Clear pmalloc allocated block
*      Scope		: OS
*      Input           : None
*	Output          : None
*	Comment		:
*/

BOOLEAN SysClearDBData()
{
	UWORD i,j;
	
	for(i=0;i<TOTAL_SLOT;i++)
	{
		for(j=0;j<mat_info[i].total_entry;j++)
		{
			if((BlockType(mat_info[i].mat[j].attribute) == MAT_BLOCK_DB_REC) ||
				(BlockType(mat_info[i].mat[j].attribute) == MAT_BLOCK_REC))  /* && mat.id = appid */
            {
				SetBlockType(mat_info[i].mat[j].attribute, MAT_BLOCK_FREE);
				mmu_total_free_block++;
			}
		}
	}
	opendb_table = NULL;
    UpdateMATCRC((&mat_info[0]));
	return TRUE;
}


/*	Function	: SysClearInterruptData
*	Purpose		: Clear data used by int
*      Scope		: OS
*	Input		: app	Application ID  - currently unused
*	Output          : None
*	Comment		:
*/
BOOLEAN SysClearInterruptData(AppID app)
{
	UWORD i,j;
	
	for(i=0;i<TOTAL_SLOT;i++)
	{
		for(j=0;j<mat_info[i].total_entry;j++)
		{
			if((BlockType(mat_info[i].mat[j].attribute) == MAT_BLOCK_INT_DATA)) // && mat.id = appid */
			{
#ifdef DEBUG
                printf("\nClear Interrupt data ");
#endif
                int_page_table = NULL;
				SetBlockType(mat_info[i].mat[j].attribute, MAT_BLOCK_FREE);
				mmu_total_free_block++;
			}
		}
		UpdateMATCRC((&mat_info[i]));
	}
	return TRUE;
}

/*	Function	: SysRemoveApp
*	Purpose		: Remove an application from registry
*  	Scope		: OS
*	Input		: app_id   application ID
*	Output      	: None
*	Return		: TRUE, FALSE
*	Comment		:
*/
BOOLEAN SysRemoveApp(AppID app_id)
{
	UWORD i, j, k;
	BOOLEAN return_val = FALSE;
	for (i=0; i<APP_MAX; i++)
	{
		if (app_reg[i].app_id == app_id)
		{
			for(j=0;j<APP_MAX - TOTAL_PRE_INSTALL_APP;j++)
			{
				if(install_app_inf[j].reg_entry_index == i)
				{
					for(k=j;k<APP_MAX - TOTAL_PRE_INSTALL_APP - 1;k++)
						install_app_inf[k] = install_app_inf[k+1];
					install_app_inf[APP_MAX - TOTAL_PRE_INSTALL_APP - 1].reg_entry_index = 0xff;
					install_app_inf[APP_MAX - TOTAL_PRE_INSTALL_APP - 1].icon_index = 0xff;
					j = 1000; /* exit loop */
				}
			}
			
			if(ChkAttribute(app_reg[i].attribute, BIT_TYPE))  /* DD */
			{
				IntUnhookISRbyAppID(app_id);
				SysUnHookSyscallByAppID(app_id);
				
				for(k=0;k<HOOKABLE_ADDR;k++)
					if(int_lookup_table[k].appid == app_id)
					{
						int_lookup_table[k].appid = 0;
						int_lookup_table[k].page_table = NULL;
					}
					
			}
			app_reg[i].app_name[0] = 0;
			if(app_reg[i].page_table)
				pfree(app_reg[i].page_table - 1);
			MemoryReleaseBlock(&mat_info[0], app_reg[i].start_block, TRUE, TRUE);
			return_val = TRUE;
			break;
		}
	}
	return return_val;
}

SysSetActiveAppID(AppID app_id)
{
	UWORD i;
	
	for (i=0; i<APP_MAX; i++)
	{
		if (app_reg[i].app_id == app_id)
		{
			SetAttribute(app_reg[i].attribute, BIT_RUN);
		}
		else
			ClrAttribute(app_reg[i].attribute, BIT_RUN);
	}
	
}

#ifdef PR31700
/*	Function	: SysRunApp
*	Purpose		: Run the application
*  Scope		: OS
*	Input		: Application ID
*	Output      : None
*	Return		: Success or fail
*	Comment		:
*/
extern BYTE user_mem_init;
BOOLEAN SysRunApp(USHORT app_id, UWORD cmd, UWORD *cmd_ptr)
{
	UWORD *addr;
	USHORT i;
	for (i=0; i<APP_MAX; i++)
	{
		if (app_reg[i].app_id == app_id)
		{
			//                       SysEnableDebug();
			run_mode = RUN_MODE_NORMAL;
			SetAttribute(app_reg[i].attribute, BIT_RUN);
			SysBuildPageTable(i);
			SysLoadAppPageTable(app_id); /* init the page table for the application */
			TlbInit();
			user_mem_init = 0;
			user_mm_init();
#ifdef DEBUG
			printf("\nB4 run");
#endif
			addr = (UWORD *)*app_page;
			if(ChkAttribute(app_reg[i].attribute, BIT_FLASH_PRG))
				memcpy((void *)*(addr+2)+USER_MEM_BASE, (void *)*(addr+1)+*app_page , *(addr+3)-*(addr+2));
			else
			{
				//#ifdef DEBUG
				BYTE *pdest_data;
				WORD data_size = *(addr+3)-*(addr+2);
				WORD data_offset = *(addr+1) & 0x00000fff;
				UWORD page_index = *(addr+1) / BLOCK_SIZE;
				UWORD index = 0;
				WORD remain_size = data_size;
				WORD copy_size;
				WORD total_len = data_offset + data_size;
				
				//                        SysEnableDebug();
				
				//                        printf("\nCopying data from %08x to %08x of size %08x",
				//                                *(addr+1)+*app_page,*(addr+2)+USER_MEM_BASE,*(addr+3)-*(addr+2));
				//#endif
				
				//memcpy((void *)*(addr+2)+USER_MEM_BASE, (void *)*(addr+1)+*app_page , *(addr+3)-*(addr+2));
				
				//            for(j=0;j<*(app_page-1);j++)
				//              printf("\napp page %d %08x ",j,  app_page[j]);
				
				pdest_data = (BYTE*)(*(addr+2)+ index * BLOCK_SIZE + USER_MEM_BASE);
				
				if( data_size + data_offset > BLOCK_SIZE)
					copy_size =  BLOCK_SIZE - data_offset;
				else
					copy_size = data_size;
				
				for(index=0;index<total_len/BLOCK_SIZE+1;index++)
				{
					//printf("\noffset = %d ", data_offset);                            
					//printf("\npdest_data = %08x ", pdest_data);
					//printf("\ncopy from %08x to %08x of size %d ", app_reg[i].page_table[page_index] + data_offset, *(addr+2)+ index * BLOCK_SIZE + USER_MEM_BASE, BLOCK_SIZE - data_offset); 
					//                            memcpy((void *)*(addr+2)+ index * BLOCK_SIZE + USER_MEM_BASE , (void *) app_page[page_index++]  + first_offset , BLOCK_SIZE);
					//                            memcpy((void *)*(addr+2)+ index * BLOCK_SIZE + USER_MEM_BASE , (void *) app_reg[i].page_table[page_index++]  + data_offset , BLOCK_SIZE - data_offset);
					//                           data_offset = 0;                           
					
					//                             memcpy((void *)*(addr+2)+ index * BLOCK_SIZE + USER_MEM_BASE , (void *) pdest_data , BLOCK_SIZE - data_offset);
					//#ifdef xxxxxxxxxxxxx
					//                             memcpy((void *) pdest_data , (void *)app_reg[i].page_table[page_index++] + data_offset, BLOCK_SIZE - data_offset);
					//    printf("\ncopy from %08x to %08x of size %d ", app_reg[i].page_table[page_index] + data_offset, pdest_data, copy_size);                             
					memcpy((void *) pdest_data , (void *)app_reg[i].page_table[page_index++] + data_offset,  copy_size);
					pdest_data += copy_size;
					remain_size -= copy_size;                            
					data_offset = 0;
					copy_size = (remain_size>BLOCK_SIZE)? BLOCK_SIZE: remain_size ;                                                         
					//#endif                             
				}
			}
#ifdef DEBUG
			printf("\nSet bss at %08x of size %08x",
				(UWORD)*(addr+4)+USER_MEM_BASE,(UWORD)*(addr+5)-*(addr+4));
#endif
			memset(*(addr+4)+USER_MEM_BASE, 0x00, *(addr+5)-*(addr+4));
			
			//                        printf("\nset end");
			
			
#ifdef DEBUG
			counta=0;
			countf=0;
#endif
			/* change pda speed  */
			CpuChangeSpeed(AppRunSpeed(app_reg[i]));
			
			//                        printf("\nRun speed = %x ",app_reg[i].run_spec); 
			
			RunApp(cmd, cmd_ptr);
			//                         Debug();
			/* restore default speed */
			ClearAppTmr();
			MsgClearAppMsg();
			CpuChangeSpeed(CPU_CLK_37M);
			
			ClrAttribute(app_reg[i].attribute, BIT_RUN);
			//printf("\nB4 clr");
			SysClearAppData(i);
			//printf("\nAfter clr");
			TlbInit();
			return TRUE;
		}
	}
	return FALSE;
}
#if 0
/*	Function	: SysSwitchUser
*	Purpose		: Switch to user mode
*  Scope		: OS
*	Input		: None
*	Output      : None
*	Comment		:
*/
void SysSwitchUser()
{
	__asm(".set noat");
	__asm(".set noreorder");
	__asm("mfc0	$8, $12");
	__asm("nop");
	__asm("or	$8, 2");
	__asm("nop");
	__asm("mtc0	$8, $12");
	__asm("nop");
	__asm(".set reorder");
	__asm(".set at");
}
#endif

/*	Function	: SysCall
*	Purpose		: Initiate syscall
*  Scope		: OS
*	Input		: Code
*	Output      : None
*	Comment		:
*/
void SysCall(UWORD code)
{
/*        if(code > SYSCALL_BASE_TOTAL)
{
if(SysCallAppID[code - SYSCALL_BASE_TOTAL] != 0)
SysLoadInterruptPageTable(SysCallAppID[code - SYSCALL_BASE_TOTAL]);
}
	*/	__asm(".set noat");
	__asm(".set noreorder");
	__asm("addu	$2, $4, $0");
	__asm("nop");
	__asm("syscall");
	__asm("nop");
	__asm("j	$31");
	__asm(".set reorder");
	__asm(".set at");
}

/*	Function	: SysCallHooked
*	Purpose		: Initiate hooked syscall
*  Scope		: OS
*	Input		: Code
*	Output      : None
*	Comment		:
*/
void SysCallHooked(UWORD code)
{
	__asm(".set noat");
	__asm(".set noreorder");
	__asm("addu	$2, $4, $0");
	__asm("nop");
	__asm("li	$4, 0x80000000");
	__asm("nop");
	__asm("add	$2, $2, $4");
	__asm("nop");
	__asm("syscall");
	__asm("nop");
	__asm("j	$31");
	__asm(".set reorder");
	__asm(".set at");
}


#if 0
/*	Function	: SysCreateProcess
*	Purpose		: Create the process
*  Scope		: Internal
*	Input		: Index in application registry
*	Output      : None
*	Comment		:
*/
void SysCreateProcess(UWORD prog_id)
{
    USHORT free_sys_asid, temp_sys_asid;
	free_sys_asid = SysSearchFreeASID();
	
	temp_sys_asid = TlbGetASID();
	
	TlbSetASID(free_sys_asid);
	sys_asid[free_sys_asid] = prog_id+1000;
	TlbDirtyEntry(free_sys_asid);
	//	printf("Prog ID %d Asid %d ", prog_id, free_sys_asid);
	//	__asm("li	$5, 4");
	__asm("li	$17, 0x80020000");
	__asm("lw	$5, 0($17)");
	SysJumpToAddr((UWORD)0x00000000);
	//	printf("Prog ID1 %d Asid1 %d ", prog_id, free_sys_asid);
	
	sys_asid[free_sys_asid] = 0;
	
	TlbSetASID(temp_sys_asid);
}
#endif
/*	Function	: SysJumpToAddr
*	Purpose		: Jump to specified address
*  Scope		: Internal
*	Input		: Address
*	Output      : None
*	Comment		:
*/
void SysJumpToAddr(UWORD addr)
{
	__asm(".set noat");
	__asm(".set noreorder");
	__asm("addu	$8, $31, $0");
	__asm("nop");
	__asm("jal $4");
	__asm("nop");
	__asm("addu	$31, $8, $0");
	__asm("nop");
	__asm(".set reorder");
	__asm(".set at");
}


/*	Function	: SysIncPC
*	Purpose		: Increment the PC by 4
*  Scope		: Internal
*	Input		: None
*	Output      : None
*	Comment		:
*/
void SysIncPC()
{
	__asm(".set noat");
	__asm(".set noreorder");
	__asm("addiu	$16, $16, 4");
	__asm("nop");
	__asm(".set reorder");
	__asm(".set at");
}


/*	Function	: SysCallGetCode
*	Purpose		: Get the code of syscall
*  Scope		: Internal
*	Input		: None
*	Output      : Code
*	Comment		:
*/
UWORD SysCallGetCode()
{
}
/* For Interrupt only */
/*	Function	: SysRunHookedIntHandler
*	Purpose		: Run the hooked interrupt handler
*  Scope		: OS
*	Input		: Interrupt number
*	Output      : None
*	Comment		:
*/
void SysRunHookedIntHandler(USHORT int_no)
{
    USHORT free_sys_asid, temp_sys_asid;
	if (int_hook_table[int_no].page_table == 0 && int_hook_table[int_no].next_ptr != 0)
		int_no = int_hook_table[int_no].next_ptr;
	if (int_hook_table[int_no].page_table != 0)
		do
		{
			free_sys_asid = SysSearchFreeASID();
			
			temp_sys_asid = TlbGetASID();
			
			TlbSetASID(free_sys_asid);
			sys_asid[free_sys_asid] = int_no;
			TlbDirtyEntry(free_sys_asid);
#ifdef DEBUG
			printf("\nInterrupt %d Asid %d ", int_no, free_sys_asid);
#endif
			SysJumpToAddr((UWORD)0x00000000);
			sys_asid[free_sys_asid] = 0;
			
			TlbSetASID(temp_sys_asid);
			
			if (int_hook_table[int_no].next_ptr == 0)
				break;
			int_no = int_hook_table[int_no].next_ptr;
		} while (1);
}


/*	Function	: SysHookIntHandler
*	Purpose		: Hook the interrupt handler
*  Scope		: OS
*	Input		: Interrupt number, starting address
*	Output      : Hook number
*	Comment		:
*/
USHORT SysHookIntHandler(USHORT int_no, UWORD *start_addr)
{
	USHORT last_no, hook_no;
	DIS_GBL_INT;
	last_no = SysSearchLastHookCell(int_no);
	hook_no = SysSearchFreeHookCell(int_no);
	int_hook_table[hook_no].page_table = start_addr;
	if (last_no != 0xFFFF)
	{
		int_hook_table[last_no].next_ptr = hook_no;
	}
	ENA_GBL_INT;
	return hook_no;
}


/*	Function	: SysUnhookIntHandler
*	Purpose		: Hook the interrupt handler
*  Scope		: OS
*	Input		: Hook number
*	Output      : None
*	Comment		:
*/
void SysUnhookIntHandler(USHORT hook_no)
{
	DIS_GBL_INT;
	int_hook_table[hook_no].page_table = 0;
	if (hook_no >= 143)
	{
		int_hook_table[SysSearchNextPtr(hook_no)].next_ptr = int_hook_table[hook_no].next_ptr;
		int_hook_table[hook_no].next_ptr = 0;
	}
	ENA_GBL_INT;
}


/*	Function	: SysSearchFreeASID
*	Purpose		: Search for free ASID
*  Scope		: Internal
*	Input		: None
*	Output      : Free ASID
*	Comment		:
*/
UWORD SysSearchFreeASID()
{
	USHORT i;
	for (i=0; i<32; i++)
	{
		if (sys_asid[i] == 0)
			break;
	}
	return i;
}

/*	Function	: SysSearchLastHookCell
*	Purpose		: Search for last hook cell
*  Scope		: Internal
*	Input		: Interrupt number
*	Output      : Hook number of last cell
*	Comment		:
*/
USHORT SysSearchLastHookCell(USHORT int_no)
{
	if (int_hook_table[int_no].page_table == 0)
		return 0xFFFF;
	while(int_hook_table[int_no].next_ptr != 0)
	{
		int_no = int_hook_table[int_no].next_ptr;
	}
	return int_no;
}


/*	Function	: SysSearchFreeHookCell
*	Purpose		: Search for free hook cell
*  Scope		: Internal
*	Input		: Interrupt number
*	Output      : Hook number of free cell
*	Comment		:
*/
USHORT SysSearchFreeHookCell(USHORT int_no)
{
	if (int_hook_table[int_no].page_table == 0)
		return int_no;
	for (int_no=143; int_no<512; int_no++)
	{
		if (int_hook_table[int_no].page_table == 0)
			break;
	}
	return int_no;
}

/*	Function	: SysSearchNextPtr
*	Purpose		: Search for next hook cell
*  Scope		: Internal
*	Input		: Hook number
*	Output      : Hook number of next cell
*	Comment		:
*/
USHORT SysSearchNextPtr(USHORT hook_no)
{
	UWORD int_no;
	for (int_no=0; int_no<512; int_no++)
	{
		if (int_hook_table[int_no].next_ptr == hook_no)
			break;
	}
	return int_no;
}


#endif   /*  PR31700 */

/*	Function	: SysGetAppEntryIndex
*	Purpose		: Get the application index in the registry
*  	Scope		: Internal
*	Input		: app_id
*	Output    	: index
*      Return		: TRUE, FALSE
*	Comment		: can use to check if the app exist in the system
*/
BOOLEAN SysGetAppEntryIndex(UWORD app_id, USHORT *index)
{
	USHORT i;
	for(i=0;i<APP_MAX;i++)
	{
		if ( app_id == app_reg[i].app_id)
		{
			if(index)
				*index = i;
			return TRUE;
		}
	}
	return FALSE;
}

/*	Function	: SysGetPageTable
*	Purpose		: Get the page table for the application
*  	Scope		: OS
*	Input		: app
*	Output    	: page_table  - a offset of 4 byte to skip the total entry
*      Return		: TRUE, FALSE
*	Comment		:
*/
BOOLEAN SysGetPageTable(UWORD app, UWORD **page_table)
{
	USHORT index;
	if (SysGetAppEntryIndex(app, &index) != TRUE)
		return FALSE;
	
	*page_table = app_reg[index].page_table;
	return TRUE;
}

/*	Function	:
SysSetPageTable
*	Purpose		: Set the page table for the application
*  	Scope		: OS
*	Input		: app
*			  page_table  - a offset of 4 byte to skip the total entry
*	Output    	: None
*      Return		: TRUE, FALSE
*	Comment		:
*/
UWORD SysSetPageTable(UWORD app, UWORD *page_table)
{
	USHORT index;
	if (SysGetAppEntryIndex(app, &index) != TRUE)
		return FALSE;
	
	app_reg[index].page_table = page_table;
	return TRUE;
}

/*	Function	: SysNextAppID
*	Purpose		: Generate a new AppID
*  	Scope		: Internal
*	Input		: None
*	Output    	: None
*      Return		: New AppID
*	Comment		:
*/
AppID SysNextAppID()
{
	USHORT max_app_id=0x00;
	USHORT i;
	
	for(i=0;i<APP_MAX;i++)
	{
		if(app_reg[i].app_name[0] != 0)
			if(app_reg[i].app_id > max_app_id)
				max_app_id = app_reg[i].app_id;
	}
	
	return max_app_id + 1;
}

/*	Function	: SysGetAppStatus
*	Purpose		: Get the system status (this function to be modified)
*  	Scope		: Internal
*	Input		: app_id
*	Output    	: res_addr
*      Return		: TRUE, FALSE
*	Comment		:
*/
BOOLEAN SysGetAppStatus(UWORD app_id, UWORD *res_addr)
{
	USHORT i;
	
	for(i=0;i<APP_MAX;i++)
	{
		if (app_reg[i].app_id == app_id)
		{
			if(res_addr)
				*res_addr = (UWORD) app_reg[i].res_addr;
			return TRUE;
		}
	}
#ifdef DEBUG
	printf("\nWarning: Cannot get status for app %d ", app_id);
#endif
	return FALSE;
}

/*	Function	: SysGetActiveAppID
*	Purpose		: Get the active application
*  	Scope		: OS
*	Input		: None
*	Output    	: None
*      Return		: 0 - application not found
*                        otherwise  - Active AppID
*	Comment		:
*/
AppID SysGetActiveAppID()
{
	USHORT i;
	
	
#ifdef PC_SIM
	return 1;
#else
	for(i=0;i<APP_MAX;i++)
	{
		if (ChkAttribute(app_reg[i].attribute, BIT_RUN))
		{
			return app_reg[i].app_id;
		}
	}
    return 1;
#endif
}

/*  Function    : SysGetRealActiveAppID
*	Purpose		: Get the active application
*  	Scope		: OS
*	Input		: None
*	Output    	: None
*      Return		: 0 - application not found
*                        otherwise  - Active AppID
*	Comment		:
*/
AppID SysGetRealActiveAppID()
{
	USHORT i;
	
	
#ifdef PC_SIM
	return 1;
#else
	for(i=0;i<APP_MAX;i++)
	{
		if (ChkAttribute(app_reg[i].attribute, BIT_RUN))
		{
			return app_reg[i].app_id;
		}
	}
    return 0;
#endif
}


/*	Function	: SysGetAppID
*	Purpose		: Query AppID by application name
*  	Scope		: All
*	Input		: app_name	application name
*	Output    	: app_id        application ID
*      Return		: TRUE, FALSE
*	Comment		:
*/
BOOLEAN SysGetAppID(BYTE *app_name, AppID *app_id)
{
	UWORD i;
	
	
	for(i=0;i<APP_MAX;i++)
	{
		if (strcmp((const char*)app_name, (const char*)app_reg[i].app_name) == 0)
		{
			*app_id = app_reg[i].app_id;
			return TRUE;
		}
	}
	return FALSE;
}

void SysDefaultSyscall()
{
#ifdef DEBUG
	printf("\nSyscall is unhooked");
#endif
}

void SysHookSyscall(AppID app, UWORD sc_no, UWORD *address)
{
/*	SysCallFptr[sc_no] = (UWORD) address;
if(sc_no > SYSCALL_BASE_TOTAL)
SysCallAppID[sc_no- SYSCALL_BASE_TOTAL] = app;
	*/
	SysCallHookedFptr[sc_no & 0x7fffffff].addr = (UWORD) address;
	SysCallHookedFptr[sc_no & 0x7fffffff].appid = app;
}

void SysUnhookSyscall(UWORD sc_no)
{
/*	SysCallFptr[sc_no] = (UWORD) SysDefaultSyscall;
if(sc_no > SYSCALL_BASE_TOTAL)
SysCallAppID[sc_no - SYSCALL_BASE_TOTAL] = 0;
	*/
	SysCallHookedFptr[sc_no & 0x7fffffff].addr = (UWORD) SysDefaultSyscall;
	SysCallHookedFptr[sc_no & 0x7fffffff].appid = 0;
}


void SysUnHookSyscallByAppID(AppID appid)
{
	UWORD i;
	
	for(i=0;i<TOTAL_INSTALLABLE_SYSCALL;i++)
	{
		if( SysCallHookedFptr[i].appid == appid)
			SysUnhookSyscall(i + (UWORD) 0x80000000);
	}
}

/*	Function	: SysGetAppAttribute
*	Purpose		: Query app. attribute
*  	Scope		: All
*	Input		: app_id
*                        query_bit
*	Output    	: None
*      Return		: TRUE	- the attribute is set
*                        FALSE - the attribute not set
*	Comment		:
*/
BOOLEAN SysGetAppAttribute(AppID app_id, UBYTE query_bit, UWORD *reserved)
{
	USHORT index;
	
	if(!SysGetAppEntryIndex(app_id, &index))
		return FALSE;
	{
		return (BOOLEAN) ChkAttribute(app_reg[index].attribute, query_bit);
	}
}



/*      Function        : SysBuildAllIntTable
*      Purpose         : Rebuild the int page table if system has been reset
*      Scope           : OS
*      Input           : None
*      Output          : None
*      Return          : None
*	Comment		:
*/
void SysBuildAllIntPageTable()
{
	USHORT index;
	UWORD i;
	for(i=0;i<HOOKABLE_ADDR;i++)
		if(int_lookup_table[i].appid)
			if(SysGetAppEntryIndex(int_lookup_table[i].appid, &index) == TRUE)
			{
				SysBuildPageTable(index);
				int_lookup_table[i].page_table = app_reg[index].page_table;
			}
}

/*      Function        : SysBuildPageTable
*      Purpose         : Rebuild the page table if system has been reset
*      Scope           : OS
*      Input           : index : app index in app_reg
*      Output          : None
*      Return          : TRUE  Success
*                        FALSE Fail
*	Comment		:
*/
BOOLEAN SysBuildPageTable(USHORT index)
{
	UWORD *page_table, j, i;
	
	if(app_reg[index].page_table)
		return TRUE;
	
#ifdef DEBUG
	printf("\nRebuild Page table, page_need = %d ", app_reg[index].page_need);
#endif
	
	if((page_table = (UWORD*) pmalloc(sizeof(UWORD*) * (app_reg[index].page_need + 1)))==NULL)
		return FALSE;
	page_table[0] = app_reg[index].page_need;
	if(ChkAttribute(app_reg[index].attribute, BIT_FLASH_PRG))
	{  /* flash prg  */
		for(j=0;j<app_reg[index].page_need;j++)
		{
			/* fill the physical address for prog, start_block = phy addr of the prog*/
			page_table[j+1] = app_reg[index].start_block + BLOCK_SIZE * j;
		}
	}
	else
	{
		USHORT next_block = app_reg[index].start_block;
		UWORD j = 1;
		for(i=0;i<app_reg[index].page_need;i++)
		{
			page_table[j++] = SBlockAddr((UWORD)next_block);
			if(MemoryNextBlock(&mat_info[0], next_block, &next_block) != TRUE)
				break;
		}
		
	}
	app_reg[index].page_table = page_table + 1;
	
	UpdateMATCRC((&mat_info[0]));
	return TRUE;
}

AppID SysGetPrevAppID()
{
	return prev_appid;
}

/*      Function        : SysCheckModemExist
*      Purpose         : Check if modem is installed
*      Scope           : All
*	Input		: None
*      Output          : None
*      Return          : TRUE, FALSE
*	Comment		:
*/
BOOLEAN SysCheckModemExist()
{
    AppID app;
    return SysGetAppID(MODEMDRV, &app);    
}


/*	Function	: SysOSVersionNo
*	Purpose		: Get OS version
*  	Scope		: All
*	Input		: None
*	Output    	: ver_no  - OS version
*      Return		: None
*	Comment		:
*/
void SysGetOSVersionNo(BYTE *ver_no)
{
	BYTE *vn;
	vn = (BYTE *)VER_NO_ADDR;
	strcpy(ver_no, vn);
}


/*	Function	: SysGetInstallAppHandle
*	Purpose		: Get installed app inf pointer
*  	Scope		: OS
*	Input		: None
*	Output    	: address of install_app_inf
*      Return		: None
*	Comment		:
*/
void SysGetInstallAppHandle(InstallAppInf **handle)
{
	*handle = install_app_inf;
}


/*	Function	: SysGetRegistryData
*	Purpose		: Get registry data
*  	Scope		: All
*	Input		: index  - application index in the registry
*	Output    	: reg_data - data in the registry
*      Return		: TRUE  - Success
*                        FALSE - Invalid index
*	Comment		:
*/
BOOLEAN SysGetRegistryData(USHORT index, REGISTRY *reg_data)
{
	if(index >= APP_MAX)
		return FALSE;
	*reg_data = app_reg[index];
	return TRUE;
}


/*	Function	: SysGetInstallAppIconHandle
*	Purpose		: Get installed app icon pointer
*  	Scope		: OS
*	Input		: None
*	Output    	: address of app_icon_bmp
*      Return		: None
*	Comment		:
*/
void SysGetInstallAppIconHandle(BYTE **handle)
{
	*handle = install_icon_res_data;
}


BOOLEAN ShellHandleEvent(EvtType *Event)
{
	AppID 		alm_app, app_id;
    void 		*alm_prev_appid;
	//    WORD 		prev_launch_cmd;
	//    void 		*prev_launch_cmd_ptr;
    
    BOOLEAN 	bat_chk_flag, app_launch_flag, app_launch_received;
    UWORD 		bat_level;
    BYTE 		cal_status;
    BOOLEAN		cant_check_battery = FALSE;
	
#ifdef DEBUG
    countqf=0;
    countqa=0;
#endif
	switch (Event->eventType)
	{
	case EVT_APP_LAUNCH:		
#ifdef DEBUG_HENRY
		printf("\n LAUNCH APPLICATION");
#endif
		SystemApplicationInit();        
		
		
		if(AlarmCallApp() || !AlarmHitCount() )
		{           	         	
			prev_appid = Event->eventID;                	    
			SysRunApp(Event->eventID, Event->para1, Event->evtPBP);
			AlarmResetCallApp();
		}
		else
		{
			if(SysGetAppID(ALARMGR, &alm_app) == TRUE)
			{
				prev_appid = Event->eventID;                	    
				SysRunApp(alm_app, LAUNCH_CMD_NORMAL_LAUNCH, NULL);
			}                	
			else
				SysRunApp(Event->eventID, Event->para1, Event->evtPBP);
		}
		
#ifdef DEBUG
		count_malloc();
		printf("\nQAlloc total = %d", countqa);
		printf("\nQFree  total = %d", countqf);
#endif
		return TRUE;
	case EVT_POWER_DOWN:
#ifdef DEBUG
		printf("\nSave Active AppID %d", prev_appid);
#endif
		
		while (SndAction);
		LcdClr();
		TmrInit();
		
		do
		{	
			do
			{	
				do
				{
					do
					{
						EvtQueueCreate(&evtQueue);
						MsgQueueCreate(&msgQueue);				
#ifdef DEBUG_HENRY
						printf("\n Enter HwSystemPowerOff");
#endif
						HwSystemPowerOff();
#ifdef DEBUG_HENRY
						printf("\n EXIT HwSystemPowerOff");
#endif
						if (MemoryCheck() == FALSE)
						{
#ifdef DEBUG_HENRY
							printf("\n Memory Check Error");
#endif
							DIS_GBL_INT;                //991010
							__asm("li	$8, 0x9fc10000");
							__asm("j	$8");
						}
					}
					while (BatDoorOpen() == 1 || CheckBatteryEmpty() == 1);
				}while(!ShellHandleEventWhileLoop() || BatDoorOpen() == 1);									
				
				BatteryWarningInit();
				OnPdaInit();
#ifdef DEBUG
				printf("\nPassword enable1 %d", GPassCheck);
#endif
				if (GPassCheck == TRUE)
				{
#ifdef DEBUG
					printf("\nPassword enable");
#endif
					SysGetAppID(SYPASSWORD, &app_id);
					SystemApplicationInit();
					SysRunApp(app_id, LAUNCH_CMD_NORMAL_LAUNCH, NULL);
				}				
			}while (BatDoorOpen() == 1 || CheckBatteryEmpty() == 1);
			
#ifdef DEBUG
			printf("\nLaunch Saved AppID %d", prev_appid);
#endif
  		        AlarmOnHit();
				if (!AlarmHitCount())
				{
#ifdef DEBUG_HENRY            	
					printf("\n POWER_ON -1- LAUNCH APP = %ld %ld", prev_appid, prev_launch_cmd);
#endif
					SySetupGetCalPenMode(&cal_status);        
					if (cal_status == 1)
					{
#ifdef DEBUG_HENRY            		
						printf("\n cal_status in Kernel = %ld", cal_status);
#endif
						SysGetAppID(SYSETUP, &app_id);	
						EvtAppendEvt(EVT_APP_LAUNCH, app_id, LAUNCH_CMD_CAL_PEN, 0, NULL);
					}	
					else
						EvtAppendEvt(EVT_APP_LAUNCH, prev_appid, prev_launch_cmd, 0, prev_launch_cmd_ptr);
				}                
				else
				{
#ifdef DEBUG
					printf("\nThere is alarm Hit when Powr on");
#endif
					if(SysGetAppID(ALARMGR, &alm_app) == TRUE)
                    	   EvtAppendEvt(EVT_APP_LAUNCH, alm_app, LAUNCH_CMD_NORMAL_LAUNCH, 0, NULL);
					else
					{
#ifdef DEBUG_HENRY                	
						printf("\n POWER_ON -2- LAUNCH APP = %ld %ld", prev_appid, prev_launch_cmd);	
#endif             	   
            	           EvtAppendEvt(EVT_APP_LAUNCH, prev_appid, prev_launch_cmd, 0, prev_launch_cmd_ptr);
					}                             	         	
				}
		}while (BatDoorOpen() == 1 || CheckBatteryEmpty() == 1);
		return TRUE;
	default:
		return FALSE;
	}
	return FALSE;
}

/********************************************************
* Function:    ShellHandleEventWhileLoop
* Purpose:     to gather enough information to 
* Scope:		application/internal
* Input:       None
* Output:		None
* Return:      None
* Comment: 	None
*********************************************************/
BOOLEAN ShellHandleEventWhileLoop()
{
	AppID 		app_id;
    BOOLEAN 	bat_chk_flag, app_launch_flag, app_launch_received;
	EvtType 	event;
    UWORD 		bat_level;
    BYTE 		cal_status;
    BOOLEAN		cant_check_battery = FALSE;
    BOOLEAN		while_loop_finished = FALSE, system_battery_empty = FALSE;
    
#ifdef DEBUG_HENRY
	printf("\n");
	printf("\n ===================== Enter ShellHandleEventWhileLoop ==============");
#endif	
	
	
	if (CheckBatteryEmpty() == 1)
		return FALSE;
	
	while (!system_battery_empty)
	{
		bat_chk_flag 		= FALSE;
        app_launch_flag 	= FALSE;
        prev_launch_cmd 	= LAUNCH_CMD_NORMAL_LAUNCH;
        prev_launch_cmd_ptr = NULL;
        app_launch_received = FALSE;
        cant_check_battery 	= FALSE;
		
		if (BatChkMainLevel() == 1)
		{
#ifdef DEBUG_HENRY
			printf("\n Kernel - Can't Check Battery");
#endif
			cant_check_battery = TRUE;
			EvtAppendEvt(0, 0, 0, 0, NULL);						
		}						
		
		while (!system_battery_empty)
		{
			if (CheckBatteryEmpty() == 1)
			{
				system_battery_empty = TRUE;		
				while_loop_finished = FALSE;
				break;
			}			
			
			EvtGetEvent(&event);
			
#ifdef DEBUG_HENRY                    	
			printf("\n While 1 Event = %ld %ld %ld %ld", event.eventType, event.eventID, event.para1, event.para2);                    	
#endif
			if (app_launch_received && (event.eventType != POWER_EVENT || event.eventID != BAT_MAIN_LEVEL))
			{
#ifdef DEBUG_HENRY							
				printf("\n EVENT_FILTERED");
#endif
				if (cant_check_battery)
				{
					bat_level = BatChkMainLevelBakup();
					bat_chk_flag = TRUE;
					break;
				}
				continue;
			}							
			
			if (!SysTranslateCustomiseButtonsWithoutPowerOff(&event))
			{
#ifdef DEBUG_HENRY                        	
				printf("\n DIDN'T CUSTOMISE");
#endif
				app_launch_flag = TRUE;
				
				if (cant_check_battery)
				{
					bat_level = BatChkMainLevelBakup();
					bat_chk_flag = TRUE;
					break;
				}
			} 	                       	
			
			if (event.eventType == POWER_EVENT && event.eventID == BAT_MAIN_EMPTY)						
			{
#ifdef DEBUG_HENRY                        	
				printf("\n While 1 BAT_EMPTY");
#endif
				system_battery_empty = TRUE;
				break;
			}			
			else if (event.eventType == POWER_EVENT && event.eventID == BAT_MAIN_LEVEL)
			{       		
				bat_level = event.para2;
#ifdef DEBUG_HENRY                        	
				printf("\n While 1 BAT_LEVEL %ld", bat_level);
#endif
				bat_chk_flag = TRUE;
				if (bat_level == 0)
					system_battery_empty = TRUE;
				break;
			}
			else if (event.eventType == POWER_EVENT && event.eventID == BAT_MAIN_LOW)
			{
				bat_level = 2;
#ifdef DEBUG_HENRY                        	
				printf("\n While 1 BAT_MAIN_LOW %ld", bat_level);
#endif
				bat_chk_flag = TRUE;
				break;
			}                       
			
			if (event.eventType == EVT_APP_LAUNCH)
			{
#ifdef DEBUG_HENRY                        	
				printf("\n While 1 EVT_APP_LAUNCH");
#endif
				prev_appid = event.eventID;
				if (prev_appid == 0)
					prev_appid = 1;
				
				prev_launch_cmd = event.para1;
				prev_launch_cmd_ptr = event.evtPBP;
				app_launch_flag = TRUE;
				app_launch_received = TRUE;
				continue;
			}
		}
		
		if (system_battery_empty)
		{
			while_loop_finished = FALSE;
			break;
		}			
		
#ifdef DEBUG_HENRY        			
        printf("\n ---->Launch --------------> app_launch_flag = %ld", app_launch_flag);
#endif
       	if (!app_launch_flag)
       	{
			while (!system_battery_empty)
			{
				if (CheckBatteryEmpty() == 1)
				{
					system_battery_empty = TRUE;		
					break;
				}	            	
				
				EvtGetEvent(&event);            	
				
				if (event.eventType == POWER_EVENT && event.eventID == BAT_MAIN_EMPTY)						
				{
					system_battery_empty = TRUE;
					break;
				}
				else if (event.eventType == POWER_EVENT && event.eventID == BAT_MAIN_LEVEL)
				{
					bat_level = event.para2;
#ifdef DEBUG_HENRY                        	
					printf("\n While 1 BAT_LEVEL %ld", bat_level);
#endif
					bat_chk_flag = TRUE;
					if (bat_level == 0)
					{
						system_battery_empty = TRUE; 
						break;
					}            			
					continue;
				}
				else if (event.eventType == POWER_EVENT && event.eventID == BAT_MAIN_LOW)
				{
					bat_level = 2;
#ifdef DEBUG_HENRY                        	
					printf("\n While 1 BAT_MAIN_LOW %ld", bat_level);
#endif
					bat_chk_flag = TRUE;
					continue;
				}                       
				
				
#ifdef DEBUG_HENRY                        	
               	printf("\n While 2 Event = %ld %ld %ld %ld", event.eventType, event.eventID, event.para1, event.para2);                    	
#endif
                if (event.eventType == EVT_APP_LAUNCH)
                {
					prev_appid = event.eventID;
					if (prev_appid == 0)
						prev_appid = 1;
					
					prev_launch_cmd = event.para1;
					prev_launch_cmd_ptr = event.evtPBP;
					break;
                }
			}
        }
		
		if (bat_level == 0 || system_battery_empty)
		{
			while_loop_finished = FALSE;	
			break;
		}			
		else if (bat_level <= 2)
		{
            if (!Lowbatscr())
			{
				while_loop_finished = FALSE;
				system_battery_empty = TRUE;
			}			
			else 
			{
				while_loop_finished = TRUE;
				system_battery_empty = FALSE;
			}		
			break;
		}
		else
		{
            while_loop_finished = TRUE;
            break;
		}
	}
	
#ifdef DEBUG_HENRY
    printf("\n while_loop_finsihed status = %ld", while_loop_finished);
	printf("\n ================= Exit ShellHandleEventWhileLoop ==============");
#endif
	return while_loop_finished;
}
