예제 #1
0
파일: hid.c 프로젝트: Bumparoo/ctrulib
void hidExit()
{
	if(!hidInitialised) return;

	// Unmap HID sharedmem and close handles.
	u8 val=0;
	int i; for(i=0; i<5; i++)svcCloseHandle(hidEvents[i]);
	svcUnmapMemoryBlock(hidMemHandle, (u32)hidSharedMem);
	svcCloseHandle(hidMemHandle);
	svcCloseHandle(hidHandle);

	APT_CheckNew3DS(NULL, &val);

	if(val)
	{
		irrstExit();
	}

	if(hidSharedMem != NULL)
	{
		mappableFree((void*) hidSharedMem);
		hidSharedMem = NULL;
	}
	
	hidInitialised = false;
}
예제 #2
0
/* fills exploit_data structure with information that is specific
   to 3DS model and firmware version
   returns: 0 on failure, 1 on success */
s32 get_exploit_data (struct exploit_data *data) {
	u32 fversion = 0;
	u8  isN3DS = 0;
	s32 i;
	s32 result = 0;
	u32 sysmodel = SYS_MODEL_NONE;

	if(!data)
		return result;

	fversion = osGetFirmVersion();
	APT_CheckNew3DS(&isN3DS);
	sysmodel = isN3DS ? SYS_MODEL_NEW_3DS : SYS_MODEL_OLD_3DS;

	/* copy platform and firmware dependent data */
	for(i=0; i < sizeof(supported_systems) / sizeof(supported_systems[0]); i++) {
		if (supported_systems[i].firm_version == fversion &&
			supported_systems[i].sys_model & sysmodel) {
				memcpy(data, &supported_systems[i], sizeof(struct exploit_data));
				result = 1;
				break;
		}
	}
	return result;
}
예제 #3
0
파일: hid.c 프로젝트: Findus79/ctrulib
Result hidInit(void)
{
	u8 val=0;
	Result ret=0;

	if (AtomicPostIncrement(&hidRefCount)) return 0;

	// Request service.
	ret = srvGetServiceHandle(&hidHandle, "hid:USER");
	if (R_FAILED(ret)) ret = srvGetServiceHandle(&hidHandle, "hid:SPVR");
	if (R_FAILED(ret)) goto cleanup0;

	// Get sharedmem handle.
	if(R_FAILED(ret=HIDUSER_GetHandles(&hidMemHandle, &hidEvents[HIDEVENT_PAD0], &hidEvents[HIDEVENT_PAD1], &hidEvents[HIDEVENT_Accel], &hidEvents[HIDEVENT_Gyro], &hidEvents[HIDEVENT_DebugPad]))) goto cleanup1;

	// Map HID shared memory.
	hidSharedMem=(vu32*)mappableAlloc(0x2b0);
	if(!hidSharedMem)
	{
		ret = -1;
		goto cleanup1;
	}

	if(R_FAILED(ret=svcMapMemoryBlock(hidMemHandle, (u32)hidSharedMem, MEMPERM_READ, 0x10000000)))goto cleanup2;

	APT_CheckNew3DS(&val);

	if(val)
	{
		ret = irrstInit();
	}

	// Reset internal state.
	kOld = kHeld = kDown = kUp = 0;
	return ret;

cleanup2:
	svcCloseHandle(hidMemHandle);
	if(hidSharedMem != NULL)
	{
		mappableFree((void*) hidSharedMem);
		hidSharedMem = NULL;
	}
cleanup1:
	svcCloseHandle(hidHandle);
cleanup0:
	AtomicDecrement(&hidRefCount);
	return ret;
}
예제 #4
0
int main (int argc, char **argv)
{
	float		time, oldtime;

	APT_CheckNew3DS(&isN3DS);
	if(isN3DS)
		osSetSpeedupEnable(true);

	gfxInit(GSP_RGB565_OES,GSP_RGB565_OES,false);
	gfxSetDoubleBuffering(GFX_TOP, false);
	gfxSetDoubleBuffering(GFX_BOTTOM, false);
	gfxSet3D(true);
	consoleInit(GFX_BOTTOM, NULL);

	#ifdef _3DS_CIA
		if(chdir("sdmc:/3ds/ctrQuake") != 0)
			Sys_Error("Could not find folder: sdmc:/3ds/ctrQuake");
	#endif

	static quakeparms_t    parms;

	parms.memsize = 24*1024*1024;
	parms.membase = malloc (parms.memsize);
	parms.basedir = ".";

	COM_InitArgv (argc, argv);

	parms.argc = com_argc;
	parms.argv = com_argv;
	Host_Init (&parms);
	
	Sys_Init();

	oldtime = Sys_FloatTime() -0.1;
	while (aptMainLoop())
	{
		time = Sys_FloatTime();
		separation_distance = osGet3DSliderState();
		Host_Frame (time - oldtime);
		oldtime = time;
	}
	gfxExit();
	return 0;
}
예제 #5
0
void patch_srv(void) {
    APT_CheckNew3DS(&is_n3ds);

    u32 pid1;
    svcGetProcessId(&pid1, 0xFFFF8001);
    // Set the current process id (PID) to 0
    svcBackdoor(&patch_pid);

    u32 pid2;
    svcGetProcessId(&pid2, 0xFFFF8001);
    // Re-initialize srv connection. It will consider this the process with id 0
    // so we will have access to any service
    srvExit();
    srvInit();

    // Once we tricked srv we can restore the real PID
    svcBackdoor(&restore_pid);

    u32 pid3;
    svcGetProcessId(&pid3, 0xFFFF8001);
    printf("%lu=%lu=%lu %lu=0 %s %s\n", pid1, pid_backup, pid3, pid2, patch_result, unpatch_result);
}
예제 #6
0
파일: hid.c 프로젝트: Findus79/ctrulib
void hidExit(void)
{
	if (AtomicDecrement(&hidRefCount)) return;

	// Unmap HID sharedmem and close handles.
	u8 val=0;
	int i; for(i=0; i<5; i++)svcCloseHandle(hidEvents[i]);
	svcUnmapMemoryBlock(hidMemHandle, (u32)hidSharedMem);
	svcCloseHandle(hidMemHandle);
	svcCloseHandle(hidHandle);

	APT_CheckNew3DS(&val);

	if(val)
	{
		irrstExit();
	}

	if(hidSharedMem != NULL)
	{
		mappableFree((void*) hidSharedMem);
		hidSharedMem = NULL;
	}
}
예제 #7
0
void saveConstants() {
    u32 kversion = *(vu32*)0x1FF80000; // KERNEL_VERSION register

    u8 is_n3ds = 0;
    APT_CheckNew3DS(NULL, &is_n3ds);

    if(kversion < 0x022C0600) {
        kproc_size = 0x260;
        kproc_num  = 0x2C; // TODO: Verify
        kproc_codeset_offset = 0xA8;
        kproc_pid_offset     = 0xAC;
    } else if(!is_n3ds) {
        kproc_size = 0x268;
        kproc_num  = 0x2C; // TODO: Verify
        kproc_codeset_offset = 0xB0;
        kproc_pid_offset     = 0xB4;
    } else {
        kproc_size = 0x270;
        kproc_num  = 0x2F; // TODO: Verify
        kproc_codeset_offset = 0xB8;
        kproc_pid_offset     = 0xBC;
    }
    kernelBackdoor(scanKProcList);
}
예제 #8
0
int main(int argc, char* argv[]) {
	gfxInitDefault();
	//Initialize console on top screen. Using NULL as the second argument tells the console library to use the internal console structure as current one
	consoleInit(GFX_TOP, &topScreen);
	consoleInit(GFX_BOTTOM,&bottomScreen);
	consoleSelect(&topScreen);
	APT_CheckNew3DS(&consoletype);
	printf("Console type:%s\n",consoletype?"New3DS. Good job!":"Old3DS. This may be a bit slow.");
	// Main loop
	while (aptMainLoop())
	{
		printf("Welcome to the adventure. Press A to continue, or any other key to exit.\n");
		hidScanInput();

		//hidKeysDown returns information about which buttons have been just pressed (and they weren't in the previous frame)
		u32 kDown = hidKeysDown();
		//hidKeysHeld returns information about which buttons have are held down in this frame
		u32 kHeld = hidKeysHeld();
		//hidKeysUp returns information about which buttons have been just released
		u32 kUp = hidKeysUp();
		while (!kDown) {hidScanInput(); u32 kDown = hidKeysDown(); u32 kHeld = hidKeysHeld(); u32 kUp = hidKeysUp(); if (kDown || kHeld || kUp) printf("Down:%d Held:%d Up:%d", kDown, kHeld, kUp);}
		if (kDown & !KEY_A) break;
		else if (kDown) {
			notknow:
			rendscreen("\n\nYou are walking in a forest. You come to a part you don't know. You can go three ways. Do you go left, right, or straight? (Use the D-Pad to select) ");
			hidScanInput();

			//hidKeysDown returns information about which buttons have been just pressed (and they weren't in the previous frame)
			kDown = hidKeysDown();
			//hidKeysHeld returns information about which buttons have are held down in this frame
			kHeld = hidKeysHeld();
			//hidKeysUp returns information about which buttons have been just released
			kUp = hidKeysUp();
			while (!kDown) {hidScanInput(); u32 kDown = hidKeysDown(); u32 kHeld = hidKeysHeld(); u32 kUp = hidKeysUp();}
			if (kDown & KEY_LEFT) {
				if (ldone) {
					rendscreen("You've already gone here! (A)");
					isButtonPressed('a');
					move="0";
					goto notknow;
				}
				else {
					rendscreen("You found a chest! Inside it was 5 bars of gold. (A to continue)");
					if (input()) goto exit;
					gold +=5;
					rendscreen("It's at a dead end, however. You walk back.");
					if (input()) goto exit;
					move="0";
					ldone=true;
					goto notknow;
				}
			}
			else if (kDown & KEY_RIGHT) {
				if (rdone) {
					rendscreen("You've already gone here!");
					if (input()) goto exit;
					move="0";
				}
				else {
					rendscreen("You walk into a trap and lose a life.(A to continue)");
					if (input()) goto exit;
					lives+=-1;
					rendscreen("You walk back.");
					if (input()) goto exit;
					move="0";
					rdone=true;
				}
			}
			else if (kDown & KEY_UP) continue;
			else if (kDown & KEY_START) goto exit;
			else goto notknow;
			rendscreen("You walk forward for a while.(A to continue)");
			if (input()) goto exit;
			rendscreen("The ground begins to shake...(A to continue)");
			if (input()) goto exit;
			cls();
			print("Louder...");
			usleep(1000);
			rendscreen("You come up to a monster!");
			usleep(1000);
			rendscreen("'I will eat you!'");
			usleep(1000);
			rendscreen("How to fight: Press A to kick and B to punch.");
			if (input()) goto exit;
			rendscreen("When it's your enemy's turn, hope for the best!");
			if (input()) goto exit;
			rendscreen("Press A to start.");
			if (input()) goto exit;
			
			while (enemyh>0) {
				rendscreenf();
				char fmove='0';
				printf("Kick or punch? \n");
				while (fmove != 'K' && fmove != 'P' && fmove != 'a') {
					if (isButtonPressed('a')) fmove = 'K';
					else if (isButtonPressed('b')) fmove = 'P';
					else if (isButtonPressed('e')) {
						if (isButtonPressed('l')) fmove = 'a';
					}
					else if (isButtonPressed('t')) goto exit;
				}
				if (fmove=='K') {
					sub=floor(random()*10)+5;
					enemyh=enemyh-sub*10;
					printf("Damage dealt: %i\n",sub*10);
					if (input()) goto exit;
				}
				else if (fmove=='a') {
					enemyh=0;
				}
				else {
					sub=floor(random()*10);
					enemyh+=-sub*18;
					printf("Damage dealt: %i\n", sub*18);
					if (input()) goto exit;
				}
				rendscreenf();
				usleep(200);
				if (enemyh>0) {
					health+=-floor(random()*100);
					health+=-60;
					printf("Monster attacks! Damage dealt: %i\n", sub+60);
					if (input()) goto exit;
				}
			}
			rendscreen("You won the battle!");
			if (input()) goto exit;
			rendscreen("The monster had 20 gold and you gained two lives from defeating him!");
			gold+=20;
			lives+=2;
			if (input()) goto exit;
			rendscreen("You continue along the path.");
			if (input()) goto exit;
			char berries = 'x';
			// Entrypoint 2																											===============
			rendscreen("You find some berries.  Do you eat them? (A/B) ");
			while (berries != 'y' && berries != 'n') {
				if (isButtonPressed('a')) berries = 'y';
				else if (isButtonPressed('b')) berries = 'n';
				else if (isButtonPressed('t')) goto exit;
			}
			if (berries=='y') {
				rendscreen("Under the leaves, you found a glove!  It grants +50 health in all battles!");
				ebhealth+=50;
				special.push_back("Glove");
				if (input()) goto exit;
				rendscreen("After eating some berries, you continue walking.");
			}
			else {
				rendscreen("You continue walking.");
			}
			if (input()) goto exit;
			char river='0';
			rendscreen("After walking for quite some time, you come to a river.  There's a bear right behind you.  Do you try to cross the river? (A/B) ");
			while (river!='y' && river!='n') {
				if (isButtonPressed('a')) river = 'y';
				else if (isButtonPressed('b')) river = 'n';
				else if (isButtonPressed('t')) goto exit;
			}
			if (river=='y') {
				rendscreen("You manage to cross the river, but you get sick and lose a life.");
				lives+=-1;
			}
			else {
				rendscreen("You stay and fight the bear!");
				if (input()) goto exit;
				health=1000+ebhealth;
				enemyh=400;
				while (enemyh>0) {
					rendscreenf();
					char fmove='0';
					printf("Kick or punch? \n");
					while (fmove!='k' && fmove!='p' && fmove!='a') {
						if (isButtonPressed('a')) fmove = 'k';
						else if (isButtonPressed('b')) fmove = 'p';
						else if (isButtonPressed('e')) {if (isButtonPressed('l')) fmove = 'a';}
						else if (kDown & KEY_START) goto exit;
					}
					if (fmove=='k') {
						sub=floor(random()*10)+6;
						enemyh=enemyh-sub*10;
						printf("Damage dealt: %i\n", sub*10);
						if (input()) goto exit;
					}
					else if (fmove=='a') enemyh=0;
					else {
						sub=floor(random()*10);
						enemyh+=-sub*1.85*10;
						printf("Damage dealt: %d\n", sub*1.85*10);
						if (input()) goto exit;
					}
					rendscreenf();
					usleep(200);
					if (enemyh>0) {
						sub=floor(random()*10)*1.4*10;
						health+=-sub;
						health+=-4*10;
						printf("Bear attacks! Damage dealt: %d\n", sub+4*10);
						if (input()) goto exit;
					}
					if (health<0) {
						lives+=-1;
						health=1000+ebhealth;
					}
				}
				rendscreen("You won the battle!");
				if (input()) goto exit;
				rendscreen("You keep the fur coat from the bear.  It gives you +200 health in all battles!");
				if (input()) goto exit;
				ebhealth+=200;
				special.push_back("Fur Coat");
				rendscreen("You decide to put down a log and cross the river.");
			}
			if (input()) goto exit;
			printf("Unfortunately, this is an *alpha* release for debugging only. This is the end of the program.\n\n\n");
			usleep(2000);
			printf("Exiting...\n");
			usleep(500);
			goto exit;
		}
	}
exit:
	// Exit services
	gfxExit();
	return 0;
}
예제 #9
0
void Player::Init(int argc, char *argv[]) {
	static bool init = false;
	frames = 0;

	if (init) return;

	// Display a nice version string
	std::stringstream header;
	std::string addtl_ver(PLAYER_ADDTL);
	header << "EasyRPG Player " << PLAYER_VERSION;
	if (!addtl_ver.empty())
		header << " " << addtl_ver;
	header << " started";
	Output::Debug(header.str().c_str());

	unsigned int header_width = header.str().length();
	header.str("");
	header << std::setfill('=') << std::setw(header_width) << "=";
	Output::Debug(header.str().c_str());

#ifdef GEKKO
	// Init libfat (Mount SD/USB)
	if (!fatInitDefault()) {
		Output::Error("Couldn't mount any storage medium!");
	}
#elif defined(_3DS)
	// Starting debug console
	gfxInitDefault();
	consoleInit(GFX_BOTTOM, NULL);

	APT_SetAppCpuTimeLimit(30);
	if (osGetKernelVersion() <  SYSTEM_VERSION(2, 48, 3)) khaxInit(); // Executing libkhax just to be sure...
	consoleClear();

	// Check if we already have access to csnd:SND, if not, we will perform a kernel privilege escalation
	Handle csndHandle = 0;
	use_dsp = false;
#ifndef FORCE_DSP
	srvGetServiceHandleDirect(&csndHandle, "csnd:SND");
	if (csndHandle) {
		Output::Debug("csnd:SND has been selected as audio service.");
		svcCloseHandle(csndHandle);
	} else {
		Output::Debug("csnd:SND is unavailable...");
#endif
		srvGetServiceHandleDirect(&csndHandle, "dsp::DSP");
		if (csndHandle) {
			Output::Debug("dsp::DSP has been selected as audio service.");
			use_dsp = true;
			svcCloseHandle(csndHandle);
		} else {
			Output::Error("dsp::DSP is unavailable. Please dump a DSP firmware to use EasyRPG Player. If the problem persists, please report us the issue.");
		}
#ifndef FORCE_DSP
	}
#endif

	fsInit();
	sdmcInit();
#ifndef CITRA3DS_COMPATIBLE
	romfsInit();
#endif

	hidInit();

	// Enable 804 Mhz mode if on N3DS
	bool isN3DS;
	APT_CheckNew3DS(&isN3DS);
	if (isN3DS) {
		osSetSpeedupEnable(true);
	}
#endif

#if (defined(_WIN32) && defined(NDEBUG) && defined(WINVER) && WINVER >= 0x0600)
	InitMiniDumpWriter();
#endif

	srand(time(NULL));

	ParseCommandLine(argc, argv);

#ifdef EMSCRIPTEN
	Output::IgnorePause(true);

	// Create initial directory structure in our private area
	// Retrieve save directory from persistent storage
	EM_ASM(

		FS.mkdir("easyrpg");
		FS.chdir("easyrpg");

		var dirs = ['Backdrop', 'Battle', 'Battle2', 'BattleCharSet', 'BattleWeapon', 'CharSet', 'ChipSet', 'FaceSet', 'Frame', 'GameOver', 'Monster', 'Movie', 'Music', 'Panorama', 'Picture', 'Sound', 'System', 'System2', 'Title', 'Save'];
		dirs.forEach(function(dir) { FS.mkdir(dir) });

		FS.mount(IDBFS, {}, 'Save');

		FS.syncfs(true, function(err) {
		});
	);
예제 #10
0
int main()
{
    gfxInitDefault();
    gfxSet3D(false);

    PrintConsole topConsole, botConsole;
    consoleInit(GFX_TOP, &topConsole);
    consoleInit(GFX_BOTTOM, &botConsole);

    consoleSelect(&topConsole);
    consoleClear();

    state_t current_state = STATE_NONE;
    state_t next_state = STATE_INITIALIZE;

    FS_ProductInfo product_info;

    char exploitname[64] = {0};
    char titlename[64] = {0};

    char versiondir[64] = {0};
    char displayversion[64] = {0};

    u32 flags_bitmask = 0;

    static char top_text[2048];
    char top_text_tmp[256];
    top_text[0] = '\0';

    int firmware_version[6] = {0};
    int firmware_selected_value = 0;

    int selected_slot = 0;
    int selected_version = 0;
    u32 selected_remaster = 0;

    AM_TitleEntry update_title;
    bool update_exists = false;
    int version_maxnum = 0;

    void* payload_buffer = NULL;
    size_t payload_size = 0;

    u64 program_id = 0;

    while(aptMainLoop())
    {
        hidScanInput();
        if(hidKeysDown() & KEY_START) break;

        // transition function
        if(next_state != current_state)
        {
            memset(top_text_tmp, 0, sizeof(top_text_tmp));

            switch(next_state)
            {
                case STATE_INITIALIZE:
                    strncat(top_text, "Initializing... You may press START at any time\nto return to menu.\n\n", sizeof(top_text) - 1);
                    break;
                case STATE_INITIAL:
                    strncat(top_text, "Welcome to sploit_installer: SALT edition!\nPlease proceed with caution, as you might lose\ndata if you don't.\n\nPress A to continue.\n\n", sizeof(top_text) - 1);
                    break;
                case STATE_SELECT_VERSION:
                    snprintf(top_text_tmp, sizeof(top_text_tmp) - 1, "Auto-detected %s version: %s\nD-Pad to select, A to continue.\n\n", titlename, displayversion);
                    break;
                case STATE_SELECT_SLOT:
                    snprintf(top_text_tmp, sizeof(top_text_tmp) - 1, "Please select the savegame slot %s will be\ninstalled to. D-Pad to select, A to continue.\n", exploitname);
                    break;
                case STATE_SELECT_FIRMWARE:
                    strncat(top_text, "Please select your console's firmware version.\nOnly select NEW 3DS if you own a New 3DS (XL).\nD-Pad to select, A to continue.\n", sizeof(top_text) - 1);
                    break;
                case STATE_DOWNLOAD_PAYLOAD:
                    snprintf(top_text, sizeof(top_text) - 1, "%s\n\n\nDownloading payload...\n", top_text);
                    break;
                case STATE_COMPRESS_PAYLOAD:
                    strncat(top_text, "Processing payload...\n", sizeof(top_text) - 1);
                    break;
                case STATE_INSTALL_PAYLOAD:
                    strncat(top_text, "Installing payload...\n\n", sizeof(top_text) - 1);
                    break;
                case STATE_INSTALLED_PAYLOAD:
                    snprintf(top_text_tmp, sizeof(top_text_tmp) - 1, "Done!\n%s was successfully installed.", exploitname);
                    break;
                case STATE_ERROR:
                    strncat(top_text, "Looks like something went wrong. :(\n", sizeof(top_text) - 1);
                    break;
                default:
                    break;
            }

            if(top_text_tmp[0]) strncat(top_text, top_text_tmp, sizeof(top_text) - 1);

            current_state = next_state;
        }

        consoleSelect(&topConsole);
        printf("\x1b[0;%dHsploit_installer: SALT edition\n\n\n", (50 - 31) / 2);
        printf(top_text);

        // state function
        switch(current_state)
        {
            case STATE_INITIALIZE:
                {
                    fsInit();

                    // get an fs:USER session as the game
                    Result ret = srvGetServiceHandleDirect(&save_session, "fs:USER");
                    if(R_SUCCEEDED(ret)) ret = FSUSER_Initialize(save_session);
                    if(R_FAILED(ret))
                    {
                        snprintf(status, sizeof(status) - 1, "Failed to get game fs:USER session.\n    Error code: %08lX", ret);
                        next_state = STATE_ERROR;
                        break;
                    }

                    ret = httpcInit(0);
                    if(R_FAILED(ret))
                    {
                        snprintf(status, sizeof(status) - 1, "Failed to initialize httpc.\n    Error code: %08lX", ret);
                        next_state = STATE_ERROR;
                        break;
                    }

                    OS_VersionBin nver_versionbin, cver_versionbin;
                    ret = osGetSystemVersionData(&nver_versionbin, &cver_versionbin);
                    if(R_FAILED(ret))
                    {
                        snprintf(status, sizeof(status) - 1, "Failed to get the system version.\n    Error code: %08lX", ret);
                        next_state = STATE_ERROR;
                        break;
                    }

                    ret = cfguInit();
                    if(R_FAILED(ret))
                    {
                        snprintf(status, sizeof(status) - 1, "Failed to initialize cfgu.\n    Error code: %08lX", ret);
                        next_state = STATE_ERROR;
                        break;
                    }

                    u8 region = 0;
                    ret = CFGU_SecureInfoGetRegion(&region);
                    if(R_FAILED(ret))
                    {
                        snprintf(status, sizeof(status) - 1, "Failed to get the system region.\n    Error code: %08lX", ret);
                        next_state = STATE_ERROR;
                        break;
                    }

                    cfguExit();

                    bool is_new3ds = false;
                    APT_CheckNew3DS(&is_new3ds);

                    firmware_version[0] = is_new3ds;
                    firmware_version[5] = region;

                    firmware_version[1] = cver_versionbin.mainver;
                    firmware_version[2] = cver_versionbin.minor;
                    firmware_version[3] = cver_versionbin.build;
                    firmware_version[4] = nver_versionbin.mainver;

                    u32 pid = 0;
                    ret = svcGetProcessId(&pid, CUR_PROCESS_HANDLE);
                    if(R_FAILED(ret))
                    {
                        snprintf(status, sizeof(status) - 1, "Failed to get the process ID for the current process.\n    Error code: %08lX", ret);
                        next_state = STATE_ERROR;
                        break;
                    }

                    ret = FSUSER_GetProductInfo(&product_info, pid);
                    selected_remaster = product_info.remasterVersion;
                    if(R_FAILED(ret))
                    {
                        snprintf(status, sizeof(status) - 1, "Failed to get the product info for the current process.\n    Error code: %08lX", ret);
                        next_state = STATE_ERROR;
                        break;
                    }

                    ret = APT_GetProgramID(&program_id);
                    if(R_FAILED(ret))
                    {
                        snprintf(status, sizeof(status) - 1, "Failed to get the program ID for the current process.\n    Error code: %08lX", ret);
                        next_state = STATE_ERROR;
                        break;
                    }

                    u64 update_program_id = 0;
                    if(((program_id >> 32) & 0xFFFF) == 0) update_program_id = program_id | 0x0000000E00000000ULL;

                    if(update_program_id)
                    {
                        ret = amInit();
                        if(R_FAILED(ret))
                        {
                            snprintf(status, sizeof(status) - 1, "Failed to initialize AM.\n    Error code: %08lX", ret);
                            next_state = STATE_ERROR;
                            break;
                        }

                        ret = AM_GetTitleInfo(1, 1, &update_program_id, &update_title);
                        amExit();

                        if(R_SUCCEEDED(ret))
                            update_exists = true;
                    }

                    ret = romfsInit();
                    if(R_FAILED(ret))
                    {
                        snprintf(status, sizeof(status) - 1, "Failed to initialize romfs for this application (romfsInit()).\n    Error code: %08lX", ret);
                        next_state = STATE_ERROR;
                        break;
                    }

                    ret = load_exploitlist_config("romfs:/exploitlist_config", &program_id, exploitname, titlename, &flags_bitmask);
                    if(ret)
                    {
                        snprintf(status, sizeof(status) - 1, "Failed to select the exploit.\n    Error code: %08lX", ret);
                        if(ret == 1) strncat(status, " Failed to\nopen the config file in romfs.", sizeof(status) - 1);
                        if(ret == 2) strncat(status, " This title is not supported.", sizeof(status) - 1);
                        next_state = STATE_ERROR;
                        break;
                    }

                    int version_index = 0;
                    u32 this_remaster = 0;
                    char this_displayversion[64] = {0};
                    while(true)
                    {
                        ret = load_exploitversion(exploitname, &program_id, version_index, &this_remaster, this_displayversion);
                        if(ret) break;

                        if(this_remaster == selected_remaster)
                        {
                            strncpy(displayversion, this_displayversion, 63);
                            selected_version = version_index;
                        }

                        version_index++;
                    }

                    if(version_index == 0)
                    {
                        snprintf(status, sizeof(status) - 1, "Failed to read remaster versions from config.");
                        next_state = STATE_ERROR;
                        break;
                    }

                    version_maxnum = version_index - 1;
                    next_state = STATE_INITIAL;
                }
                break;

            case STATE_INITIAL:
                {
                    if(hidKeysDown() & KEY_A)
                    {
                        if(version_maxnum != 0) next_state = STATE_SELECT_VERSION;
                        else if(flags_bitmask & 0x10) next_state = STATE_SELECT_FIRMWARE;
                        else next_state = STATE_SELECT_SLOT;
                    }
                }
                break;

            case STATE_SELECT_VERSION:
                {
                    if(hidKeysDown() & KEY_UP) selected_version++;
                    if(hidKeysDown() & KEY_DOWN) selected_version--;
                    if(hidKeysDown() & KEY_A)
                    {
                        if(flags_bitmask & 0x10) next_state = STATE_SELECT_FIRMWARE;
                        else next_state = STATE_SELECT_SLOT;
                    }

                    if(selected_version < 0) selected_version = 0;
                    if(selected_version > version_maxnum) selected_version = version_maxnum;

                    Result ret = load_exploitversion(exploitname, &program_id, selected_version, &selected_remaster, displayversion);
                    if(ret)
                    {
                        snprintf(status, sizeof(status) - 1, "Failed to read remaster version from config.");
                        next_state = STATE_ERROR;
                        break;
                    }

                    printf((selected_version >= version_maxnum) ? "                       \n" : "                      ^\n");
                    printf("      Selected version: %s  \n", displayversion);
                    printf((!selected_version) ? "                       \n" : "                      v\n");
                }
                break;

            case STATE_SELECT_SLOT:
                {
                    if(hidKeysDown() & KEY_UP) selected_slot++;
                    if(hidKeysDown() & KEY_DOWN) selected_slot--;
                    if(hidKeysDown() & KEY_A) next_state = STATE_SELECT_FIRMWARE;

                    if(selected_slot < 0) selected_slot = 0;
                    if(selected_slot > 2) selected_slot = 2;

                    printf((selected_slot >= 2) ? "                                             \n" : "                                            ^\n");
                    printf("                            Selected slot: %d  \n", selected_slot + 1);
                    printf((!selected_slot) ? "                                             \n" : "                                            v\n");
                }
                break;

            case STATE_SELECT_FIRMWARE:
                {
                    if(hidKeysDown() & KEY_LEFT) firmware_selected_value--;
                    if(hidKeysDown() & KEY_RIGHT) firmware_selected_value++;

                    if(firmware_selected_value < 0) firmware_selected_value = 0;
                    if(firmware_selected_value > 5) firmware_selected_value = 5;

                    if(hidKeysDown() & KEY_UP) firmware_version[firmware_selected_value]++;
                    if(hidKeysDown() & KEY_DOWN) firmware_version[firmware_selected_value]--;

                    int firmware_maxnum = 256;
                    if(firmware_selected_value == 0) firmware_maxnum = 2;
                    if(firmware_selected_value == 5) firmware_maxnum = 7;

                    if(firmware_version[firmware_selected_value] < 0) firmware_version[firmware_selected_value] = 0;
                    if(firmware_version[firmware_selected_value] >= firmware_maxnum) firmware_version[firmware_selected_value] = firmware_maxnum - 1;

                    if(hidKeysDown() & KEY_A) next_state = STATE_DOWNLOAD_PAYLOAD;

                    int offset = 26;
                    if(firmware_selected_value)
                    {
                        offset += 7;

                        for(int i = 1; i < firmware_selected_value; i++)
                        {
                            offset += 2;
                            if(firmware_version[i] >= 10) offset++;
                        }
                    }

                    printf((firmware_version[firmware_selected_value] < firmware_maxnum - 1) ? "%*s^%*s" : "%*s-%*s", offset, " ", 50 - offset - 1, " ");
                    printf("      Selected firmware: %s %d-%d-%d-%d %s  \n", firmware_version[0] ? "New3DS" : "Old3DS", firmware_version[1], firmware_version[2], firmware_version[3], firmware_version[4], regions[firmware_version[5]]);
                    printf((firmware_version[firmware_selected_value] > 0) ? "%*sv%*s" : "%*s-%*s", offset, " ", 50 - offset - 1, " ");
                }
                break;

            case STATE_DOWNLOAD_PAYLOAD:
                {
                    httpcContext context;
                    static char in_url[512];
                    static char out_url[512];

                    snprintf(in_url, sizeof(in_url) - 1, "http://smea.mtheall.com/get_payload.php?version=%s-%d-%d-%d-%d-%s",
                        firmware_version[0] ? "NEW" : "OLD", firmware_version[1], firmware_version[2], firmware_version[3], firmware_version[4], regions[firmware_version[5]]);

                    char user_agent[64];
                    snprintf(user_agent, sizeof(user_agent) - 1, "salt_sploit_installer-%s", exploitname);
                    Result ret = get_redirect(in_url, out_url, 512, user_agent);
                    if(R_FAILED(ret))
                    {
                        sprintf(status, "Failed to grab payload url\n    Error code: %08lX", ret);
                        next_state = STATE_ERROR;
                        break;
                    }

                    ret = httpcOpenContext(&context, HTTPC_METHOD_GET, out_url, 0);
                    if(R_FAILED(ret))
                    {
                        sprintf(status, "Failed to open http context\n    Error code: %08lX", ret);
                        next_state = STATE_ERROR;
                        break;
                    }

                    ret = download_file(&context, &payload_buffer, &payload_size, user_agent);
                    if(R_FAILED(ret))
                    {
                        sprintf(status, "Failed to download payload\n    Error code: %08lX", ret);
                        next_state = STATE_ERROR;
                        break;
                    }

                    if(flags_bitmask & 0x1) next_state = STATE_COMPRESS_PAYLOAD;
                    else next_state = STATE_INSTALL_PAYLOAD;
                }
                break;

            case STATE_COMPRESS_PAYLOAD:
                payload_buffer = BLZ_Code(payload_buffer, payload_size, &payload_size, BLZ_NORMAL);
                next_state = STATE_INSTALL_PAYLOAD;
                break;

            case STATE_INSTALL_PAYLOAD:
                {
                    u32 selected_remaster_version = 0;
                    Result ret = load_exploitconfig(exploitname, &program_id, selected_remaster, update_exists ? &update_title.version : NULL, &selected_remaster_version, versiondir, displayversion);
                    if(ret)
                    {
                        snprintf(status, sizeof(status) - 1, "Failed to find your version of\n%s in the config / config loading failed.\n    Error code: %08lX", titlename, ret);
                        if(ret == 1) strncat(status, " Failed to\nopen the config file in romfs.", sizeof(status) - 1);
                        if(ret == 2 || ret == 4) strncat(status, " The romfs config file is invalid.", sizeof(status) - 1);
                        if(ret == 3)
                        {
                            snprintf(status, sizeof(status) - 1, "this update-title version (v%u) of %s is not compatible with %s, sorry\n", update_title.version, titlename, exploitname);
                            next_state = STATE_ERROR;
                            break;
                        }
                        if(ret == 5)
                        {
                            snprintf(status, sizeof(status) - 1, "this remaster version (%04lX) of %s is not compatible with %s, sorry\n", selected_remaster_version, titlename, exploitname);
                            next_state = STATE_ERROR;
                            break;
                        }

                        next_state = STATE_ERROR;
                        break;
                    }

                    if(flags_bitmask & 0x8)
                    {
                        fsUseSession(save_session);
                        Result ret = FSUSER_FormatSaveData(ARCHIVE_SAVEDATA, (FS_Path){PATH_EMPTY, 1, (u8*)""}, 0x200, 10, 10, 11, 11, true);
                        fsEndUseSession();
                        if(ret)
                        {
                            sprintf(status, "Failed to format savedata.\n    Error code: %08lX", ret);
                            next_state = STATE_ERROR;
                            break;
                        }
                    }

                    if(flags_bitmask & 0x2)
                    {
                        Result ret = parsecopy_saveconfig(versiondir, firmware_version[0], selected_slot);
                        if(ret)
                        {
                            sprintf(status, "Failed to install the savefiles with romfs %s savedir.\n    Error code: %08lX", firmware_version[0] == 0?"Old3DS" : "New3DS", ret);
                            next_state = STATE_ERROR;
                            break;
                        }
                    }

                    if(flags_bitmask & 0x4)
                    {
                        Result ret = parsecopy_saveconfig(versiondir, 2, selected_slot);
                        if(ret)
                        {
                            sprintf(status, "Failed to install the savefiles with romfs %s savedir.\n    Error code: %08lX", "common", ret);
                            next_state = STATE_ERROR;
                            break;
                        }
                    }
                }

                {
                    Result ret;

                    if(payload_embed.enabled)
                    {
                        void* buffer = NULL;
                        size_t size = 0;
                        ret = read_savedata(payload_embed.path, &buffer, &size);
                        if(ret)
                        {
                            sprintf(status, "Failed to embed payload\n    Error code: %08lX", ret);
                            next_state = STATE_ERROR;
                            break;
                        }
                        if((payload_embed.offset + payload_size + sizeof(u32)) >= size)
                        {
                            sprintf(status, "Failed to embed payload (too large)\n    0x%X >= 0x%X", (payload_embed.offset + payload_size + sizeof(u32)), size);
                            next_state = STATE_ERROR;
                            break;
                        }

                        *(u32*)(buffer + payload_embed.offset) = payload_size;
                        memcpy(buffer + payload_embed.offset + sizeof(u32), payload_buffer, payload_size);
                        ret = write_savedata(payload_embed.path, buffer, size);

                        free(buffer);
                    }
                    else
                        ret = write_savedata("/payload.bin", payload_buffer, payload_size);

                    if(ret)
                    {
                        sprintf(status, "Failed to install payload\n    Error code: %08lX", ret);
                        next_state = STATE_ERROR;
                        break;
                    }

                    next_state = STATE_INSTALLED_PAYLOAD;
                }
                break;

            case STATE_INSTALLED_PAYLOAD:
                next_state = STATE_NONE;
                break;

            default: break;
        }

        consoleSelect(&botConsole);
        printf("\x1b[0;0H  Current status:\n    %s\n", status);

        gspWaitForVBlank();
    }

    if(payload_buffer) free(payload_buffer);

    romfsExit();
    httpcExit();

    svcCloseHandle(save_session);
    fsExit();

    gfxExit();
    return 0;
}
Result load_hblauncher()
{
	Result ret = 0;
	u8 region=0;
	u8 new3dsflag = 0;

	OS_VersionBin nver_versionbin;
	OS_VersionBin cver_versionbin;

	u32 payloadsize = 0, payloadsize_aligned = 0;
	u32 payload_src = 0;

	char payload_sysver[32];
	char payloadurl[0x80];
	char payload_sdpath[0x80];

	void (*funcptr)(u32*, u32*) = NULL;
	u32 *paramblk = NULL;

	memset(&nver_versionbin, 0, sizeof(OS_VersionBin));
	memset(&cver_versionbin, 0, sizeof(OS_VersionBin));

	memset(payload_sysver, 0, sizeof(payload_sysver));
	memset(payloadurl, 0, sizeof(payloadurl));
	memset(payload_sdpath, 0, sizeof(payload_sdpath));

	printf("Getting system-version/system-info etc...\n");

	ret = cfguInit();
	if(ret!=0)
	{
		printf("Failed to init cfgu: 0x%08x.\n", (unsigned int)ret);
		return ret;
	}
	ret = CFGU_SecureInfoGetRegion(&region);
	if(ret!=0)
	{
		printf("Failed to get region from cfgu: 0x%08x.\n", (unsigned int)ret);
		return ret;
	}
	if(region>=7)
	{
		printf("Region value from cfgu is invalid: 0x%02x.\n", (unsigned int)region);
		ret = -9;
		return ret;
	}
	cfguExit();

	APT_CheckNew3DS(&new3dsflag);

	ret = osGetSystemVersionData(&nver_versionbin, &cver_versionbin);
	if(ret!=0)
	{
		printf("Failed to load the system-version: 0x%08x.\n", (unsigned int)ret);
		return ret;
	}

	snprintf(payload_sysver, sizeof(payload_sysver)-1, "%s-%d-%d-%d-%d-%s", new3dsflag?"NEW":"OLD", cver_versionbin.mainver, cver_versionbin.minor, cver_versionbin.build, nver_versionbin.mainver, regionids_table[region]);
	snprintf(payloadurl, sizeof(payloadurl)-1, "http://smea.mtheall.com/get_payload.php?version=%s", payload_sysver);
	snprintf(payload_sdpath, sizeof(payload_sdpath)-1, "sdmc:/hblauncherloader_otherapp_payload_%s.bin", payload_sysver);

	printf("Detected system-version: %s %d.%d.%d-%d %s\n", new3dsflag?"New3DS":"Old3DS", cver_versionbin.mainver, cver_versionbin.minor, cver_versionbin.build, nver_versionbin.mainver, regionids_table[region]);

	memset(filebuffer, 0, filebuffer_maxsize);

	hidScanInput();

	if((hidKeysHeld() & KEY_X) == 0)
	{
		printf("Since the X button isn't pressed, this will now check for the otherapp payload on SD, with the following filepath: %s\n", payload_sdpath);
		ret = loadsd_payload(payload_sdpath, &payloadsize);
	}
	else
	{
		printf("Skipping SD payload load-attempt since the X button is pressed.\n");
		ret = 1;
	}

	if(ret==0)
	{
		printf("The otherapp payload for this app already exists on SD, that will be used instead of downloading the payload via HTTP.\n");
		payload_src = 0;
	}
	else
	{
		printf("Requesting the actual payload URL with HTTP...\n");
		ret = http_getactual_payloadurl(payloadurl, payloadurl, sizeof(payloadurl));
		if(ret!=0)
		{
			printf("Failed to request the actual payload URL: 0x%08x.\n", (unsigned int)ret);
			printf("If the server isn't down, and the HTTP request was actually done, this may mean your system-version or region isn't supported by the hblauncher-payload currently.\n");
			return ret;
		}

		printf("Downloading the actual payload with HTTP...\n");
		ret = http_download_payload(payloadurl, &payloadsize);
		if(ret!=0)
		{
			printf("Failed to download the actual payload with HTTP: 0x%08x.\n", (unsigned int)ret);
			printf("If the server isn't down, and the HTTP request was actually done, this may mean your system-version or region isn't supported by the hblauncher-payload currently.\n");
			return ret;
		}

		if(ret==0)payload_src = 1;
	}

	printf("Initializing payload data etc...\n");

	payloadsize_aligned = (payloadsize + 0xfff) & ~0xfff;
	if(payloadsize_aligned > PAYLOAD_TEXTMAXSIZE)
	{
		printf("Invalid payload size: 0x%08x.\n", (unsigned int)payloadsize);
		ret = -3;
		return ret;
	}

	if(payload_src)
	{
		hidScanInput();

		if(hidKeysHeld() & KEY_Y)
		{
			printf("Saving the downloaded payload to SD since the Y button is pressed...\n");
			ret = savesd_payload(payload_sdpath, payloadsize);

			if(ret!=0)
			{
				printf("Payload saving failed: 0x%08x.\n", (unsigned int)ret);
			}
			else
			{
				printf("Payload saving was successful.\n");
			}
		}
		else
		{
			printf("Skipping saving the downloaded payload to SD since the Y button isn't pressed.\n");
		}
	}

	memcpy(PAYLOAD_TEXTADDR, filebuffer, payloadsize_aligned);
	memset(filebuffer, 0, filebuffer_maxsize);

	ret = svcFlushProcessDataCache(0xffff8001, PAYLOAD_TEXTADDR, payloadsize_aligned);//Flush dcache for the payload which was copied into .text. Since that area was never executed, icache shouldn't be an issue.
	if(ret!=0)
	{
		printf("svcFlushProcessDataCache failed: 0x%08x.\n", (unsigned int)ret);
		return ret;
	}

	paramblk = linearMemAlign(0x10000, 0x1000);
	if(paramblk==NULL)
	{
		ret = 0xfe;
		printf("Failed to alloc the paramblk.\n");
		return ret;
	}

	httpcExit();

	memset(paramblk, 0, 0x10000);

	paramblk[0x1c>>2] = (u32)gxlowcmd_4;
	paramblk[0x20>>2] = (u32)gsp_flushdcache;
	paramblk[0x48>>2] = 0x8d;//flags
	paramblk[0x58>>2] = (u32)&gspGpuHandle;

	printf("Jumping into the payload...\n");

	funcptr = (void*)PAYLOAD_TEXTADDR;
	funcptr(paramblk, (u32*)(0x10000000-0x1000));

	ret = 0xff;
	printf("The payload returned back into the app, this should *never* happen with the actual hblauncher-payload.\n");

	return ret;
}
예제 #12
0
//Gets system version from kernel and writes it to system.txt
void getSystemVersion()
{
	//FIRSTLY, CHECK NEW 3DS
	u8 isN3DS = 0;
	APT_CheckNew3DS(NULL, &isN3DS);
    unsigned int kversion = *(unsigned int *)0x1FF80000;
	if (!isN3DS || kversion < 0x022C0600)
	{
		//-----------> OLD 3DS
		switch (kversion)
		{
		default:         // Unsupported
			type = '0';
			systemVersion = "unsupported";
			break;
		case 0x02220000: // 4.x
			type = '1';
			systemVersion = "Old 3DS V. 4.1 - 4.5";
			break;
		case 0x02230600: // 5.0
			type = '2';
			systemVersion = "Old 3DS V. 5.0";
			break;
		case 0x02240000: // 5.1
			type = '3';
			systemVersion = "Old 3DS V. 5.1";
			break;
		case 0x02250000: // 6.0
			type = '4';
			systemVersion = "Old 3DS V. 6.0";
			break;
		case 0x02260000: // 6.1
			type = '5';
			systemVersion = "Old 3DS V. 6.1 - 6.3";
			break;
		case 0x02270400: // 7.0-7.1
			type = '6';
			systemVersion = "Old 3DS V. 7.0 - 7.1";
			break;
		case 0x02280000: // 7.2
			type = '7';
			systemVersion = "Old 3DS V. 7.2";
			break;
		case 0x022C0600: // 8.x
			type = '8';
			systemVersion = "Old 3DS V. 8.0 - 8.1";
			break;
		case 0x022E0000: // 9.x
			type = '9';
			systemVersion = "Old 3DS V. 9.0 - 9.2";
			break;
		}
	}
	else
	{
		//-----------> NEW 3DS
		switch (kversion)
		{
		case 0x022C0600: // 8.x
			type = 'a';
			systemVersion = "New 3DS V. 8.1";
			break;
		case 0x022E0000: // 9.x
			type = 'b';
			systemVersion = "New 3DS V. 9.0 - 9.2";
			break;
		default:         // Unsupported
			type = '0';
			systemVersion = "unsupported";
			break;
		}
	}
}
예제 #13
0
int main()
{
   static char load_filename[512];
    char    *romname = NULL;
	float audioStart; // this is a float to count the half sample per frame needed ho have precise timing
	u32 audioTarget, audioEnd;

    srvInit();
    aptInit();
    hidInit();

	APT_CheckNew3DS(&isN3DS);
	
	if(isN3DS) 
		osSetSpeedupEnable(true);

	get_config_path();

	sprintf(savename, "%s/Handy3ds.cfg", config_base_path);  // using savename char buffer to save memory
	do_config(savename);

	handy_3ds_video_init();

    sprintf(bios_path_and_name, "%s/%s", config_bios_path, "lynxboot.img");

    // Call filebrowser
       if(gui_LoadFile(load_filename)!= -1)  {
            romname = (char *)&load_filename;
            do {
                hidScanInput();
            } while (hidKeysHeld());
        } else {
			handy_3ds_quit();
        }

    // Primary initalise of Handy - should be called AFTER _Init() but BEFORE handy_3ds_video_setup()
    handy_3ds_core_init(romname);

    // Initialise Handy 3ds video 
    handy_3ds_video_setup(1, 0, 0, 32, LynxScale, 0, 0);

    // Initialise Handy 3ds audio
    printf("\nInitialising 3DS Audio...     ");
    gAudioEnabled = handy_3ds_audio_init();

    printf("[DONE]\n");


    // Setup of Handy Core video
    handy_3ds_video_reinit(32);

    printf("Starting Lynx Emulation...\n");
	
    bool touched = false;
    audioStart =  gAudioBufferPointer;  // both should be 0 at this point

	// initialize timers
	u64 tickcurr, syncticknext,synctickres; 
	u64 fpsticknext,fpstickres;
	int frameSyncPeriod;

	if(isN3DS) 
		frameSyncPeriod = 1;
	else	
		frameSyncPeriod = 12;

	fpstickres= TICKS_PER_SEC; 
	synctickres = TICKS_PER_FRAME * frameSyncPeriod; // on o3ds the sync is every 12 frame, i.e. 5 times every sec
	tickcurr=svcGetSystemTick();
	fpsticknext = tickcurr + fpstickres;
	syncticknext = tickcurr + synctickres;
	int fpscnt = 0, synccnt = 0;
	
	gThrottleMaxPercentage = isN3DS?100:50; //  !! TO DO: check if 50 is the best value.

    while(!emulation)
    {
        // Initialise Handy button events
        int OldKeyMask, KeyMask = mpLynx->GetButtonData();
        OldKeyMask = KeyMask;

        // Getting events for keyboard and/or joypad handling
        hidScanInput();
        if (hidKeysHeld() & KEY_TOUCH) {
            touched = true;
        } else {
            if (touched) {
				handy_3ds_audio_pause();
                gui_Run();
                KeyMask = 0;
                touched = false;
//				audioStart =  gAudioBufferPointer;
                do {
                    hidScanInput();
                } while (hidKeysHeld());

				gThrottleMaxPercentage = isN3DS?100:50; //  !! Loading a savestate overrides this value, so we force it again exiting menu

				fpscnt = 0;
				synccnt = 0;
				tickcurr=svcGetSystemTick();
				fpsticknext = tickcurr + fpstickres;
				syncticknext = tickcurr + synctickres;
            } else {
                touched = false;
            }
        }
        KeyMask = handy_3ds_on_key_down(hidKeysHeld(), KeyMask);

        // Check if there are handling events and then update the Handy button events.
        if (OldKeyMask != KeyMask)
            mpLynx->SetButtonData(KeyMask);

        // Update TimerCount
        gTimerCount++;

        while( handy_3ds_update() )
        {
            
            //!!
            hidScanInput();
            u32 held = hidKeysHeld();
            if (held & KEY_SELECT) {
//				handy_3ds_video_quit();
//				handy_3ds_audio_quit();
//              exit(EXIT_SUCCESS);   //break;
				touched = true; // enter menu
            }
            //!!
 
           
            if(!gSystemHalt)
            {
				if (!handy_3ds_audio_getstate()) {
					audioStart=0.0; // reset counter
					gAudioBufferPointer = 0; // reset buffer. really not needed since we set it to 0 in handy_3ds_audio_pause().
				}	

				// increase sound samples counter - 367,5 samples per frame at 60 fps
                audioEnd =  (int)(audioStart + 367.5) % HANDY_AUDIO_BUFFER_SIZE;
				 // filling 1 half of the buffer, roughly enough for slow frames on o3DS without risk of buffer head to reach the tail during the 10 frames before resync.
                audioTarget =  (int)(audioStart + HANDY_AUDIO_BUFFER_SIZE/2.1) % HANDY_AUDIO_BUFFER_SIZE;
				if (audioTarget>audioStart)
				  while (gAudioBufferPointer<audioTarget) mpLynx->Update();  
                else
				  while ((gAudioBufferPointer>audioStart)||(gAudioBufferPointer<audioTarget)) mpLynx->Update();
				  
				if(Handy_cfg_Throttle && Handy_cfg_Sound && gAudioEnabled) {
					if (handy_3ds_audio_getstate())
						handy_3ds_audio_callback(audioStart, (int)(audioTarget-audioStart));  
					else
						handy_3ds_audio_start(22050, audioStart);  
				}	
				audioStart = audioEnd;
            }
            else
            {
                printf("gSystemHalt : %ld\n", gSystemHalt);
                gTimerCount++;
            }
			system_checkPolls();
        }

// Timing

		fpscnt++;
		synccnt++;

		if (Handy_cfg_Throttle) {
			if (synccnt==frameSyncPeriod){
				svcSleepThread((syncticknext - svcGetSystemTick()) / TICKS_PER_NSEC); 
			}
		}

		tickcurr=svcGetSystemTick();
 		
		if (tickcurr >= syncticknext) {
			syncticknext += synctickres;
			synccnt = 0;
		} 
		if (tickcurr >= fpsticknext) {
			fpsticknext += fpstickres;
			fps_counter = fpscnt;
			fpscnt = 0;
		} 

    }   // while(!emulation)

	osSetSpeedupEnable(true);
	return 0;
}