/*
 *  Copyright (C) 2008 Nuke (wiinuke@gmail.com)
 *
 *  this file is part of GeckoOS for USB Gecko
 *  http://www.usbgecko.com
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <gccore.h>
#include <ogcsys.h>
#include <wiiuse/wpad.h>

#include "geckoload.h"
#include "relos.h"
#include "reloself.h"
#include "tools.h"
#include "geckomenu.h"
#include "patchcode.h"
#include "relostub.h"

#define reloc_code_location 0x817f8000
#define exe_file_location 0x90080000
//#define exe_file_location 0x80003f00
#define packetsize 3968

extern s32 __IOS_ShutdownSubsystems();
extern void __exception_closeall();


typedef void (*entrypoint) (void);
extern const unsigned char kenobiwii[];
const int kenobiwii_size;
/*---------------------------------------------------------------------------*
    Name:               commands_uploadexe
    Description:        Uploads DOL / ELF files from PC
*---------------------------------------------------------------------------*/
void commands_uploadexe(u32 mode) // 0 for DOL, 1 for ELF, 2 for DOL debug, 3 for ELF debug
{
	u8 exesize[4];
	u32 exe_filesize;
	u32 fullpackets = 0;
	u32 currentpacket = 0;
	u32 last_bytes = 0;
	static u8 packetbuff[packetsize] ATTRIBUTE_ALIGN(32);
	u8 *exe_buff = (u8*)exe_file_location;
	u8 ack_packet = 0xAA;

	usb_sendbuffer_safe(EXI_CHANNEL_1,&ack_packet,1);

	usb_recvbuffer_safe(EXI_CHANNEL_1,&exesize, 4);
	exe_filesize = be32(exesize);

	memset((u8*)exe_file_location, 0, exe_filesize);			
	
	fullpackets = exe_filesize / packetsize;				
    last_bytes  = exe_filesize % packetsize;		
	doprogress(0,fullpackets); // Init and draw progress box

	for (currentpacket=0;currentpacket < fullpackets;)
	{
		memset(packetbuff, 0, packetsize);
		usb_recvbuffer_safe(EXI_CHANNEL_1,&packetbuff, packetsize);
		memcpy(exe_buff, packetbuff, packetsize);
		exe_buff += packetsize;
		currentpacket++;		
		doprogress(1,fullpackets); // Step
		usb_sendbuffer_safe(EXI_CHANNEL_1,&ack_packet,1);
	}
	doprogress(2,fullpackets); // Padding
	// Dump remainder and flush
	usb_recvbuffer_safe(EXI_CHANNEL_1,&packetbuff, last_bytes);
	memcpy(exe_buff, &packetbuff, last_bytes);
	DCFlushRange((u8*)exe_file_location, exe_filesize);
	// Copy stub
	
	
	switch(mode)
	{
		case 0:
			memcpy((void*)0x80001800, relostub, relostub_size);
			DCFlushRange((void*)0x80001800, relostub_size);
			memcpy((u8*)reloc_code_location, relos, relos_size); // DOL
			DCFlushRange((u8*)reloc_code_location, relos_size);
		break;

		case 1:
			memcpy((void*)0x80001800, relostub, relostub_size);
			DCFlushRange((void*)0x80001800, relostub_size);
			memcpy((u8*)reloc_code_location, reloself, reloself_size); //ELF
			DCFlushRange((u8*)reloc_code_location, reloself_size);
		break;
	}
		void (*exe_entry)(void*) = reloc_code_location;
		sdio_Deinitialize();
		WPAD_Shutdown();						// crashes without
		__IOS_ShutdownSubsystems();
		__exception_closeall();
		exe_entry((void*)exe_file_location);	// disables IRQ and relocates from very high
}
