diff --git a/desmume/src/Makefile.am b/desmume/src/Makefile.am index 17db3cd44..80bd935ba 100644 --- a/desmume/src/Makefile.am +++ b/desmume/src/Makefile.am @@ -21,7 +21,7 @@ libdesmume_a_SOURCES = \ debug.cpp debug.h driver.h \ Disassembler.cpp Disassembler.h \ emufile.h emufile.cpp fat.h FIFO.cpp FIFO.h \ - GPU.cpp GPU.h \ + firmware.cpp firmware.h GPU.cpp GPU.h \ GPU_osd.cpp GPU_osd.h \ mem.h mc.cpp mc.h \ path.h \ diff --git a/desmume/src/NDSSystem.cpp b/desmume/src/NDSSystem.cpp index e2d62a373..da5fadf8f 100644 --- a/desmume/src/NDSSystem.cpp +++ b/desmume/src/NDSSystem.cpp @@ -42,6 +42,7 @@ #include "Disassembler.h" #include "readwrite.h" #include "debug.h" +#include "firmware.h" #include "path.h" @@ -55,15 +56,9 @@ std::string InputDisplayString; static BOOL LidClosed = FALSE; static u8 countLid = 0; - GameInfo gameInfo; - -// the count of bytes copied from the firmware into memory -#define NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT 0x70 - -BOOL fw_success = FALSE; - NDSSystem nds; +CFIRMWARE *firmware = NULL; using std::min; using std::max; @@ -75,415 +70,6 @@ int TotalLagFrames; TSCalInfo TSCal; -/* ------------------------------------------------------------------------- */ -/* FIRMWARE DECRYPTION */ - -static u32 keyBuf[0x412]; -static u32 keyCode[3]; - -#define DWNUM(i) ((i) >> 2) - -static u32 bswap32(u32 val) -{ - return (((val & 0x000000FF) << 24) | ((val & 0x0000FF00) << 8) | ((val & 0x00FF0000) >> 8) | ((val & 0xFF000000) >> 24)); -} - -static BOOL getKeyBuf() -{ - int dummy; - FILE *file = fopen(CommonSettings.ARM7BIOS, "rb"); - - if(file == NULL) - return FALSE; - - fseek(file, 0x30, SEEK_SET); - dummy = fread(keyBuf, 0x412, 4, file); - - fclose(file); - return TRUE; -} - -static void crypt64BitUp(u32 *ptr) -{ - u32 Y = ptr[0]; - u32 X = ptr[1]; - - for(u32 i = 0x00; i <= 0x0F; i++) - { - u32 Z = (keyBuf[i] ^ X); - X = keyBuf[DWNUM(0x048 + (((Z >> 24) & 0xFF) << 2))]; - X = (keyBuf[DWNUM(0x448 + (((Z >> 16) & 0xFF) << 2))] + X); - X = (keyBuf[DWNUM(0x848 + (((Z >> 8) & 0xFF) << 2))] ^ X); - X = (keyBuf[DWNUM(0xC48 + ((Z & 0xFF) << 2))] + X); - X = (Y ^ X); - Y = Z; - } - - ptr[0] = (X ^ keyBuf[DWNUM(0x40)]); - ptr[1] = (Y ^ keyBuf[DWNUM(0x44)]); -} - -static void crypt64BitDown(u32 *ptr) -{ - u32 Y = ptr[0]; - u32 X = ptr[1]; - - for(u32 i = 0x11; i >= 0x02; i--) - { - u32 Z = (keyBuf[i] ^ X); - X = keyBuf[DWNUM(0x048 + (((Z >> 24) & 0xFF) << 2))]; - X = (keyBuf[DWNUM(0x448 + (((Z >> 16) & 0xFF) << 2))] + X); - X = (keyBuf[DWNUM(0x848 + (((Z >> 8) & 0xFF) << 2))] ^ X); - X = (keyBuf[DWNUM(0xC48 + ((Z & 0xFF) << 2))] + X); - X = (Y ^ X); - Y = Z; - } - - ptr[0] = (X ^ keyBuf[DWNUM(0x04)]); - ptr[1] = (Y ^ keyBuf[DWNUM(0x00)]); -} - -static void applyKeycode(u32 modulo) -{ - crypt64BitUp(&keyCode[1]); - crypt64BitUp(&keyCode[0]); - - u32 scratch[2] = {0x00000000, 0x00000000}; - - for(u32 i = 0; i <= 0x44; i += 4) - { - keyBuf[DWNUM(i)] = (keyBuf[DWNUM(i)] ^ bswap32(keyCode[DWNUM(i % modulo)])); - } - - for(u32 i = 0; i <= 0x1040; i += 8) - { - crypt64BitUp(scratch); - keyBuf[DWNUM(i)] = scratch[1]; - keyBuf[DWNUM(i+4)] = scratch[0]; - } -} - -static BOOL initKeycode(u32 idCode, int level, u32 modulo) -{ - if(getKeyBuf() == FALSE) - return FALSE; - - keyCode[0] = idCode; - keyCode[1] = (idCode >> 1); - keyCode[2] = (idCode << 1); - - if(level >= 1) applyKeycode(modulo); - if(level >= 2) applyKeycode(modulo); - - keyCode[1] <<= 1; - keyCode[2] >>= 1; - - if(level >= 3) applyKeycode(modulo); - - return TRUE; -} - -static u16 getBootCodeCRC16() -{ - unsigned int i, j; - u32 crc = 0xFFFF; - const u16 val[8] = {0xC0C1, 0xC181, 0xC301, 0xC601, 0xCC01, 0xD801, 0xF001, 0xA001}; - - for(i = 0; i < nds.FW_ARM9BootCodeSize; i++) - { - crc = (crc ^ nds.FW_ARM9BootCode[i]); - - for(j = 0; j < 8; j++) - { - if(crc & 0x0001) - crc = ((crc >> 1) ^ (val[j] << (7-j))); - else - crc = (crc >> 1); - } - } - - for(i = 0; i < nds.FW_ARM7BootCodeSize; i++) - { - crc = (crc ^ nds.FW_ARM7BootCode[i]); - - for(j = 0; j < 8; j++) - { - if(crc & 0x0001) - crc = ((crc >> 1) ^ (val[j] << (7-j))); - else - crc = (crc >> 1); - } - } - - return (crc & 0xFFFF); -} - -static u32 * decryptFirmwareBlock(const char *blockName, u32 *src, u32 &size) -{ - u32 curBlock[2]; - u32 *dst; - u32 i, j; - u32 xIn = 4, xOut = 0; - u32 len; - u32 offset; - u32 windowOffset; - u32 xLen; - u8 d; - u16 data; - - memcpy(curBlock, src, 8); - crypt64BitDown(curBlock); - - u32 blockSize = (curBlock[0] >> 8); - size = blockSize; - - INFO("Firmware: %s final size: %i bytes\n", blockName, blockSize); - - dst = (u32*)new u8[blockSize]; - - xLen = blockSize; - - while(xLen > 0) - { - d = T1ReadByte((u8*)curBlock, (xIn % 8)); - xIn++; - if((xIn % 8) == 0) - { - memcpy(curBlock, (((u8*)src) + xIn), 8); - crypt64BitDown(curBlock); - } - - for(i = 0; i < 8; i++) - { - if(d & 0x80) - { - data = (T1ReadByte((u8*)curBlock, (xIn % 8)) << 8); - xIn++; - if((xIn % 8) == 0) - { - memcpy(curBlock, (((u8*)src) + xIn), 8); - crypt64BitDown(curBlock); - } - data |= T1ReadByte((u8*)curBlock, (xIn % 8)); - xIn++; - if((xIn % 8) == 0) - { - memcpy(curBlock, (((u8*)src) + xIn), 8); - crypt64BitDown(curBlock); - } - - len = (data >> 12) + 3; - offset = (data & 0xFFF); - windowOffset = (xOut - offset - 1); - - for(j = 0; j < len; j++) - { - T1WriteByte((u8*)dst, xOut, T1ReadByte((u8*)dst, windowOffset)); - xOut++; - windowOffset++; - - xLen--; - if(xLen == 0) - goto lz77End; - } - } - else - { - T1WriteByte((u8*)dst, xOut, T1ReadByte((u8*)curBlock, (xIn % 8))); - xOut++; - xIn++; - if((xIn % 8) == 0) - { - memcpy(curBlock, (((u8*)src) + xIn), 8); - crypt64BitDown(curBlock); - } - - xLen--; - if(xLen == 0) - goto lz77End; - } - - d = ((d << 1) & 0xFF); - } - } - -lz77End: - - return dst; -} - -static BOOL decryptFirmware(u8 *data) -{ - u16 shifts; - u16 shift1, shift2, shift3, shift4; - u32 part1addr, part2addr, part3addr, part4addr, part5addr; - u32 part1ram, part2ram; - - shifts = T1ReadWord(data, 0x14); - shift1 = (shifts & 0x7); - shift2 = ((shifts >> 3) & 0x7); - shift3 = ((shifts >> 6) & 0x7); - shift4 = ((shifts >> 9) & 0x7); - - part1addr = T1ReadWord(data, 0x0C); - part1addr = (part1addr << (2+shift1)); - - INFO("Firmware: ARM9 boot code address: %05X\n", part1addr); - - part1ram = T1ReadWord(data, 0x0E); - part1ram = (0x02800000 - (part1ram << (2+shift2))); - - INFO("Firmware: ARM9 boot code RAM address: %08X\n", part1ram); - - part2addr = T1ReadWord(data, 0x10); - part2addr = (part2addr << (2+shift3)); - - INFO("Firmware: ARM7 boot code address: %05X\n", part2addr); - - part2ram = T1ReadWord(data, 0x12); - part2ram = (0x03810000 - (part2ram << (2+shift4))); - - INFO("Firmware: ARM7 boot code RAM address: %08X\n", part2ram); - - part3addr = T1ReadWord(data, 0x00); - part3addr = (part3addr << 3); - - INFO("Firmware: ARM9 GUI code address: %05X\n", part3addr); - - part4addr = T1ReadWord(data, 0x02); - part4addr = (part4addr << 3); - - INFO("Firmware: ARM7 GUI code address: %05X\n", part4addr); - - part5addr = T1ReadWord(data, 0x16); - part5addr = (part5addr << 3); - - INFO("Firmware: data/gfx address: %05X\n", part5addr); - - if(initKeycode(T1ReadLong(data, 0x08), 1, 0xC) == FALSE) return FALSE; - crypt64BitDown((u32*)&data[0x18]); - if(initKeycode(T1ReadLong(data, 0x08), 2, 0xC) == FALSE) return FALSE; - - nds.FW_ARM9BootCode = (u8*)decryptFirmwareBlock("ARM9 boot code", (u32*)&data[part1addr], nds.FW_ARM9BootCodeSize); - nds.FW_ARM7BootCode = (u8*)decryptFirmwareBlock("ARM7 boot code", (u32*)&data[part2addr], nds.FW_ARM7BootCodeSize); - - nds.FW_ARM9BootCodeAddr = part1ram; - nds.FW_ARM7BootCodeAddr = part2ram; - - u16 crc16_header = T1ReadWord(data, 0x06); - u16 crc16_mine = getBootCodeCRC16(); - if(crc16_header != crc16_mine) - { - INFO("Firmware: error: the boot code CRC16 (%04X) doesn't match the value in the firmware header (%04X).\n", - crc16_mine, crc16_header); - return FALSE; - } - - return TRUE; -} - -/* ------------------------------------------------------------------------- */ - -static u32 -calc_CRC16( u32 start, const u8 *data, int count) { - int i,j; - u32 crc = start & 0xffff; - const u16 val[8] = { 0xC0C1,0xC181,0xC301,0xC601,0xCC01,0xD801,0xF001,0xA001 }; - for(i = 0; i < count; i++) - { - crc = crc ^ data[i]; - - for(j = 0; j < 8; j++) { - int do_bit = 0; - - if ( crc & 0x1) - do_bit = 1; - - crc = crc >> 1; - - if ( do_bit) { - crc = crc ^ (val[j] << (7-j)); - } - } - } - return crc; -} - -static int -copy_firmware_user_data( u8 *dest_buffer, const u8 *fw_data) { - /* - * Determine which of the two user settings in the firmware is the current - * and valid one and then copy this into the destination buffer. - * - * The current setting will have a greater count. - * Settings are only valid if its CRC16 is correct. - */ - int user1_valid = 0; - int user2_valid = 0; - u32 user_settings_offset; - u32 fw_crc; - u32 crc; - int copy_good = 0; - - user_settings_offset = fw_data[0x20]; - user_settings_offset |= fw_data[0x21] << 8; - user_settings_offset <<= 3; - - if ( user_settings_offset <= 0x3FE00) { - s32 copy_settings_offset = -1; - - crc = calc_CRC16( 0xffff, &fw_data[user_settings_offset], - NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT); - fw_crc = fw_data[user_settings_offset + 0x72]; - fw_crc |= fw_data[user_settings_offset + 0x73] << 8; - if ( crc == fw_crc) { - user1_valid = 1; - } - - crc = calc_CRC16( 0xffff, &fw_data[user_settings_offset + 0x100], - NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT); - fw_crc = fw_data[user_settings_offset + 0x100 + 0x72]; - fw_crc |= fw_data[user_settings_offset + 0x100 + 0x73] << 8; - if ( crc == fw_crc) { - user2_valid = 1; - } - - if ( user1_valid) { - if ( user2_valid) { - u16 count1, count2; - - count1 = fw_data[user_settings_offset + 0x70]; - count1 |= fw_data[user_settings_offset + 0x71] << 8; - - count2 = fw_data[user_settings_offset + 0x100 + 0x70]; - count2 |= fw_data[user_settings_offset + 0x100 + 0x71] << 8; - - if ( count2 > count1) { - copy_settings_offset = user_settings_offset + 0x100; - } - else { - copy_settings_offset = user_settings_offset; - } - } - else { - copy_settings_offset = user_settings_offset; - } - } - else if ( user2_valid) { - /* copy the second user settings */ - copy_settings_offset = user_settings_offset + 0x100; - } - - if ( copy_settings_offset > 0) { - memcpy( dest_buffer, &fw_data[copy_settings_offset], - NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT); - copy_good = 1; - } - } - - return copy_good; -} - void Desmume_InitOnce() { static bool initOnce = false; @@ -527,9 +113,6 @@ int NDS_Init( void) { WIFI_Init() ; - nds.FW_ARM9BootCode = NULL; - nds.FW_ARM7BootCode = NULL; - // Init calibration info TSCal.adc.x1 = 0x0200; TSCal.adc.y1 = 0x0200; @@ -1238,238 +821,6 @@ int NDS_WriteBMP_32bppBuffer(int width, int height, const void* buf, const char return 1; } - -static void fill_user_data_area( struct NDS_fw_config_data *user_settings,u8 *data, int count) -{ - u32 crc; - int i; - u8 *ts_cal_data_area; - - memset( data, 0, 0x100); - - // version - data[0x00] = 5; - data[0x01] = 0; - - // colour - data[0x02] = user_settings->fav_colour; - - // birthday month and day - data[0x03] = user_settings->birth_month; - data[0x04] = user_settings->birth_day; - - //nickname and length - for ( i = 0; i < MAX_FW_NICKNAME_LENGTH; i++) { - data[0x06 + (i * 2)] = user_settings->nickname[i] & 0xff; - data[0x06 + (i * 2) + 1] = (user_settings->nickname[i] >> 8) & 0xff; - } - - data[0x1a] = user_settings->nickname_len; - - //Message - for ( i = 0; i < MAX_FW_MESSAGE_LENGTH; i++) { - data[0x1c + (i * 2)] = user_settings->message[i] & 0xff; - data[0x1c + (i * 2) + 1] = (user_settings->message[i] >> 8) & 0xff; - } - - data[0x50] = user_settings->message_len; - - //touch screen calibration - ts_cal_data_area = &data[0x58]; - for ( i = 0; i < 2; i++) { - // ADC x y - *ts_cal_data_area++ = user_settings->touch_cal[i].adc_x & 0xff; - *ts_cal_data_area++ = (user_settings->touch_cal[i].adc_x >> 8) & 0xff; - *ts_cal_data_area++ = user_settings->touch_cal[i].adc_y & 0xff; - *ts_cal_data_area++ = (user_settings->touch_cal[i].adc_y >> 8) & 0xff; - - //screen x y - *ts_cal_data_area++ = user_settings->touch_cal[i].screen_x; - *ts_cal_data_area++ = user_settings->touch_cal[i].screen_y; - } - - //language and flags - data[0x64] = user_settings->language; - data[0x65] = 0xfc; - - //update count and crc - data[0x70] = count & 0xff; - data[0x71] = (count >> 8) & 0xff; - - crc = calc_CRC16( 0xffff, data, 0x70); - data[0x72] = crc & 0xff; - data[0x73] = (crc >> 8) & 0xff; - - memset( &data[0x74], 0xff, 0x100 - 0x74); -} - -// creates an firmware flash image, which contains all needed info to initiate a wifi connection -int NDS_CreateDummyFirmware( struct NDS_fw_config_data *user_settings) -{ - //Create the firmware header - - memset( MMU.fw.data, 0, 0x40000); - - //firmware identifier - MMU.fw.data[0x8] = 'M'; - MMU.fw.data[0x8 + 1] = 'A'; - MMU.fw.data[0x8 + 2] = 'C'; - MMU.fw.data[0x8 + 3] = 'P'; - - // DS type - if ( user_settings->ds_type == NDS_FW_DS_TYPE_LITE) - MMU.fw.data[0x1d] = 0x20; - else - MMU.fw.data[0x1d] = 0xff; - - //User Settings offset 0x3fe00 / 8 - MMU.fw.data[0x20] = 0xc0; - MMU.fw.data[0x21] = 0x7f; - - - //User settings (at 0x3FE00 and 0x3FF00) - - fill_user_data_area( user_settings, &MMU.fw.data[ 0x3FE00], 0); - fill_user_data_area( user_settings, &MMU.fw.data[ 0x3FF00], 1); - - // Wifi config length - MMU.fw.data[0x2C] = 0x38; - MMU.fw.data[0x2D] = 0x01; - - MMU.fw.data[0x2E] = 0x00; - - //Wifi version - MMU.fw.data[0x2F] = 0x00; - - //MAC address - memcpy((MMU.fw.data + 0x36), FW_Mac, sizeof(FW_Mac)); - - //Enabled channels - MMU.fw.data[0x3C] = 0xFE; - MMU.fw.data[0x3D] = 0x3F; - - MMU.fw.data[0x3E] = 0xFF; - MMU.fw.data[0x3F] = 0xFF; - - //RF related - MMU.fw.data[0x40] = 0x02; - MMU.fw.data[0x41] = 0x18; - MMU.fw.data[0x42] = 0x0C; - - MMU.fw.data[0x43] = 0x01; - - //Wifi I/O init values - memcpy((MMU.fw.data + 0x44), FW_WIFIInit, sizeof(FW_WIFIInit)); - - //Wifi BB init values - memcpy((MMU.fw.data + 0x64), FW_BBInit, sizeof(FW_BBInit)); - - //Wifi RF init values - memcpy((MMU.fw.data + 0xCE), FW_RFInit, sizeof(FW_RFInit)); - - //Wifi channel-related init values - memcpy((MMU.fw.data + 0xF2), FW_RFChannel, sizeof(FW_RFChannel)); - memcpy((MMU.fw.data + 0x146), FW_BBChannel, sizeof(FW_BBChannel)); - memset((MMU.fw.data + 0x154), 0x10, 0xE); - - //WFC profiles - memcpy((MMU.fw.data + 0x3FA40), &FW_WFCProfile1, sizeof(FW_WFCProfile)); - memcpy((MMU.fw.data + 0x3FB40), &FW_WFCProfile2, sizeof(FW_WFCProfile)); - memcpy((MMU.fw.data + 0x3FC40), &FW_WFCProfile3, sizeof(FW_WFCProfile)); - (*(u16*)(MMU.fw.data + 0x3FAFE)) = (u16)calc_CRC16(0, (MMU.fw.data + 0x3FA00), 0xFE); - (*(u16*)(MMU.fw.data + 0x3FBFE)) = (u16)calc_CRC16(0, (MMU.fw.data + 0x3FB00), 0xFE); - (*(u16*)(MMU.fw.data + 0x3FCFE)) = (u16)calc_CRC16(0, (MMU.fw.data + 0x3FC00), 0xFE); - - - MMU.fw.data[0x162] = 0x19; - memset((MMU.fw.data + 0x163), 0xFF, 0x9D); - - //Wifi settings CRC16 - (*(u16*)(MMU.fw.data + 0x2A)) = calc_CRC16(0, (MMU.fw.data + 0x2C), 0x138); - - return TRUE ; -} - -void NDS_FillDefaultFirmwareConfigData( struct NDS_fw_config_data *fw_config) { - const char *default_nickname = "yopyop"; - const char *default_message = "DeSmuME makes you happy!"; - int i; - int str_length; - - memset( fw_config, 0, sizeof( struct NDS_fw_config_data)); - fw_config->ds_type = NDS_FW_DS_TYPE_FAT; - - fw_config->fav_colour = 7; - - fw_config->birth_day = 23; - fw_config->birth_month = 6; - - str_length = strlen( default_nickname); - for ( i = 0; i < str_length; i++) { - fw_config->nickname[i] = default_nickname[i]; - } - fw_config->nickname_len = str_length; - - str_length = strlen( default_message); - for ( i = 0; i < str_length; i++) { - fw_config->message[i] = default_message[i]; - } - fw_config->message_len = str_length; - - /* default to English */ - fw_config->language = 1; - - /* default touchscreen calibration */ - fw_config->touch_cal[0].adc_x = 0x200; - fw_config->touch_cal[0].adc_y = 0x200; - fw_config->touch_cal[0].screen_x = 0x20 + 1; // calibration screen coords are 1-based, - fw_config->touch_cal[0].screen_y = 0x20 + 1; // either that or NDS_getADCTouchPosX/Y are wrong. - - fw_config->touch_cal[1].adc_x = 0xe00; - fw_config->touch_cal[1].adc_y = 0x800; - fw_config->touch_cal[1].screen_x = 0xe0 + 1; - fw_config->touch_cal[1].screen_y = 0x80 + 1; -} - -int NDS_LoadFirmware(const char *filename) -{ - int i; - unsigned long size; - //FILE *file; - - if ((MMU.fw.fp = fopen(filename, "rb+")) == NULL) - return -1; - - fseek(MMU.fw.fp, 0, SEEK_END); - size = ftell(MMU.fw.fp); - fseek(MMU.fw.fp, 0, SEEK_SET); - - if(size > MMU.fw.size) - { - fclose(MMU.fw.fp); - fw_success = FALSE; - return -1; - } - - i = fread(MMU.fw.data, size, 1, MMU.fw.fp); - //fclose(file); - - INFO("Firmware: decrypting NDS firmware %s...\n", filename); - - if(decryptFirmware(MMU.fw.data) == FALSE) - { - INFO("Firmware: decryption failed.\n"); - fw_success = FALSE; - } - else - { - INFO("Firmware: decryption successful.\n"); - fw_success = TRUE; - } - - return i; -} - void NDS_Sleep() { nds.sleeping = TRUE; } @@ -2484,9 +1835,10 @@ static void resetUserInput(); bool _HACK_DONT_STOPMOVIE = false; void NDS_Reset() { - u32 src; - u32 dst; - FILE* inf = 0; + u32 src = 0; + u32 dst = 0; + bool fw_success = false; + FILE* inf = NULL; NDS_header * header = NDS_getROMHeader(); DEBUG_reset(); @@ -2582,35 +1934,23 @@ void NDS_Reset() #endif } - if(CommonSettings.UseExtFirmware == true) - NDS_LoadFirmware(CommonSettings.Firmware); - - if((CommonSettings.UseExtBIOS == true) && (CommonSettings.UseExtFirmware == true) && (CommonSettings.BootFromFirmware == true) && (fw_success == TRUE)) + if (firmware) + { + delete [] firmware; + firmware = NULL; + } + firmware = new CFIRMWARE(); + fw_success = firmware->load(); + if ((CommonSettings.UseExtBIOS == true) && (CommonSettings.BootFromFirmware == true) && (fw_success == TRUE)) { - // Copy firmware boot codes to their respective locations - - src = 0; - dst = nds.FW_ARM9BootCodeAddr; - for(u32 i = 0; i < (nds.FW_ARM9BootCodeSize >> 2); i++) - { - _MMU_write32(dst, T1ReadLong(nds.FW_ARM9BootCode, src)); - src += 4; dst += 4; - } - - src = 0; - dst = nds.FW_ARM7BootCodeAddr; - for(u32 i = 0; i < (nds.FW_ARM7BootCodeSize >> 2); i++) - { - _MMU_write32(dst, T1ReadLong(nds.FW_ARM7BootCode, src)); - src += 4; dst += 4; - } - // Copy secure area to memory if needed if ((header->ARM9src >= 0x4000) && (header->ARM9src < 0x8000)) { src = header->ARM9src; dst = header->ARM9cpy; + u32 size = (0x8000 - src) >> 2; + INFO("Copy secure area from 0x%08X to 0x%08X (size %i/0x%08X)\n", src, dst, size, size); for (u32 i = 0; i < size; i++) { _MMU_write32(dst, T1ReadLong(MMU.CART_ROM, src)); @@ -2618,10 +1958,20 @@ void NDS_Reset() } } - armcpu_init(&NDS_ARM9, nds.FW_ARM9BootCodeAddr); - armcpu_init(&NDS_ARM7, nds.FW_ARM7BootCodeAddr); - //armcpu_init(&NDS_ARM9, 0xFFFF0000); - //armcpu_init(&NDS_ARM7, 0x00000000); + if (firmware->patched) + { + armcpu_init(&NDS_ARM7, 0x00000008); + armcpu_init(&NDS_ARM9, 0xFFFF0008); + } + else + { + //INFO("Booting at ARM9: 0x%08X, ARM7: 0x%08X\n", firmware->ARM9bootAddr, firmware->ARM7bootAddr); + // need for firmware + //armcpu_init(&NDS_ARM7, 0x00000008); + //armcpu_init(&NDS_ARM9, 0xFFFF0008); + armcpu_init(&NDS_ARM7, firmware->ARM7bootAddr); + armcpu_init(&NDS_ARM9, firmware->ARM9bootAddr); + } } else { @@ -2686,9 +2036,8 @@ void NDS_Reset() // Reference: http://nocash.emubase.de/gbatek.htm#dscartridgeheader //zero 27-jun-09 : why did this copy 0x90 more? gbatek says its not stored in ram. //for (i = 0; i < ((0x170+0x90)/4); i++) { - for (int i = 0; i < ((0x170)/4); i++) { + for (int i = 0; i < ((0x170)/4); i++) _MMU_write32(0x027FFE00+i*4, LE_TO_LOCAL_32(((u32*)MMU.CART_ROM)[i])); - } // Write the header checksum to memory (the firmware needs it to see the cart) _MMU_write16(0x027FF808, T1ReadWord(MMU.CART_ROM, 0x15E)); @@ -2716,6 +2065,13 @@ void NDS_Reset() _MMU_write08(kCommandline+rompath.size(), 0); //-------------------------------- + if ((firmware->patched) && (CommonSettings.UseExtBIOS == true) && (CommonSettings.BootFromFirmware == true) && (fw_success == TRUE)) + { + // HACK! for flashme + _MMU_write32(0x27FFE24, firmware->ARM9bootAddr); + _MMU_write32(0x27FFE34, firmware->ARM7bootAddr); + } + // Save touchscreen calibration info in a structure // so we can easily access it at any time diff --git a/desmume/src/NDSSystem.h b/desmume/src/NDSSystem.h index 38c74b091..e239c787a 100644 --- a/desmume/src/NDSSystem.h +++ b/desmume/src/NDSSystem.h @@ -260,8 +260,6 @@ int NDS_Init ( void); void Desmume_InitOnce(); void NDS_DeInit(void); -void -NDS_FillDefaultFirmwareConfigData( struct NDS_fw_config_data *fw_config); BOOL NDS_SetROM(u8 * rom, u32 mask); NDS_header * NDS_getROMHeader(void); @@ -377,7 +375,6 @@ void nds_savestate(EMUFILE* os); bool nds_loadstate(EMUFILE* is, int size); int NDS_WriteBMP(const char *filename); -int NDS_LoadFirmware(const char *filename); int NDS_CreateDummyFirmware( struct NDS_fw_config_data *user_settings); void NDS_Sleep(); diff --git a/desmume/src/firmware.cpp b/desmume/src/firmware.cpp new file mode 100644 index 000000000..6c5c9c871 --- /dev/null +++ b/desmume/src/firmware.cpp @@ -0,0 +1,804 @@ +/* Copyright (C) 2009 DeSmuME Team + + This file is part of DeSmuME + + DeSmuME 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. + + DeSmuME 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 DeSmuME; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "firmware.h" +#include "NDSSystem.h" + +//#define _FLASHME_SUPPORT // bugged + +#define DWNUM(i) ((i) >> 2) + +bool CFIRMWARE::getKeyBuf() +{ + FILE *file = fopen(CommonSettings.ARM7BIOS, "rb"); + if (!file) return false; + + fseek(file, 0x30, SEEK_SET); + size_t res = fread(keyBuf, 4, 0x412, file); + fclose(file); + return (res == 0x412); +} + +void CFIRMWARE::crypt64BitUp(u32 *ptr) +{ + u32 Y = ptr[0]; + u32 X = ptr[1]; + + for(u32 i = 0x00; i <= 0x0F; i++) + { + u32 Z = (keyBuf[i] ^ X); + X = keyBuf[DWNUM(0x048 + (((Z >> 24) & 0xFF) << 2))]; + X = (keyBuf[DWNUM(0x448 + (((Z >> 16) & 0xFF) << 2))] + X); + X = (keyBuf[DWNUM(0x848 + (((Z >> 8) & 0xFF) << 2))] ^ X); + X = (keyBuf[DWNUM(0xC48 + ((Z & 0xFF) << 2))] + X); + X = (Y ^ X); + Y = Z; + } + + ptr[0] = (X ^ keyBuf[DWNUM(0x40)]); + ptr[1] = (Y ^ keyBuf[DWNUM(0x44)]); +} + +void CFIRMWARE::crypt64BitDown(u32 *ptr) +{ + u32 Y = ptr[0]; + u32 X = ptr[1]; + + for(u32 i = 0x11; i >= 0x02; i--) + { + u32 Z = (keyBuf[i] ^ X); + X = keyBuf[DWNUM(0x048 + (((Z >> 24) & 0xFF) << 2))]; + X = (keyBuf[DWNUM(0x448 + (((Z >> 16) & 0xFF) << 2))] + X); + X = (keyBuf[DWNUM(0x848 + (((Z >> 8) & 0xFF) << 2))] ^ X); + X = (keyBuf[DWNUM(0xC48 + ((Z & 0xFF) << 2))] + X); + X = (Y ^ X); + Y = Z; + } + + ptr[0] = (X ^ keyBuf[DWNUM(0x04)]); + ptr[1] = (Y ^ keyBuf[DWNUM(0x00)]); +} + +#define bswap32(val) (((val & 0x000000FF) << 24) | ((val & 0x0000FF00) << 8) | ((val & 0x00FF0000) >> 8) | ((val & 0xFF000000) >> 24)) +void CFIRMWARE::applyKeycode(u32 modulo) +{ + crypt64BitUp(&keyCode[1]); + crypt64BitUp(&keyCode[0]); + + u32 scratch[2] = {0x00000000, 0x00000000}; + + for(u32 i = 0; i <= 0x44; i += 4) + { + keyBuf[DWNUM(i)] = (keyBuf[DWNUM(i)] ^ bswap32(keyCode[DWNUM(i % modulo)])); + } + + for(u32 i = 0; i <= 0x1040; i += 8) + { + crypt64BitUp(scratch); + keyBuf[DWNUM(i)] = scratch[1]; + keyBuf[DWNUM(i+4)] = scratch[0]; + } +} +#undef bswap32 + +bool CFIRMWARE::initKeycode(u32 idCode, int level, u32 modulo) +{ + if(getKeyBuf() == FALSE) + return FALSE; + + keyCode[0] = idCode; + keyCode[1] = (idCode >> 1); + keyCode[2] = (idCode << 1); + + if(level >= 1) applyKeycode(modulo); + if(level >= 2) applyKeycode(modulo); + + keyCode[1] <<= 1; + keyCode[2] >>= 1; + + if(level >= 3) applyKeycode(modulo); + + return TRUE; +} + +// TODO +u16 CFIRMWARE::getBootCodeCRC16() +{ + unsigned int i, j; + u32 crc = 0xFFFF; + const u16 val[8] = {0xC0C1, 0xC181, 0xC301, 0xC601, 0xCC01, 0xD801, 0xF001, 0xA001}; + + for(i = 0; i < size9; i++) + { + crc = (crc ^ tmp_data9[i]); + + for(j = 0; j < 8; j++) + { + if(crc & 0x0001) + crc = ((crc >> 1) ^ (val[j] << (7-j))); + else + crc = (crc >> 1); + } + } + + for(i = 0; i < size7; i++) + { + crc = (crc ^ tmp_data7[i]); + + for(j = 0; j < 8; j++) + { + if(crc & 0x0001) + crc = ((crc >> 1) ^ (val[j] << (7-j))); + else + crc = (crc >> 1); + } + } + + return (crc & 0xFFFF); +} + +u32 CFIRMWARE::decrypt(const u8 *in, u8* &out) +{ + u32 curBlock[2] = { 0 }; + u32 blockSize = 0; + u32 xLen = 0; + + u32 i = 0, j = 0; + u32 xIn = 4, xOut = 0; + u32 len = 0; + u32 offset = 0; + u32 windowOffset = 0; + u8 d = 0; + u16 data = 0; + + memcpy(curBlock, in, 8); + crypt64BitDown(curBlock); + blockSize = (curBlock[0] >> 8); + + if (blockSize == 0) return (0); + + out = new u8 [blockSize]; + if (!out ) return (0); + memset(out, 0xFF, blockSize); + + xLen = blockSize; + while(xLen > 0) + { + d = T1ReadByte((u8*)curBlock, (xIn % 8)); + xIn++; + if((xIn % 8) == 0) + { + memcpy(curBlock, in + xIn, 8); + crypt64BitDown(curBlock); + } + + for(i = 0; i < 8; i++) + { + if(d & 0x80) + { + data = (T1ReadByte((u8*)curBlock, (xIn % 8)) << 8); + xIn++; + if((xIn % 8) == 0) + { + memcpy(curBlock, in + xIn, 8); + crypt64BitDown(curBlock); + } + data |= T1ReadByte((u8*)curBlock, (xIn % 8)); + xIn++; + if((xIn % 8) == 0) + { + memcpy(curBlock, in + xIn, 8); + crypt64BitDown(curBlock); + } + + len = (data >> 12) + 3; + offset = (data & 0xFFF); + windowOffset = (xOut - offset - 1); + + for(j = 0; j < len; j++) + { + T1WriteByte(out, xOut, T1ReadByte(out, windowOffset)); + xOut++; + windowOffset++; + + xLen--; + if(xLen == 0) return (blockSize); + } + } + else + { + T1WriteByte(out, xOut, T1ReadByte((u8*)curBlock, (xIn % 8))); + xOut++; + xIn++; + if((xIn % 8) == 0) + { + memcpy(curBlock, in + xIn, 8); + crypt64BitDown(curBlock); + } + + xLen--; + if(xLen == 0) return (blockSize); + } + + d = ((d << 1) & 0xFF); + } + } + + return (blockSize); +} + +u32 CFIRMWARE::decompress(const u8 *in, u8* &out) +{ + u32 curBlock[2] = { 0 }; + u32 blockSize = 0; + u32 xLen = 0; + + u32 i = 0, j = 0; + u32 xIn = 4, xOut = 0; + u32 len = 0; + u32 offset = 0; + u32 windowOffset = 0; + u8 d = 0; + u16 data = 0; + + memcpy(curBlock, in, 8); + blockSize = (curBlock[0] >> 8); + + if (blockSize == 0) return (0); + + out = new u8 [blockSize]; + if (!out ) return (0); + memset(out, 0xFF, blockSize); + + xLen = blockSize; + while(xLen > 0) + { + d = T1ReadByte((u8*)curBlock, (xIn % 8)); + xIn++; + if((xIn % 8) == 0) + { + memcpy(curBlock, in + xIn, 8); + } + + for(i = 0; i < 8; i++) + { + if(d & 0x80) + { + data = (T1ReadByte((u8*)curBlock, (xIn % 8)) << 8); + xIn++; + if((xIn % 8) == 0) + { + memcpy(curBlock, in + xIn, 8); + } + data |= T1ReadByte((u8*)curBlock, (xIn % 8)); + xIn++; + if((xIn % 8) == 0) + { + memcpy(curBlock, in + xIn, 8); + } + + len = (data >> 12) + 3; + offset = (data & 0xFFF); + windowOffset = (xOut - offset - 1); + + for(j = 0; j < len; j++) + { + T1WriteByte(out, xOut, T1ReadByte(out, windowOffset)); + xOut++; + windowOffset++; + + xLen--; + if(xLen == 0) return (blockSize); + } + } + else + { + T1WriteByte(out, xOut, T1ReadByte((u8*)curBlock, (xIn % 8))); + xOut++; + xIn++; + if((xIn % 8) == 0) + { + memcpy(curBlock, in + xIn, 8); + } + + xLen--; + if(xLen == 0) return (blockSize); + } + + d = ((d << 1) & 0xFF); + } + } + + return (blockSize); +} +//================================================================================ +bool CFIRMWARE::load() +{ + u32 size = 0; + u8 *data = NULL; + u16 shift1 = 0, shift2 = 0, shift3 = 0, shift4 = 0; + u32 part1addr = 0, part2addr = 0, part3addr = 0, part4addr = 0, part5addr = 0; + u32 part1ram = 0, part2ram = 0; + + u32 src = 0; + + if (CommonSettings.UseExtFirmware == false) return false; + if (strlen(CommonSettings.Firmware) == 0) return false; + + FILE *fp = fopen(CommonSettings.Firmware, "rb"); + if (!fp) return false; + fseek(fp, 0, SEEK_END); + size = ftell(fp); + fseek(fp, 0, SEEK_SET); + if( (size != 256*1024) && (size != 512*1024) ) + { + fclose(fp); + return false; + } + data = new u8 [size]; + if (!data) { fclose(fp); return false; } + if (fread(data, 1, size, fp) != size) { delete [] data; fclose(fp); return false; } + + memcpy(&header, data, sizeof(header)); + if ((header.fw_identifier[0] != 'M') || + (header.fw_identifier[1] != 'A') || + (header.fw_identifier[2] != 'C')) { delete [] data; fclose(fp); return false; } + + shift1 = ((header.shift_amounts >> 0) & 0x07); + shift2 = ((header.shift_amounts >> 3) & 0x07); + shift3 = ((header.shift_amounts >> 6) & 0x07); + shift4 = ((header.shift_amounts >> 9) & 0x07); + + // todo - add support for 512Kb + part1addr = (header.part1_rom_boot9_addr << (2 + shift1)); + part1ram = (0x02800000 - (header.part1_ram_boot9_addr << (2+shift2))); + part2addr = (header.part2_rom_boot7_addr << (2+shift3)); + part2ram = (0x03810000 - (header.part2_ram_boot7_addr << (2+shift4))); + part3addr = (header.part3_rom_gui9_addr << 3); + part4addr = (header.part4_rom_wifi7_addr << 3); + part5addr = (header.part5_data_gfx_addr << 3); + + ARM9bootAddr = part1ram; + ARM7bootAddr = part2ram; + + if(initKeycode(T1ReadLong(data, 0x08), 1, 0xC) == FALSE) { delete [] data; fclose(fp); return false; }; + crypt64BitDown((u32*)&data[0x18]); + if(initKeycode(T1ReadLong(data, 0x08), 2, 0xC) == FALSE) { delete [] data; fclose(fp); return false; }; + + size9 = decrypt(data + part1addr, tmp_data9); + if (!tmp_data9) { delete [] data; fclose(fp); return false; }; + + size7 = decrypt(data + part2addr, tmp_data7); + if (!tmp_data7) { delete [] tmp_data9; delete [] data; fclose(fp); return false; }; + + u16 crc16_mine = getBootCodeCRC16(); + + if (crc16_mine != header.part12_boot_crc16) + { + INFO("Firmware: ERROR: the boot code CRC16 (0x%04X) doesn't match the value in the firmware header (0x%04X)", crc16_mine, header.part12_boot_crc16); + delete [] tmp_data9; delete [] tmp_data7; delete [] data; fclose(fp); + return false; + } + // Copy firmware boot codes to their respective locations + src = 0; + for(u32 i = 0; i < (size9 >> 2); i++) + { + _MMU_write32(part1ram, T1ReadLong(tmp_data9, src)); + src += 4; part1ram += 4; + } + + src = 0; + for(u32 i = 0; i < (size7 >> 2); i++) + { + _MMU_write32(part2ram, T1ReadLong(tmp_data7, src)); + src += 4; part2ram += 4; + } + delete [] tmp_data7; + delete [] tmp_data9; + + patched = false; + if (data[0x17C] != 0xFF) + { +#ifdef _FLASHME_SUPPORT + patched = true; +#else + INFO("!!! ERROR: Firmware patched with 'Flashme' v"); + if (data[0x17C] == 1) INFO("1..4"); + else + INFO("%i", (u16)data[0x3F7FC] + 3); + INFO(" - not support\n"); + return false; +#endif + } + + INFO("Firmware:\n"); + INFO("- path: %s\n", CommonSettings.Firmware); + INFO("- size: %i bytes (%i Mbit)\n", size, size/1024/8); + INFO("- CRC : 0x%04X\n", header.part12_boot_crc16); + INFO("- header: \n"); + INFO(" * size firmware %i\n", ((header.shift_amounts >> 12) & 0xF) * 128 * 1024); + INFO(" * ARM9 boot code address: 0x%08X\n", part1addr); + INFO(" * ARM9 boot code RAM address: 0x%08X\n", ARM9bootAddr); + INFO(" * ARM9 unpacked size: 0x%08X (%i) bytes\n", size9, size9); + INFO(" * ARM9 GUI code address: 0x%08X\n", part3addr); + INFO("\n"); + INFO(" * ARM7 boot code address: 0x%08X\n", part2addr); + INFO(" * ARM7 boot code RAM address: 0x%08X\n", ARM7bootAddr); + INFO(" * ARM7 WiFi code address: 0x%08X\n", part4addr); + INFO(" * ARM7 unpacked size: 0x%08X (%i) bytes\n", size7, size7); + INFO("\n"); + INFO(" * Data/GFX address: 0x%08X\n", part5addr); + +#ifdef _FLASHME_SUPPORT + if (patched) + { + u32 patch_offset = 0x3FC80; + if (data[0x17C] > 1) + patch_offset = 0x3F680; + + memcpy(&header, data + patch_offset, sizeof(header)); + + shift1 = ((header.shift_amounts >> 0) & 0x07); + shift2 = ((header.shift_amounts >> 3) & 0x07); + shift3 = ((header.shift_amounts >> 6) & 0x07); + shift4 = ((header.shift_amounts >> 9) & 0x07); + + // todo - add support for 512Kb + part1addr = (header.part1_rom_boot9_addr << (2 + shift1)); + part1ram = (0x02800000 - (header.part1_ram_boot9_addr << (2+shift2))); + part2addr = (header.part2_rom_boot7_addr << (2+shift3)); + part2ram = (0x03810000 - (header.part2_ram_boot7_addr << (2+shift4))); + + ARM9bootAddr = part1ram; + ARM7bootAddr = part2ram; + + size9 = decompress(data + part1addr, tmp_data9); + if (!tmp_data9) { delete [] data; fclose(fp); return false; }; + + size7 = decompress(data + part2addr, tmp_data7); + if (!tmp_data7) { delete [] tmp_data9; delete [] data; fclose(fp); return false; }; + // Copy firmware boot codes to their respective locations + src = 0; + for(u32 i = 0; i < (size9 >> 2); i++) + { + _MMU_write32(part1ram, T1ReadLong(tmp_data9, src)); + src += 4; part1ram += 4; + } + + src = 0; + for(u32 i = 0; i < (size7 >> 2); i++) + { + _MMU_write32(part2ram, T1ReadLong(tmp_data7, src)); + src += 4; part2ram += 4; + } + delete [] tmp_data7; + delete [] tmp_data9; + + INFO("\nFlashme:\n"); + INFO("- header: \n"); + INFO(" * ARM9 boot code address: 0x%08X\n", part1addr); + INFO(" * ARM9 boot code RAM address: 0x%08X\n", ARM9bootAddr); + INFO(" * ARM9 unpacked size: 0x%08X (%i) bytes\n", size9, size9); + INFO("\n"); + INFO(" * ARM7 boot code address: 0x%08X\n", part2addr); + INFO(" * ARM7 boot code RAM address: 0x%08X\n", ARM7bootAddr); + INFO(" * ARM7 unpacked size: 0x%08X (%i) bytes\n", size7, size7); + } +#endif + + // TODO: add 512Kb support + memcpy(MMU.fw.data, data, 256*1024); + + delete [] data; data = NULL; + return true; +} + + +//===================================================================================================== +static u32 +calc_CRC16( u32 start, const u8 *data, int count) { + int i,j; + u32 crc = start & 0xffff; + const u16 val[8] = { 0xC0C1,0xC181,0xC301,0xC601,0xCC01,0xD801,0xF001,0xA001 }; + for(i = 0; i < count; i++) + { + crc = crc ^ data[i]; + + for(j = 0; j < 8; j++) { + int do_bit = 0; + + if ( crc & 0x1) + do_bit = 1; + + crc = crc >> 1; + + if ( do_bit) { + crc = crc ^ (val[j] << (7-j)); + } + } + } + return crc; +} + +int copy_firmware_user_data( u8 *dest_buffer, const u8 *fw_data) +{ + /* + * Determine which of the two user settings in the firmware is the current + * and valid one and then copy this into the destination buffer. + * + * The current setting will have a greater count. + * Settings are only valid if its CRC16 is correct. + */ + int user1_valid = 0; + int user2_valid = 0; + u32 user_settings_offset; + u32 fw_crc; + u32 crc; + int copy_good = 0; + + user_settings_offset = fw_data[0x20]; + user_settings_offset |= fw_data[0x21] << 8; + user_settings_offset <<= 3; + + if ( user_settings_offset <= 0x3FE00) { + s32 copy_settings_offset = -1; + + crc = calc_CRC16( 0xffff, &fw_data[user_settings_offset], + NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT); + fw_crc = fw_data[user_settings_offset + 0x72]; + fw_crc |= fw_data[user_settings_offset + 0x73] << 8; + if ( crc == fw_crc) { + user1_valid = 1; + } + + crc = calc_CRC16( 0xffff, &fw_data[user_settings_offset + 0x100], + NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT); + fw_crc = fw_data[user_settings_offset + 0x100 + 0x72]; + fw_crc |= fw_data[user_settings_offset + 0x100 + 0x73] << 8; + if ( crc == fw_crc) { + user2_valid = 1; + } + + if ( user1_valid) { + if ( user2_valid) { + u16 count1, count2; + + count1 = fw_data[user_settings_offset + 0x70]; + count1 |= fw_data[user_settings_offset + 0x71] << 8; + + count2 = fw_data[user_settings_offset + 0x100 + 0x70]; + count2 |= fw_data[user_settings_offset + 0x100 + 0x71] << 8; + + if ( count2 > count1) { + copy_settings_offset = user_settings_offset + 0x100; + } + else { + copy_settings_offset = user_settings_offset; + } + } + else { + copy_settings_offset = user_settings_offset; + } + } + else if ( user2_valid) { + /* copy the second user settings */ + copy_settings_offset = user_settings_offset + 0x100; + } + + if ( copy_settings_offset > 0) { + memcpy( dest_buffer, &fw_data[copy_settings_offset], + NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT); + copy_good = 1; + } + } + + return copy_good; +} + +static void fill_user_data_area( struct NDS_fw_config_data *user_settings,u8 *data, int count) +{ + u32 crc; + int i; + u8 *ts_cal_data_area; + + memset( data, 0, 0x100); + + // version + data[0x00] = 5; + data[0x01] = 0; + + // colour + data[0x02] = user_settings->fav_colour; + + // birthday month and day + data[0x03] = user_settings->birth_month; + data[0x04] = user_settings->birth_day; + + //nickname and length + for ( i = 0; i < MAX_FW_NICKNAME_LENGTH; i++) { + data[0x06 + (i * 2)] = user_settings->nickname[i] & 0xff; + data[0x06 + (i * 2) + 1] = (user_settings->nickname[i] >> 8) & 0xff; + } + + data[0x1a] = user_settings->nickname_len; + + //Message + for ( i = 0; i < MAX_FW_MESSAGE_LENGTH; i++) { + data[0x1c + (i * 2)] = user_settings->message[i] & 0xff; + data[0x1c + (i * 2) + 1] = (user_settings->message[i] >> 8) & 0xff; + } + + data[0x50] = user_settings->message_len; + + //touch screen calibration + ts_cal_data_area = &data[0x58]; + for ( i = 0; i < 2; i++) { + // ADC x y + *ts_cal_data_area++ = user_settings->touch_cal[i].adc_x & 0xff; + *ts_cal_data_area++ = (user_settings->touch_cal[i].adc_x >> 8) & 0xff; + *ts_cal_data_area++ = user_settings->touch_cal[i].adc_y & 0xff; + *ts_cal_data_area++ = (user_settings->touch_cal[i].adc_y >> 8) & 0xff; + + //screen x y + *ts_cal_data_area++ = user_settings->touch_cal[i].screen_x; + *ts_cal_data_area++ = user_settings->touch_cal[i].screen_y; + } + + //language and flags + data[0x64] = user_settings->language; + data[0x65] = 0xfc; + + //update count and crc + data[0x70] = count & 0xff; + data[0x71] = (count >> 8) & 0xff; + + crc = calc_CRC16( 0xffff, data, 0x70); + data[0x72] = crc & 0xff; + data[0x73] = (crc >> 8) & 0xff; + + memset( &data[0x74], 0xff, 0x100 - 0x74); +} + +// creates an firmware flash image, which contains all needed info to initiate a wifi connection +int NDS_CreateDummyFirmware( struct NDS_fw_config_data *user_settings) +{ + //Create the firmware header + + memset( MMU.fw.data, 0, 0x40000); + + //firmware identifier + MMU.fw.data[0x8] = 'M'; + MMU.fw.data[0x8 + 1] = 'A'; + MMU.fw.data[0x8 + 2] = 'C'; + MMU.fw.data[0x8 + 3] = 'P'; + + // DS type + if ( user_settings->ds_type == NDS_FW_DS_TYPE_LITE) + MMU.fw.data[0x1d] = 0x20; + else + MMU.fw.data[0x1d] = 0xff; + + //User Settings offset 0x3fe00 / 8 + MMU.fw.data[0x20] = 0xc0; + MMU.fw.data[0x21] = 0x7f; + + + //User settings (at 0x3FE00 and 0x3FF00) + + fill_user_data_area( user_settings, &MMU.fw.data[ 0x3FE00], 0); + fill_user_data_area( user_settings, &MMU.fw.data[ 0x3FF00], 1); + + // Wifi config length + MMU.fw.data[0x2C] = 0x38; + MMU.fw.data[0x2D] = 0x01; + + MMU.fw.data[0x2E] = 0x00; + + //Wifi version + MMU.fw.data[0x2F] = 0x00; + + //MAC address + memcpy((MMU.fw.data + 0x36), FW_Mac, sizeof(FW_Mac)); + + //Enabled channels + MMU.fw.data[0x3C] = 0xFE; + MMU.fw.data[0x3D] = 0x3F; + + MMU.fw.data[0x3E] = 0xFF; + MMU.fw.data[0x3F] = 0xFF; + + //RF related + MMU.fw.data[0x40] = 0x02; + MMU.fw.data[0x41] = 0x18; + MMU.fw.data[0x42] = 0x0C; + + MMU.fw.data[0x43] = 0x01; + + //Wifi I/O init values + memcpy((MMU.fw.data + 0x44), FW_WIFIInit, sizeof(FW_WIFIInit)); + + //Wifi BB init values + memcpy((MMU.fw.data + 0x64), FW_BBInit, sizeof(FW_BBInit)); + + //Wifi RF init values + memcpy((MMU.fw.data + 0xCE), FW_RFInit, sizeof(FW_RFInit)); + + //Wifi channel-related init values + memcpy((MMU.fw.data + 0xF2), FW_RFChannel, sizeof(FW_RFChannel)); + memcpy((MMU.fw.data + 0x146), FW_BBChannel, sizeof(FW_BBChannel)); + memset((MMU.fw.data + 0x154), 0x10, 0xE); + + //WFC profiles + memcpy((MMU.fw.data + 0x3FA40), &FW_WFCProfile1, sizeof(FW_WFCProfile)); + memcpy((MMU.fw.data + 0x3FB40), &FW_WFCProfile2, sizeof(FW_WFCProfile)); + memcpy((MMU.fw.data + 0x3FC40), &FW_WFCProfile3, sizeof(FW_WFCProfile)); + (*(u16*)(MMU.fw.data + 0x3FAFE)) = (u16)calc_CRC16(0, (MMU.fw.data + 0x3FA00), 0xFE); + (*(u16*)(MMU.fw.data + 0x3FBFE)) = (u16)calc_CRC16(0, (MMU.fw.data + 0x3FB00), 0xFE); + (*(u16*)(MMU.fw.data + 0x3FCFE)) = (u16)calc_CRC16(0, (MMU.fw.data + 0x3FC00), 0xFE); + + + MMU.fw.data[0x162] = 0x19; + memset((MMU.fw.data + 0x163), 0xFF, 0x9D); + + //Wifi settings CRC16 + (*(u16*)(MMU.fw.data + 0x2A)) = calc_CRC16(0, (MMU.fw.data + 0x2C), 0x138); + + return TRUE ; +} + +void NDS_FillDefaultFirmwareConfigData( struct NDS_fw_config_data *fw_config) { + const char *default_nickname = "DeSmuME"; + const char *default_message = "DeSmuME makes you happy!"; + int i; + int str_length; + + memset( fw_config, 0, sizeof( struct NDS_fw_config_data)); + fw_config->ds_type = NDS_FW_DS_TYPE_FAT; + + fw_config->fav_colour = 7; + + fw_config->birth_day = 23; + fw_config->birth_month = 6; + + str_length = strlen( default_nickname); + for ( i = 0; i < str_length; i++) { + fw_config->nickname[i] = default_nickname[i]; + } + fw_config->nickname_len = str_length; + + str_length = strlen( default_message); + for ( i = 0; i < str_length; i++) { + fw_config->message[i] = default_message[i]; + } + fw_config->message_len = str_length; + + /* default to English */ + fw_config->language = 1; + + /* default touchscreen calibration */ + fw_config->touch_cal[0].adc_x = 0x200; + fw_config->touch_cal[0].adc_y = 0x200; + fw_config->touch_cal[0].screen_x = 0x20 + 1; // calibration screen coords are 1-based, + fw_config->touch_cal[0].screen_y = 0x20 + 1; // either that or NDS_getADCTouchPosX/Y are wrong. + + fw_config->touch_cal[1].adc_x = 0xe00; + fw_config->touch_cal[1].adc_y = 0x800; + fw_config->touch_cal[1].screen_x = 0xe0 + 1; + fw_config->touch_cal[1].screen_y = 0x80 + 1; +} \ No newline at end of file diff --git a/desmume/src/firmware.h b/desmume/src/firmware.h new file mode 100644 index 000000000..6d4f8dd6f --- /dev/null +++ b/desmume/src/firmware.h @@ -0,0 +1,84 @@ +/* Copyright (C) 2009 DeSmuME Team + + This file is part of DeSmuME + + DeSmuME 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. + + DeSmuME 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 DeSmuME; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _FIRMWARE_H_ +#define _FIRMWARE_H_ +#include "common.h" + +// the count of bytes copied from the firmware into memory +#define NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT 0x70 + +class CFIRMWARE +{ +private: + u8 *tmp_data9; + u8 *tmp_data7; + u32 size9, size7; + + u32 keyBuf[0x412]; + u32 keyCode[3]; + + bool getKeyBuf(); + void crypt64BitUp(u32 *ptr); + void crypt64BitDown(u32 *ptr); + void applyKeycode(u32 modulo); + bool initKeycode(u32 idCode, int level, u32 modulo); + u16 getBootCodeCRC16(); + u32 decrypt(const u8 *in, u8* &out); + u32 decompress(const u8 *in, u8* &out); + +public: + CFIRMWARE(): ARM9bootAddr(0), ARM7bootAddr(0), size9(0), size7(0), patched(0) {}; + + bool load(); + + struct HEADER + { + u16 part3_rom_gui9_addr; // 000h + u16 part4_rom_wifi7_addr; // 002h + u16 part34_gui_wifi_crc16; // 004h + u16 part12_boot_crc16; // 006h + u8 fw_identifier[4]; // 008h + u16 part1_rom_boot9_addr; // 00Ch + u16 part1_ram_boot9_addr; // 00Eh + u16 part2_rom_boot7_addr; // 010h + u16 part2_ram_boot7_addr; // 012h + u16 shift_amounts; // 014h + u16 part5_data_gfx_addr; // 016h + + u8 fw_timestamp[5]; // 018h + u8 console_type; // 01Dh + u16 unused1; // 01Eh + u16 user_settings_offset; // 020h + u16 unknown1; // 022h + u16 unknown2; // 024h + u16 part5_crc16; // 026h + u16 unused2; // 028h - FFh filled + } header; + + u32 ARM9bootAddr; + u32 ARM7bootAddr; + bool patched; +}; + +extern int copy_firmware_user_data( u8 *dest_buffer, const u8 *fw_data); +extern int NDS_CreateDummyFirmware( struct NDS_fw_config_data *user_settings); +extern void NDS_FillDefaultFirmwareConfigData( struct NDS_fw_config_data *fw_config); + +#endif \ No newline at end of file diff --git a/desmume/src/mc.cpp b/desmume/src/mc.cpp index 3e5301927..0c6406c7f 100644 --- a/desmume/src/mc.cpp +++ b/desmume/src/mc.cpp @@ -117,6 +117,7 @@ u8 *mc_alloc(memory_chip_t *mc, u32 size) buffer = new u8[size]; memset(buffer,0,size); + if (mc->data) delete [] mc->data; mc->data = buffer; if(!buffer) { return NULL; } mc->size = size; diff --git a/desmume/src/windows/DeSmuME_2005.vcproj b/desmume/src/windows/DeSmuME_2005.vcproj index 19bdb8552..7cb7f16c4 100644 --- a/desmume/src/windows/DeSmuME_2005.vcproj +++ b/desmume/src/windows/DeSmuME_2005.vcproj @@ -1418,6 +1418,14 @@ RelativePath=".\filter\filter.h" > + + + + diff --git a/desmume/src/windows/DeSmuME_2008.vcproj b/desmume/src/windows/DeSmuME_2008.vcproj index a65f083b3..31605b992 100644 --- a/desmume/src/windows/DeSmuME_2008.vcproj +++ b/desmume/src/windows/DeSmuME_2008.vcproj @@ -728,6 +728,14 @@ RelativePath="..\FIFO.h" > + + + + diff --git a/desmume/src/windows/main.cpp b/desmume/src/windows/main.cpp index 8f3917a72..9d6466acf 100644 --- a/desmume/src/windows/main.cpp +++ b/desmume/src/windows/main.cpp @@ -89,6 +89,7 @@ #include "directx/ddraw.h" #include "video.h" #include "path.h" +#include "../firmware.h" #include "aggdraw.h" #include "agg2d.h"