From 7335379127f3b39298c57b1a691f1650af31d381 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Tue, 18 Jun 2019 19:00:44 +0200 Subject: HARK HARK HARK --- src/DSi_AES.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/DSi_AES.cpp (limited to 'src/DSi_AES.cpp') diff --git a/src/DSi_AES.cpp b/src/DSi_AES.cpp new file mode 100644 index 0000000..6a524dd --- /dev/null +++ b/src/DSi_AES.cpp @@ -0,0 +1,17 @@ +/* + Copyright 2016-2019 Arisotura + + This file is part of melonDS. + + melonDS 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 3 of the License, or (at your option) + any later version. + + melonDS 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 melonDS. If not, see http://www.gnu.org/licenses/. +*/ -- cgit v1.2.3 From 81dde71ebac19cf9a68dd7a2a41561cbcbfacc68 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Wed, 19 Jun 2019 14:24:49 +0200 Subject: add AES, fix a bunch of bugs we're getting an error screen! wee --- src/ARM.cpp | 37 ------- src/DSi.cpp | 55 ++++++++++ src/DSi.h | 3 + src/DSi_AES.cpp | 303 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/DSi_AES.h | 26 ++++- src/DSi_NDMA.cpp | 21 ++-- src/DSi_SD.cpp | 21 ++-- src/NDS.cpp | 6 +- 8 files changed, 416 insertions(+), 56 deletions(-) (limited to 'src/DSi_AES.cpp') diff --git a/src/ARM.cpp b/src/ARM.cpp index 60dec9a..b7fe3c7 100644 --- a/src/ARM.cpp +++ b/src/ARM.cpp @@ -239,36 +239,6 @@ void ARMv4::JumpTo(u32 addr, bool restorecpsr) else addr &= ~0x1; } - /*if (addr==0x037D4668) printf("MYSTERY START\n"); - if (addr==0x037CA71C) printf("MYSTERY END\n"); - if (addr==0x037CCD68) printf("atomic_store %08X %08X, %08X\n", R[0], R[1], R[15]); - if (addr==0x037CDD00) printf("zog %08X\n", R[15]);*/ - /*if (addr==0x037CDC00) printf("sendcmd %08X %08X\n", R[0], R[15]); - if (addr==0x037CA700) printf("prepare CID, %08X\n", R[15]); - if(addr==0x037D4498) printf("READ SHITTY FIFO. %08X\n", R[15]); - if (addr==0x037CCD68) printf("atomic_store %08X %08X, %08X\n", R[0], R[1], R[15]); - if (addr>=0x037CEE00 && addr<=0x037CEE30) printf("shitty loop: %08X->%08X\n", R[15], addr); - if (R[15]==0x037CCD8C) printf("BERG!!! %08X\n", addr); - if (addr==0x037CD600) printf("XFER IRQ HANDLER\n"); - if (R[15]==0x037CD62C) printf("TERRIBLE HANDLER: %08X\n", addr); - if (addr==0x037CCE24) printf("SD IRQ HANDLER\n"); - if (addr==0x037CCD94) printf("atomic_load %08X %08X, %08X\n", R[0], R[1], R[15]); - if (addr==0x037CEB7C) printf("CHECK CSR RESULT. %08X %08X %08X, %08X\n", R[0], R[1], R[2], R[15]); - if (R[15]==0x037CEC6C) printf("RETURN FROM CSR CHECK: %08X %08X\n", R[0], R[3]+0x38); - if (addr==0x037CB2AC) printf("ZOG!\n"); - if (addr==0x037CB2A0) printf("GONP %08X %08X, %08X\n", R[1]+0x28, R[3]+0x34, R[15]); - if (addr==0x037CCFC0) printf("SDMMC TIMEOUT. %08X\n", R[15]); - if (addr==0x037D68A8) printf("BARKBARKBARK. %08X\n", R[15]); - if (addr==0x037CCF04) printf("BAKAAA\n"); - if (addr==0x037D6988) printf("MORPMORPMORPMORPMORPMORPMORPMORPMORP %08X\n", R[15]); - if (addr==0x37D6904) printf("TIMEOUT FARTORED! %08X, %08X %08X, %08X\n", R[4], R[3], R[12], R[15]); - // TIMEOUT FARTORED! 037E89B8, 00000000 00200BFB, 037D68FC - if (addr==0x037CD660) printf("BRAAAAAAAAAAAP %08X\n", R[15]); - if (addr==0x037CD798) printf("BRAAPP SHATORED. %08X, %08X %08X\n", R[0], R[1], R[2]); - if (addr==0x037CCD34) printf("atomic_and %08X %08X, %08X\n", R[0], R[1], R[15]);*/ - // atomic_and 0400481C 0000FFE7, 037CD850 - - u32 oldregion = R[15] >> 23; u32 newregion = addr >> 23; @@ -607,13 +577,6 @@ void ARMv4::Execute() } else AddCycles_C(); - - /*if (R[15]==0x037CEE18) printf("SHITTY POINTER = %08X\n", R[0]+0x34); - if (R[15]==0x037CEE1C) printf("SHITTY FLAG = %08X\n", R[0]); - if (R[15]==0x037D68F0) printf("TIMESTAMP THING = %08X:%08X, CUR=%08X:%08X, ptr=%08X\n", - R[3], R[12], R[1], R[0], R[4]); - //if (R[15]==0x037CB29C) printf("GLORG!!! %08X\n", R[3]+0x34); 037E8A8C - if (R[15]==0x037CD730) printf("COUNT OF SHITO. %08X %08X\n", R[0], R[2]);*/ } // TODO optimize this shit!!! diff --git a/src/DSi.cpp b/src/DSi.cpp index fc590e1..fd58872 100644 --- a/src/DSi.cpp +++ b/src/DSi.cpp @@ -28,6 +28,7 @@ #include "DSi_NDMA.h" #include "DSi_I2C.h" #include "DSi_SD.h" +#include "DSi_AES.h" namespace NDS @@ -71,6 +72,7 @@ u8 eMMC_CID[16]; bool Init() { if (!DSi_I2C::Init()) return false; + if (!DSi_AES::Init()) return false; NDMAs[0] = new DSi_NDMA(0, 0); NDMAs[1] = new DSi_NDMA(0, 1); @@ -90,6 +92,7 @@ bool Init() void DeInit() { DSi_I2C::DeInit(); + DSi_AES::DeInit(); for (int i = 0; i < 8; i++) delete NDMAs[i]; @@ -110,6 +113,7 @@ void Reset() for (int i = 0; i < 8; i++) NDMAs[i]->Reset(); DSi_I2C::Reset(); + DSi_AES::Reset(); SDMMC->Reset(); SDIO->Reset(); @@ -336,6 +340,24 @@ bool NDMAsRunning(u32 cpu) return false; } +void CheckNDMAs(u32 cpu, u32 mode) +{ + cpu <<= 2; + NDMAs[cpu+0]->StartIfNeeded(mode); + NDMAs[cpu+1]->StartIfNeeded(mode); + NDMAs[cpu+2]->StartIfNeeded(mode); + NDMAs[cpu+3]->StartIfNeeded(mode); +} + +void StopNDMAs(u32 cpu, u32 mode) +{ + cpu <<= 2; + NDMAs[cpu+0]->StopIfNeeded(mode); + NDMAs[cpu+1]->StopIfNeeded(mode); + NDMAs[cpu+2]->StopIfNeeded(mode); + NDMAs[cpu+3]->StopIfNeeded(mode); +} + // new WRAM mapping // TODO: find out what happens upon overlapping slots!! @@ -1097,6 +1119,9 @@ u32 ARM7IORead32(u32 addr) case 0x04004168: return NDMAs[7]->SubblockTimer; case 0x0400416C: return NDMAs[7]->FillData; case 0x04004170: return NDMAs[7]->Cnt; + + case 0x04004400: return DSi_AES::ReadCnt(); + case 0x0400440C: return DSi_AES::ReadOutputFIFO(); } if (addr >= 0x04004800 && addr < 0x04004A00) @@ -1182,6 +1207,36 @@ void ARM7IOWrite32(u32 addr, u32 val) case 0x04004168: NDMAs[7]->SubblockTimer = val & 0x0003FFFF; return; case 0x0400416C: NDMAs[7]->FillData = val; return; case 0x04004170: NDMAs[7]->WriteCnt(val); return; + + case 0x04004400: DSi_AES::WriteCnt(val); return; + case 0x04004404: DSi_AES::WriteBlkCnt(val); return; + case 0x04004408: DSi_AES::WriteInputFIFO(val); return; + } + + if (addr >= 0x04004420 && addr < 0x04004430) + { + addr -= 0x04004420; + DSi_AES::WriteIV(addr, val, 0xFFFFFFFF); + return; + } + if (addr >= 0x04004430 && addr < 0x04004440) + { + addr -= 0x04004430; + DSi_AES::WriteMAC(addr, val, 0xFFFFFFFF); + return; + } + if (addr >= 0x04004440 && addr < 0x04004500) + { + addr -= 0x04004440; + int n = 0; + while (addr > 0x30) { addr -= 0x30; n++; } + + switch (addr >> 4) + { + case 0: DSi_AES::WriteKeyNormal(n, addr&0xF, val, 0xFFFFFFFF); return; + case 1: DSi_AES::WriteKeyX(n, addr&0xF, val, 0xFFFFFFFF); return; + case 2: DSi_AES::WriteKeyY(n, addr&0xF, val, 0xFFFFFFFF); return; + } } if (addr >= 0x04004800 && addr < 0x04004A00) diff --git a/src/DSi.h b/src/DSi.h index 32253a7..642a56a 100644 --- a/src/DSi.h +++ b/src/DSi.h @@ -26,6 +26,7 @@ namespace DSi { extern u8 eMMC_CID[16]; +extern u64 ConsoleID; extern DSi_SDHost* SDMMC; extern DSi_SDHost* SDIO; @@ -41,6 +42,8 @@ bool LoadNAND(); void RunNDMAs(u32 cpu); void StallNDMAs(); bool NDMAsRunning(u32 cpu); +void CheckNDMAs(u32 cpu, u32 mode); +void StopNDMAs(u32 cpu, u32 mode); void MapNWRAM_A(u32 num, u8 val); void MapNWRAM_B(u32 num, u8 val); diff --git a/src/DSi_AES.cpp b/src/DSi_AES.cpp index 6a524dd..8271e3e 100644 --- a/src/DSi_AES.cpp +++ b/src/DSi_AES.cpp @@ -15,3 +15,306 @@ You should have received a copy of the GNU General Public License along with melonDS. If not, see http://www.gnu.org/licenses/. */ + +#include +#include +#include "DSi.h" +#include "DSi_AES.h" +#include "FIFO.h" +#include "tiny-AES-c/aes.hpp" + + +namespace DSi_AES +{ + +u32 Cnt; + +u32 BlkCnt; +u32 RemBlocks; + +u32 InputDMASize, OutputDMASize; +u32 AESMode; + +FIFO* InputFIFO; +FIFO* OutputFIFO; + +u8 IV[16]; + +u8 KeyNormal[4][16]; +u8 KeyX[4][16]; +u8 KeyY[4][16]; + +u8 CurKey[16]; + +AES_ctx Ctx; + + +void Swap16(u8* dst, u8* src) +{ + for (int i = 0; i < 16; i++) + dst[i] = src[15-i]; +} + +void ROL16(u8* val, u32 n) +{ + u32 n_coarse = n >> 3; + u32 n_fine = n & 7; + u8 tmp[16]; + + for (u32 i = 0; i < 16; i++) + { + tmp[i] = val[(i - n_coarse) & 0xF]; + } + + for (u32 i = 0; i < 16; i++) + { + val[i] = (tmp[i] << n_fine) | (tmp[(i - 1) & 0xF] >> (8-n_fine)); + } +} + +#define _printhex(str, size) { for (int z = 0; z < (size); z++) printf("%02X", (str)[z]); printf("\n"); } + + +bool Init() +{ + InputFIFO = new FIFO(16); + OutputFIFO = new FIFO(16); + + const u8 zero[16] = {0}; + AES_init_ctx_iv(&Ctx, zero, zero); + + return true; +} + +void DeInit() +{ + delete InputFIFO; + delete OutputFIFO; +} + +void Reset() +{ + Cnt = 0; + + BlkCnt = 0; + RemBlocks = 0; + + InputDMASize = 0; + OutputDMASize = 0; + AESMode = 0; + + InputFIFO->Clear(); + OutputFIFO->Clear(); + + memset(KeyNormal, 0, sizeof(KeyNormal)); + memset(KeyX, 0, sizeof(KeyX)); + memset(KeyY, 0, sizeof(KeyY)); + + memset(CurKey, 0, sizeof(CurKey)); + + // initialize keys, as per GBAtek + + // slot 3: console-unique eMMC crypto + *(u32*)&KeyX[3][0] = (u32)DSi::ConsoleID; + *(u32*)&KeyX[3][4] = (u32)DSi::ConsoleID ^ 0x24EE6906; + *(u32*)&KeyX[3][8] = (u32)(DSi::ConsoleID >> 32) ^ 0xE65B601D; + *(u32*)&KeyX[3][12] = (u32)(DSi::ConsoleID >> 32); + *(u32*)&KeyY[3][0] = 0x0AB9DC76; + *(u32*)&KeyY[3][4] = 0xBD4DC4D3; + *(u32*)&KeyY[3][8] = 0x202DDD1D; +} + + +void ProcessBlock_CTR() +{ + u8 data[16]; + u8 data_rev[16]; + + *(u32*)&data[0] = InputFIFO->Read(); + *(u32*)&data[4] = InputFIFO->Read(); + *(u32*)&data[8] = InputFIFO->Read(); + *(u32*)&data[12] = InputFIFO->Read(); + + //printf("AES-CTR: INPUT: "); _printhex(data, 16); + + Swap16(data_rev, data); + AES_CTR_xcrypt_buffer(&Ctx, data_rev, 16); + Swap16(data, data_rev); + + //printf("AES-CTR: OUTPUT: "); _printhex(data, 16); + + OutputFIFO->Write(*(u32*)&data[0]); + OutputFIFO->Write(*(u32*)&data[4]); + OutputFIFO->Write(*(u32*)&data[8]); + OutputFIFO->Write(*(u32*)&data[12]); +} + + +u32 ReadCnt() +{ + u32 ret = Cnt; + + ret |= InputFIFO->Level(); + ret |= (OutputFIFO->Level() << 5); + + return ret; +} + +void WriteCnt(u32 val) +{ + u32 oldcnt = Cnt; + Cnt = val & 0xFC1FF000; + + if (val & (1<<10)) InputFIFO->Clear(); + if (val & (1<<11)) OutputFIFO->Clear(); + + u32 dmasize[4] = {4, 8, 12, 16}; + InputDMASize = dmasize[3 - ((val >> 12) & 0x3)]; + OutputDMASize = dmasize[(val >> 14) & 0x3]; + + AESMode = (val >> 28) & 0x3; + if (AESMode < 2) printf("AES-CCM TODO\n"); + + if (val & (1<<24)) + { + u32 slot = (val >> 26) & 0x3; + memcpy(CurKey, KeyNormal[slot], 16); + + //printf("AES: key(%d): ", slot); _printhex(CurKey, 16); + + u8 tmp[16]; + Swap16(tmp, CurKey); + AES_init_ctx(&Ctx, tmp); + } + + if (!(oldcnt & (1<<31)) && (val & (1<<31))) + { + // transfer start (checkme) + RemBlocks = BlkCnt >> 16; + } + + printf("AES CNT: %08X / mode=%d inDMA=%d outDMA=%d blocks=%d\n", + val, AESMode, InputDMASize, OutputDMASize, RemBlocks); +} + +void WriteBlkCnt(u32 val) +{ + BlkCnt = val; +} + +u32 ReadOutputFIFO() +{ + return OutputFIFO->Read(); +} + +void WriteInputFIFO(u32 val) +{ + // TODO: add some delay to processing + + InputFIFO->Write(val); + + if (!(Cnt & (1<<31))) return; + + while (InputFIFO->Level() >= 4 && RemBlocks > 0) + { + switch (AESMode) + { + case 2: + case 3: ProcessBlock_CTR(); break; + default: + // dorp + OutputFIFO->Write(InputFIFO->Read()); + OutputFIFO->Write(InputFIFO->Read()); + OutputFIFO->Write(InputFIFO->Read()); + OutputFIFO->Write(InputFIFO->Read()); + } + + RemBlocks--; + } + + if (OutputFIFO->Level() >= OutputDMASize) + { + // trigger DMA + DSi::CheckNDMAs(1, 0x2B); + } + // TODO: DMA the other way around + + if (RemBlocks == 0) + { + Cnt &= ~(1<<31); + if (Cnt & (1<<30)) NDS::SetIRQ2(NDS::IRQ2_DSi_AES); + } +} + + +void WriteIV(u32 offset, u32 val, u32 mask) +{ + u32 old = *(u32*)&IV[offset]; + + *(u32*)&IV[offset] = (old & ~mask) | (val & mask); + + //printf("AES: IV: "); _printhex(IV, 16); + + u8 tmp[16]; + Swap16(tmp, IV); + AES_ctx_set_iv(&Ctx, tmp); +} + +void WriteMAC(u32 offset, u32 val, u32 mask) +{ + // +} + +void DeriveNormalKey(u32 slot) +{ + const u8 key_const[16] = {0xFF, 0xFE, 0xFB, 0x4E, 0x29, 0x59, 0x02, 0x58, 0x2A, 0x68, 0x0F, 0x5F, 0x1A, 0x4F, 0x3E, 0x79}; + u8 tmp[16]; + + //printf("keyX: "); _printhex(KeyX[slot], 16); + //printf("keyY: "); _printhex(KeyY[slot], 16); + + for (int i = 0; i < 16; i++) + tmp[i] = KeyX[slot][i] ^ KeyY[slot][i]; + + u32 carry = 0; + for (int i = 0; i < 16; i++) + { + u32 res = tmp[i] + key_const[15-i] + carry; + tmp[i] = res & 0xFF; + carry = res >> 8; + } + + ROL16(tmp, 42); + + //printf("derive normalkey %d\n", slot); _printhex(tmp, 16); + + memcpy(KeyNormal[slot], tmp, 16); +} + +void WriteKeyNormal(u32 slot, u32 offset, u32 val, u32 mask) +{ + u32 old = *(u32*)&KeyNormal[slot][offset]; + + *(u32*)&KeyNormal[slot][offset] = (old & ~mask) | (val & mask); +} + +void WriteKeyX(u32 slot, u32 offset, u32 val, u32 mask) +{ + u32 old = *(u32*)&KeyX[slot][offset]; + + *(u32*)&KeyX[slot][offset] = (old & ~mask) | (val & mask); +} + +void WriteKeyY(u32 slot, u32 offset, u32 val, u32 mask) +{ + u32 old = *(u32*)&KeyY[slot][offset]; + + *(u32*)&KeyY[slot][offset] = (old & ~mask) | (val & mask); + + if (offset >= 0xC) + { + DeriveNormalKey(slot); + } +} + +} diff --git a/src/DSi_AES.h b/src/DSi_AES.h index 028523a..7c388f5 100644 --- a/src/DSi_AES.h +++ b/src/DSi_AES.h @@ -19,6 +19,30 @@ #ifndef DSI_AES_H #define DSI_AES_H -// +#include "types.h" + +namespace DSi_AES +{ + +extern u32 Cnt; + +bool Init(); +void DeInit(); +void Reset(); + +u32 ReadCnt(); +void WriteCnt(u32 val); +void WriteBlkCnt(u32 val); + +u32 ReadOutputFIFO(); +void WriteInputFIFO(u32 val); + +void WriteIV(u32 offset, u32 val, u32 mask); +void WriteMAC(u32 offset, u32 val, u32 mask); +void WriteKeyNormal(u32 slot, u32 offset, u32 val, u32 mask); +void WriteKeyX(u32 slot, u32 offset, u32 val, u32 mask); +void WriteKeyY(u32 slot, u32 offset, u32 val, u32 mask); + +} #endif // DSI_AES_H diff --git a/src/DSi_NDMA.cpp b/src/DSi_NDMA.cpp index 7c0b2a1..aed78af 100644 --- a/src/DSi_NDMA.cpp +++ b/src/DSi_NDMA.cpp @@ -99,7 +99,8 @@ void DSi_NDMA::WriteCnt(u32 val) if ((StartMode & 0x1F) == 0x10) Start(); - if (StartMode != 0x10 && StartMode != 0x30) + if (StartMode != 0x10 && StartMode != 0x30 && + StartMode != 0x2B) printf("UNIMPLEMENTED ARM%d NDMA%d START MODE %02X, %08X->%08X\n", CPU?7:9, Num, StartMode, SrcAddr, DstAddr); } } @@ -223,16 +224,19 @@ void DSi_NDMA::Run9() } if ((StartMode & 0x1F) == 0x10) // CHECKME + { Cnt &= ~(1<<31); + if (Cnt & (1<<30)) NDS::SetIRQ(0, NDS::IRQ_DSi_NDMA0 + Num); + } else if (!(Cnt & (1<<29))) { if (TotalRemCount == 0) + { Cnt &= ~(1<<31); + if (Cnt & (1<<30)) NDS::SetIRQ(0, NDS::IRQ_DSi_NDMA0 + Num); + } } - if (Cnt & (1<<30)) - NDS::SetIRQ(0, NDS::IRQ_DSi_NDMA0 + Num); - Running = 0; InProgress = false; NDS::ResumeCPU(0, 1<<(Num+4)); @@ -305,16 +309,19 @@ void DSi_NDMA::Run7() } if ((StartMode & 0x1F) == 0x10) // CHECKME + { Cnt &= ~(1<<31); + if (Cnt & (1<<30)) NDS::SetIRQ(1, NDS::IRQ_DSi_NDMA0 + Num); + } else if (!(Cnt & (1<<29))) { if (TotalRemCount == 0) + { Cnt &= ~(1<<31); + if (Cnt & (1<<30)) NDS::SetIRQ(1, NDS::IRQ_DSi_NDMA0 + Num); + } } - if (Cnt & (1<<30)) - NDS::SetIRQ(1, NDS::IRQ_DSi_NDMA0 + Num); - Running = 0; InProgress = false; NDS::ResumeCPU(1, 1<<(Num+4)); diff --git a/src/DSi_SD.cpp b/src/DSi_SD.cpp index 42b515c..bb3c4a4 100644 --- a/src/DSi_SD.cpp +++ b/src/DSi_SD.cpp @@ -473,10 +473,10 @@ void DSi_MMCStorage::SendCMD(u8 cmd, u32 param) case 2: case 10: // get CID - Host->SendResponse(*(u32*)&CID[0], false); - Host->SendResponse(*(u32*)&CID[1], false); - Host->SendResponse(*(u32*)&CID[2], false); - Host->SendResponse(*(u32*)&CID[3], true); + Host->SendResponse(*(u32*)&CID[12], false); + Host->SendResponse(*(u32*)&CID[8], false); + Host->SendResponse(*(u32*)&CID[4], false); + Host->SendResponse(*(u32*)&CID[0], true); //if (cmd == 2) SetState(0x02); return; @@ -502,13 +502,18 @@ void DSi_MMCStorage::SendCMD(u8 cmd, u32 param) return; case 9: // get CSD - Host->SendResponse(*(u32*)&CSD[0], false); - Host->SendResponse(*(u32*)&CSD[1], false); - Host->SendResponse(*(u32*)&CSD[2], false); - Host->SendResponse(*(u32*)&CSD[3], true); + Host->SendResponse(*(u32*)&CSD[12], false); + Host->SendResponse(*(u32*)&CSD[8], false); + Host->SendResponse(*(u32*)&CSD[4], false); + Host->SendResponse(*(u32*)&CSD[0], true); return; case 12: // stop operation + // TODO + Host->SendResponse(CSR, true); + return; + + case 13: // get status Host->SendResponse(CSR, true); return; diff --git a/src/NDS.cpp b/src/NDS.cpp index e20f62f..7513d57 100644 --- a/src/NDS.cpp +++ b/src/NDS.cpp @@ -1582,12 +1582,12 @@ void debug(u32 param) printf("ARM7 PC=%08X LR=%08X %08X\n", ARM7->R[15], ARM7->R[14], ARM7->R_IRQ[1]); printf("ARM9 IME=%08X IE=%08X IF=%08X\n", IME[0], IE[0], IF[0]); - printf("ARM7 IME=%08X IE=%08X IF=%08X\n", IME[1], IE[1], IF[1]); + printf("ARM7 IME=%08X IE=%08X IF=%08X IE2=%04X IF2=%04X\n", IME[1], IE[1], IF[1], IE2, IF2); //for (int i = 0; i < 9; i++) // printf("VRAM %c: %02X\n", 'A'+i, GPU::VRAMCNT[i]); - FILE* + /*FILE* shit = fopen("debug/card.bin", "wb"); for (u32 i = 0x02000000; i < 0x02400000; i+=4) { @@ -1599,7 +1599,7 @@ void debug(u32 param) u32 val = ARM7Read32(i); fwrite(&val, 4, 1, shit); } - fclose(shit); + fclose(shit);*/ } -- cgit v1.2.3 From 6e5879f8bbf6bf85791b03f36675aa7991ae4771 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Wed, 19 Jun 2019 15:26:38 +0200 Subject: fix more bugs, get further --- src/DSi_AES.cpp | 1 + src/DSi_SD.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'src/DSi_AES.cpp') diff --git a/src/DSi_AES.cpp b/src/DSi_AES.cpp index 8271e3e..1ba690f 100644 --- a/src/DSi_AES.cpp +++ b/src/DSi_AES.cpp @@ -243,6 +243,7 @@ void WriteInputFIFO(u32 val) { Cnt &= ~(1<<31); if (Cnt & (1<<30)) NDS::SetIRQ2(NDS::IRQ2_DSi_AES); + DSi::StopNDMAs(1, 0x2B); } } diff --git a/src/DSi_SD.cpp b/src/DSi_SD.cpp index 9775ca8..4a7fd2e 100644 --- a/src/DSi_SD.cpp +++ b/src/DSi_SD.cpp @@ -477,7 +477,7 @@ void DSi_MMCStorage::SendCMD(u8 cmd, u32 param) Host->SendResponse(*(u32*)&CID[8], false); Host->SendResponse(*(u32*)&CID[4], false); Host->SendResponse(*(u32*)&CID[0], true); - //if (cmd == 2) SetState(0x02); + if (cmd == 2) SetState(0x02); return; case 3: // get/set RCA @@ -509,7 +509,7 @@ void DSi_MMCStorage::SendCMD(u8 cmd, u32 param) return; case 12: // stop operation - // TODO + SetState(0x04); Host->SendResponse(CSR, true); return; @@ -525,6 +525,7 @@ void DSi_MMCStorage::SendCMD(u8 cmd, u32 param) printf("!! SD/MMC: BAD BLOCK LEN %d\n", BlockSize); BlockSize = 0x200; } + SetState(0x04); // CHECKME Host->SendResponse(CSR, true); return; @@ -535,6 +536,7 @@ void DSi_MMCStorage::SendCMD(u8 cmd, u32 param) Host->SendResponse(CSR, true); ReadBlock(RWAddress); RWAddress += BlockSize; + SetState(0x05); return; case 55: // ?? -- cgit v1.2.3 From dcae9788e510e44341b7535c267262b89667720b Mon Sep 17 00:00:00 2001 From: Arisotura Date: Wed, 19 Jun 2019 19:19:51 +0200 Subject: add NDMA start mode 0x0A (AES input FIFO) --- src/DSi_AES.cpp | 22 +++++++++++++++++++--- src/DSi_AES.h | 1 + src/DSi_NDMA.cpp | 8 +++++++- 3 files changed, 27 insertions(+), 4 deletions(-) (limited to 'src/DSi_AES.cpp') diff --git a/src/DSi_AES.cpp b/src/DSi_AES.cpp index 1ba690f..b427dcd 100644 --- a/src/DSi_AES.cpp +++ b/src/DSi_AES.cpp @@ -191,6 +191,8 @@ void WriteCnt(u32 val) { // transfer start (checkme) RemBlocks = BlkCnt >> 16; + + DSi::CheckNDMAs(1, 0x2A); } printf("AES CNT: %08X / mode=%d inDMA=%d outDMA=%d blocks=%d\n", @@ -204,7 +206,8 @@ void WriteBlkCnt(u32 val) u32 ReadOutputFIFO() { - return OutputFIFO->Read(); + u32 ret = OutputFIFO->Read(); + return ret; } void WriteInputFIFO(u32 val) @@ -234,17 +237,30 @@ void WriteInputFIFO(u32 val) if (OutputFIFO->Level() >= OutputDMASize) { - // trigger DMA + // trigger output DMA DSi::CheckNDMAs(1, 0x2B); } - // TODO: DMA the other way around if (RemBlocks == 0) { Cnt &= ~(1<<31); if (Cnt & (1<<30)) NDS::SetIRQ2(NDS::IRQ2_DSi_AES); + DSi::StopNDMAs(1, 0x2A); DSi::StopNDMAs(1, 0x2B); } + else + { + CheckInputDMA(); + } +} + +void CheckInputDMA() +{ + if (InputFIFO->Level() < InputDMASize) + { + // trigger input DMA + DSi::CheckNDMAs(1, 0x2A); + } } diff --git a/src/DSi_AES.h b/src/DSi_AES.h index 7c388f5..77a4400 100644 --- a/src/DSi_AES.h +++ b/src/DSi_AES.h @@ -36,6 +36,7 @@ void WriteBlkCnt(u32 val); u32 ReadOutputFIFO(); void WriteInputFIFO(u32 val); +void CheckInputDMA(); void WriteIV(u32 offset, u32 val, u32 mask); void WriteMAC(u32 offset, u32 val, u32 mask); diff --git a/src/DSi_NDMA.cpp b/src/DSi_NDMA.cpp index aed78af..cd84901 100644 --- a/src/DSi_NDMA.cpp +++ b/src/DSi_NDMA.cpp @@ -21,6 +21,7 @@ #include "DSi.h" #include "DSi_NDMA.h" #include "GPU.h" +#include "DSi_AES.h" @@ -100,7 +101,7 @@ void DSi_NDMA::WriteCnt(u32 val) Start(); if (StartMode != 0x10 && StartMode != 0x30 && - StartMode != 0x2B) + StartMode != 0x2A && StartMode != 0x2B) printf("UNIMPLEMENTED ARM%d NDMA%d START MODE %02X, %08X->%08X\n", CPU?7:9, Num, StartMode, SrcAddr, DstAddr); } } @@ -290,6 +291,7 @@ void DSi_NDMA::Run7() CurDstAddr += DstAddrInc<<2; IterCount--; RemCount--; + TotalRemCount--; if (NDS::ARM7Timestamp >= NDS::ARM7Target) break; } @@ -303,6 +305,8 @@ void DSi_NDMA::Run7() { Running = 0; NDS::ResumeCPU(1, 1<<(Num+4)); + + DSi_AES::CheckInputDMA(); } return; @@ -325,4 +329,6 @@ void DSi_NDMA::Run7() Running = 0; InProgress = false; NDS::ResumeCPU(1, 1<<(Num+4)); + + DSi_AES::CheckInputDMA(); } -- cgit v1.2.3 From 3807c9bf5b19bbea6eb10c12734a17e0c55b4f51 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Wed, 19 Jun 2019 21:57:08 +0200 Subject: combat AES overflowing and/or getting stuck --- src/DSi_AES.cpp | 59 +++++++++++++++++++++++++++++++++++--------------------- src/DSi_AES.h | 2 ++ src/DSi_NDMA.cpp | 4 +++- 3 files changed, 42 insertions(+), 23 deletions(-) (limited to 'src/DSi_AES.cpp') diff --git a/src/DSi_AES.cpp b/src/DSi_AES.cpp index b427dcd..9f48519 100644 --- a/src/DSi_AES.cpp +++ b/src/DSi_AES.cpp @@ -207,6 +207,9 @@ void WriteBlkCnt(u32 val) u32 ReadOutputFIFO() { u32 ret = OutputFIFO->Read(); + + CheckInputDMA(); + CheckOutputDMA(); return ret; } @@ -218,28 +221,7 @@ void WriteInputFIFO(u32 val) if (!(Cnt & (1<<31))) return; - while (InputFIFO->Level() >= 4 && RemBlocks > 0) - { - switch (AESMode) - { - case 2: - case 3: ProcessBlock_CTR(); break; - default: - // dorp - OutputFIFO->Write(InputFIFO->Read()); - OutputFIFO->Write(InputFIFO->Read()); - OutputFIFO->Write(InputFIFO->Read()); - OutputFIFO->Write(InputFIFO->Read()); - } - - RemBlocks--; - } - - if (OutputFIFO->Level() >= OutputDMASize) - { - // trigger output DMA - DSi::CheckNDMAs(1, 0x2B); - } + Update(); if (RemBlocks == 0) { @@ -261,6 +243,39 @@ void CheckInputDMA() // trigger input DMA DSi::CheckNDMAs(1, 0x2A); } + + Update(); +} + +void CheckOutputDMA() +{ + if (OutputFIFO->Level() >= OutputDMASize) + { + // trigger output DMA + DSi::CheckNDMAs(1, 0x2B); + } +} + +void Update() +{ + while (InputFIFO->Level() >= 4 && OutputFIFO->Level() <= 12 && RemBlocks > 0) + { + switch (AESMode) + { + case 2: + case 3: ProcessBlock_CTR(); break; + default: + // dorp + OutputFIFO->Write(InputFIFO->Read()); + OutputFIFO->Write(InputFIFO->Read()); + OutputFIFO->Write(InputFIFO->Read()); + OutputFIFO->Write(InputFIFO->Read()); + } + + RemBlocks--; + } + + CheckOutputDMA(); } diff --git a/src/DSi_AES.h b/src/DSi_AES.h index 77a4400..5e726cd 100644 --- a/src/DSi_AES.h +++ b/src/DSi_AES.h @@ -37,6 +37,8 @@ void WriteBlkCnt(u32 val); u32 ReadOutputFIFO(); void WriteInputFIFO(u32 val); void CheckInputDMA(); +void CheckOutputDMA(); +void Update(); void WriteIV(u32 offset, u32 val, u32 mask); void WriteMAC(u32 offset, u32 val, u32 mask); diff --git a/src/DSi_NDMA.cpp b/src/DSi_NDMA.cpp index cd84901..a62904a 100644 --- a/src/DSi_NDMA.cpp +++ b/src/DSi_NDMA.cpp @@ -129,7 +129,7 @@ void DSi_NDMA::Start() if (Cnt & (1<<12)) CurDstAddr = DstAddr; if (Cnt & (1<<15)) CurSrcAddr = SrcAddr; - printf("ARM%d NDMA%d %08X %02X %08X->%08X %d bytes, total=%d\n", CPU?7:9, Num, Cnt, StartMode, CurSrcAddr, CurDstAddr, RemCount*4, TotalRemCount*4); + //printf("ARM%d NDMA%d %08X %02X %08X->%08X %d bytes, total=%d\n", CPU?7:9, Num, Cnt, StartMode, CurSrcAddr, CurDstAddr, RemCount*4, TotalRemCount*4); //IsGXFIFODMA = (CPU == 0 && (CurSrcAddr>>24) == 0x02 && CurDstAddr == 0x04000400 && DstAddrInc == 0); @@ -307,6 +307,7 @@ void DSi_NDMA::Run7() NDS::ResumeCPU(1, 1<<(Num+4)); DSi_AES::CheckInputDMA(); + DSi_AES::CheckOutputDMA(); } return; @@ -331,4 +332,5 @@ void DSi_NDMA::Run7() NDS::ResumeCPU(1, 1<<(Num+4)); DSi_AES::CheckInputDMA(); + DSi_AES::CheckOutputDMA(); } -- cgit v1.2.3 From 95f4c1472b5c3d08d82b42747da397c19d8916ec Mon Sep 17 00:00:00 2001 From: Arisotura Date: Wed, 19 Jun 2019 22:08:35 +0200 Subject: probably betterer like this --- src/DSi_AES.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'src/DSi_AES.cpp') diff --git a/src/DSi_AES.cpp b/src/DSi_AES.cpp index 9f48519..ced8d1a 100644 --- a/src/DSi_AES.cpp +++ b/src/DSi_AES.cpp @@ -222,18 +222,6 @@ void WriteInputFIFO(u32 val) if (!(Cnt & (1<<31))) return; Update(); - - if (RemBlocks == 0) - { - Cnt &= ~(1<<31); - if (Cnt & (1<<30)) NDS::SetIRQ2(NDS::IRQ2_DSi_AES); - DSi::StopNDMAs(1, 0x2A); - DSi::StopNDMAs(1, 0x2B); - } - else - { - CheckInputDMA(); - } } void CheckInputDMA() @@ -276,6 +264,14 @@ void Update() } CheckOutputDMA(); + + if (RemBlocks == 0) + { + Cnt &= ~(1<<31); + if (Cnt & (1<<30)) NDS::SetIRQ2(NDS::IRQ2_DSi_AES); + DSi::StopNDMAs(1, 0x2A); + DSi::StopNDMAs(1, 0x2B); + } } -- cgit v1.2.3 From 3d9e6c5c669c20893cd65cbbf3f293a315ab2225 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Thu, 20 Jun 2019 01:36:10 +0200 Subject: * fix more AES bugs * fix ass-stupid bug with NWRAM mapping --- src/DSi.cpp | 4 ++-- src/DSi_AES.cpp | 48 +++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 41 insertions(+), 11 deletions(-) (limited to 'src/DSi_AES.cpp') diff --git a/src/DSi.cpp b/src/DSi.cpp index ab76a76..53c7135 100644 --- a/src/DSi.cpp +++ b/src/DSi.cpp @@ -52,8 +52,8 @@ u8 NWRAM_B[0x40000]; u8 NWRAM_C[0x40000]; u8* NWRAMMap_A[2][4]; -u8* NWRAMMap_B[3][4]; -u8* NWRAMMap_C[3][4]; +u8* NWRAMMap_B[3][8]; +u8* NWRAMMap_C[3][8]; u32 NWRAMStart[2][3]; u32 NWRAMEnd[2][3]; diff --git a/src/DSi_AES.cpp b/src/DSi_AES.cpp index ced8d1a..e218315 100644 --- a/src/DSi_AES.cpp +++ b/src/DSi_AES.cpp @@ -32,6 +32,8 @@ u32 Cnt; u32 BlkCnt; u32 RemBlocks; +bool OutputFlush; + u32 InputDMASize, OutputDMASize; u32 AESMode; @@ -73,6 +75,7 @@ void ROL16(u8* val, u32 n) } #define _printhex(str, size) { for (int z = 0; z < (size); z++) printf("%02X", (str)[z]); printf("\n"); } +#define _printhex2(str, size) { for (int z = 0; z < (size); z++) printf("%02X", (str)[z]); } bool Init() @@ -99,6 +102,8 @@ void Reset() BlkCnt = 0; RemBlocks = 0; + OutputFlush = false; + InputDMASize = 0; OutputDMASize = 0; AESMode = 0; @@ -114,6 +119,10 @@ void Reset() // initialize keys, as per GBAtek + // slot 0: modcrypt + *(u32*)&KeyX[0][0] = 0x746E694E; + *(u32*)&KeyX[0][4] = 0x6F646E65; + // slot 3: console-unique eMMC crypto *(u32*)&KeyX[3][0] = (u32)DSi::ConsoleID; *(u32*)&KeyX[3][4] = (u32)DSi::ConsoleID ^ 0x24EE6906; @@ -135,13 +144,13 @@ void ProcessBlock_CTR() *(u32*)&data[8] = InputFIFO->Read(); *(u32*)&data[12] = InputFIFO->Read(); - //printf("AES-CTR: INPUT: "); _printhex(data, 16); + //printf("AES-CTR: "); _printhex2(data, 16); Swap16(data_rev, data); AES_CTR_xcrypt_buffer(&Ctx, data_rev, 16); Swap16(data, data_rev); - //printf("AES-CTR: OUTPUT: "); _printhex(data, 16); + //printf(" -> "); _printhex(data, 16); OutputFIFO->Write(*(u32*)&data[0]); OutputFIFO->Write(*(u32*)&data[4]); @@ -165,8 +174,11 @@ void WriteCnt(u32 val) u32 oldcnt = Cnt; Cnt = val & 0xFC1FF000; - if (val & (1<<10)) InputFIFO->Clear(); - if (val & (1<<11)) OutputFIFO->Clear(); + /*if (val & (3<<10)) + { + if (val & (1<<11)) OutputFlush = true; + Update(); + }*/ u32 dmasize[4] = {4, 8, 12, 16}; InputDMASize = dmasize[3 - ((val >> 12) & 0x3)]; @@ -208,8 +220,19 @@ u32 ReadOutputFIFO() { u32 ret = OutputFIFO->Read(); - CheckInputDMA(); - CheckOutputDMA(); + if (Cnt & (1<<31)) + { + CheckInputDMA(); + CheckOutputDMA(); + } + else + { + if (OutputFIFO->Level() > 0) + DSi::CheckNDMAs(1, 0x2B); + else + DSi::StopNDMAs(1, 0x2B); + } + return ret; } @@ -226,6 +249,8 @@ void WriteInputFIFO(u32 val) void CheckInputDMA() { + if (RemBlocks == 0) return; + if (InputFIFO->Level() < InputDMASize) { // trigger input DMA @@ -270,7 +295,12 @@ void Update() Cnt &= ~(1<<31); if (Cnt & (1<<30)) NDS::SetIRQ2(NDS::IRQ2_DSi_AES); DSi::StopNDMAs(1, 0x2A); - DSi::StopNDMAs(1, 0x2B); + + if (OutputFIFO->Level() > 0) + DSi::CheckNDMAs(1, 0x2B); + else + DSi::StopNDMAs(1, 0x2B); + OutputFlush = false; } } @@ -298,8 +328,8 @@ void DeriveNormalKey(u32 slot) const u8 key_const[16] = {0xFF, 0xFE, 0xFB, 0x4E, 0x29, 0x59, 0x02, 0x58, 0x2A, 0x68, 0x0F, 0x5F, 0x1A, 0x4F, 0x3E, 0x79}; u8 tmp[16]; - //printf("keyX: "); _printhex(KeyX[slot], 16); - //printf("keyY: "); _printhex(KeyY[slot], 16); + //printf("slot%d keyX: ", slot); _printhex(KeyX[slot], 16); + //printf("slot%d keyY: ", slot); _printhex(KeyY[slot], 16); for (int i = 0; i < 16; i++) tmp[i] = KeyX[slot][i] ^ KeyY[slot][i]; -- cgit v1.2.3 From 6c60e97a6312b04771f9a90baf573518eb3572d4 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Thu, 20 Jun 2019 22:42:28 +0200 Subject: fix another AES bug --- src/DSi_AES.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src/DSi_AES.cpp') diff --git a/src/DSi_AES.cpp b/src/DSi_AES.cpp index e218315..7f962fd 100644 --- a/src/DSi_AES.cpp +++ b/src/DSi_AES.cpp @@ -180,9 +180,10 @@ void WriteCnt(u32 val) Update(); }*/ - u32 dmasize[4] = {4, 8, 12, 16}; - InputDMASize = dmasize[3 - ((val >> 12) & 0x3)]; - OutputDMASize = dmasize[(val >> 14) & 0x3]; + u32 dmasize_in[4] = {0, 4, 8, 12}; + u32 dmasize_out[4] = {4, 8, 12, 16}; + InputDMASize = dmasize_in[(val >> 12) & 0x3]; + OutputDMASize = dmasize_out[(val >> 14) & 0x3]; AESMode = (val >> 28) & 0x3; if (AESMode < 2) printf("AES-CCM TODO\n"); @@ -251,7 +252,7 @@ void CheckInputDMA() { if (RemBlocks == 0) return; - if (InputFIFO->Level() < InputDMASize) + if (InputFIFO->Level() <= InputDMASize) { // trigger input DMA DSi::CheckNDMAs(1, 0x2A); -- cgit v1.2.3 From 851e255b4099904b4784fa7e1c672f03e5ca531b Mon Sep 17 00:00:00 2001 From: Arisotura Date: Tue, 2 Jul 2019 23:46:39 +0200 Subject: * AES-CCM decrypt * fix a bunch of bugs --- src/DSi.cpp | 36 +++++++++++++-- src/DSi_AES.cpp | 134 +++++++++++++++++++++++++++++++++++++++++++++++++------ src/DSi_NDMA.cpp | 3 ++ src/DSi_SD.cpp | 23 +++++++--- src/DSi_SD.h | 1 + src/SPU.cpp | 7 ++- 6 files changed, 180 insertions(+), 24 deletions(-) (limited to 'src/DSi_AES.cpp') diff --git a/src/DSi.cpp b/src/DSi.cpp index 8f35d91..e601da9 100644 --- a/src/DSi.cpp +++ b/src/DSi.cpp @@ -44,6 +44,8 @@ namespace DSi u32 BootAddr[2]; +u16 SCFG_Clock9; +u16 SCFG_Clock7; u32 SCFG_MC; u32 MBK[2][9]; @@ -123,11 +125,19 @@ void Reset() SDMMC->Reset(); SDIO->Reset(); + SCFG_Clock9 = 0x0187; // CHECKME + SCFG_Clock7 = 0x0187; SCFG_MC = 0x0011; // LCD init flag GPU::DispStat[0] |= (1<<6); GPU::DispStat[1] |= (1<<6); + + NDS::MapSharedWRAM(3); + + // TEST + u8 derp[16] = {0xE5, 0xCC, 0x5A, 0x8B, 0x56, 0xD0, 0xC9, 0x72, 0x9C, 0x17, 0xE8, 0xDC, 0x39, 0x12, 0x36, 0xA9}; + for (int i = 0; i < 16; i+=4) ARM7Write32(0x03FFC580+i, *(u32*)&derp[i]); } bool LoadBIOS() @@ -1007,7 +1017,7 @@ u16 ARM9IORead16(u32 addr) { switch (addr) { - case 0x04004004: return 0; // TODO + case 0x04004004: return SCFG_Clock9; case 0x04004010: return SCFG_MC & 0xFFFF; CASE_READ16_32BIT(0x04004040, MBK[0][0]) @@ -1079,6 +1089,16 @@ void ARM9IOWrite8(u32 addr, u8 val) { switch (addr) { + case 0x04000301: + // TODO: OPTIONAL PERFORMANCE HACK + // the DSi ARM9 BIOS has a bug where the IRQ wait function attempts to use (ARM7-only) HALTCNT + // effectively causing it to wait in a busy loop. + // for better DSi performance, we can implement an actual IRQ wait here. + // in practice this would only matter when running DS software in DSi mode (ie already a hack). + // DSi software does not use the BIOS IRQ wait function. + //if (val == 0x80 && NDS::ARM9->R[15] == 0xFFFF0268) NDS::ARM9->Halt(1); + return; + case 0x04004040: MapNWRAM_A(0, val); return; case 0x04004041: MapNWRAM_A(1, val); return; case 0x04004042: MapNWRAM_A(2, val); return; @@ -1108,6 +1128,12 @@ void ARM9IOWrite16(u32 addr, u16 val) { switch (addr) { + case 0x04004004: + // TODO: actually change clock! + printf("CLOCK9=%04X\n", val); + SCFG_Clock9 = val & 0x0187; + return; + case 0x04004040: MapNWRAM_A(0, val & 0xFF); MapNWRAM_A(1, val >> 8); @@ -1267,7 +1293,7 @@ u16 ARM7IORead16(u32 addr) case 0x04000218: return NDS::IE2; case 0x0400021C: return NDS::IF2; - case 0x04004004: return 0x0187; + case 0x04004004: return SCFG_Clock7; case 0x04004006: return 0; // JTAG register case 0x04004010: return SCFG_MC & 0xFFFF; @@ -1390,6 +1416,10 @@ void ARM7IOWrite16(u32 addr, u16 val) case 0x04000218: NDS::IE2 = (val & 0x7FF7); NDS::UpdateIRQ(1); return; case 0x0400021C: NDS::IF2 &= ~(val & 0x7FF7); NDS::UpdateIRQ(1); return; + case 0x04004004: + SCFG_Clock7 = val & 0x0187; + return; + case 0x04004010: val &= 0x800C; if ((val & 0xC) == 0xC) val &= ~0xC; // hax @@ -1482,7 +1512,7 @@ void ARM7IOWrite32(u32 addr, u32 val) { addr -= 0x04004440; int n = 0; - while (addr > 0x30) { addr -= 0x30; n++; } + while (addr >= 0x30) { addr -= 0x30; n++; } switch (addr >> 4) { diff --git a/src/DSi_AES.cpp b/src/DSi_AES.cpp index 7f962fd..8ae9082 100644 --- a/src/DSi_AES.cpp +++ b/src/DSi_AES.cpp @@ -42,11 +42,14 @@ FIFO* OutputFIFO; u8 IV[16]; +u8 MAC[16]; + u8 KeyNormal[4][16]; u8 KeyX[4][16]; u8 KeyY[4][16]; u8 CurKey[16]; +u8 CurMAC[16]; AES_ctx Ctx; @@ -77,6 +80,9 @@ void ROL16(u8* val, u32 n) #define _printhex(str, size) { for (int z = 0; z < (size); z++) printf("%02X", (str)[z]); printf("\n"); } #define _printhex2(str, size) { for (int z = 0; z < (size); z++) printf("%02X", (str)[z]); } +#define _printhexR(str, size) { for (int z = 0; z < (size); z++) printf("%02X", (str)[((size)-1)-z]); printf("\n"); } +#define _printhex2R(str, size) { for (int z = 0; z < (size); z++) printf("%02X", (str)[((size)-1)-z]); } + bool Init() { @@ -111,11 +117,16 @@ void Reset() InputFIFO->Clear(); OutputFIFO->Clear(); + memset(IV, 0, sizeof(IV)); + + memset(MAC, 0, sizeof(MAC)); + memset(KeyNormal, 0, sizeof(KeyNormal)); memset(KeyX, 0, sizeof(KeyX)); memset(KeyY, 0, sizeof(KeyY)); memset(CurKey, 0, sizeof(CurKey)); + memset(CurMAC, 0, sizeof(CurMAC)); // initialize keys, as per GBAtek @@ -123,6 +134,12 @@ void Reset() *(u32*)&KeyX[0][0] = 0x746E694E; *(u32*)&KeyX[0][4] = 0x6F646E65; + // slot 1: 'Tad'/dev.kp + *(u32*)&KeyX[1][0] = 0x4E00004A; + *(u32*)&KeyX[1][4] = 0x4A00004E; + *(u32*)&KeyX[1][8] = (u32)(DSi::ConsoleID >> 32) ^ 0xC80C4B72; + *(u32*)&KeyX[1][12] = (u32)DSi::ConsoleID; + // slot 3: console-unique eMMC crypto *(u32*)&KeyX[3][0] = (u32)DSi::ConsoleID; *(u32*)&KeyX[3][4] = (u32)DSi::ConsoleID ^ 0x24EE6906; @@ -134,6 +151,34 @@ void Reset() } +void ProcessBlock_CCM_Decrypt() +{ + u8 data[16]; + u8 data_rev[16]; + + *(u32*)&data[0] = InputFIFO->Read(); + *(u32*)&data[4] = InputFIFO->Read(); + *(u32*)&data[8] = InputFIFO->Read(); + *(u32*)&data[12] = InputFIFO->Read(); + + //printf("AES-CCM: "); _printhex2(data, 16); + + Swap16(data_rev, data); + AES_CTR_xcrypt_buffer(&Ctx, data_rev, 16); + + for (int i = 0; i < 16; i++) CurMAC[i] ^= data_rev[i]; + AES_ECB_encrypt(&Ctx, CurMAC); + + Swap16(data, data_rev); + + //printf(" -> "); _printhex2(data, 16); + + OutputFIFO->Write(*(u32*)&data[0]); + OutputFIFO->Write(*(u32*)&data[4]); + OutputFIFO->Write(*(u32*)&data[8]); + OutputFIFO->Write(*(u32*)&data[12]); +} + void ProcessBlock_CTR() { u8 data[16]; @@ -186,18 +231,12 @@ void WriteCnt(u32 val) OutputDMASize = dmasize_out[(val >> 14) & 0x3]; AESMode = (val >> 28) & 0x3; - if (AESMode < 2) printf("AES-CCM TODO\n"); + if (AESMode == 1) printf("AES-CCM TODO\n"); if (val & (1<<24)) { u32 slot = (val >> 26) & 0x3; memcpy(CurKey, KeyNormal[slot], 16); - - //printf("AES: key(%d): ", slot); _printhex(CurKey, 16); - - u8 tmp[16]; - Swap16(tmp, CurKey); - AES_init_ctx(&Ctx, tmp); } if (!(oldcnt & (1<<31)) && (val & (1<<31))) @@ -205,11 +244,45 @@ void WriteCnt(u32 val) // transfer start (checkme) RemBlocks = BlkCnt >> 16; + u8 key[16]; + u8 iv[16]; + + Swap16(key, CurKey); + Swap16(iv, IV); + + if (AESMode < 2) + { + if (BlkCnt & 0xFFFF) printf("AES: CCM EXTRA LEN TODO\n"); + + u32 maclen = (val >> 16) & 0x7; + if (maclen < 1) maclen = 1; + + iv[0] = 0x02; + for (int i = 0; i < 12; i++) iv[1+i] = iv[4+i]; + iv[13] = 0x00; + iv[14] = 0x00; + iv[15] = 0x01; + + AES_init_ctx_iv(&Ctx, key, iv); + + iv[0] |= (maclen << 3) | ((BlkCnt & 0xFFFF) ? (1<<6) : 0); + iv[13] = RemBlocks >> 12; + iv[14] = RemBlocks >> 4; + iv[15] = RemBlocks << 4; + + memcpy(CurMAC, iv, 16); + AES_ECB_encrypt(&Ctx, CurMAC); + } + else + { + AES_init_ctx_iv(&Ctx, key, iv); + } + DSi::CheckNDMAs(1, 0x2A); } - printf("AES CNT: %08X / mode=%d inDMA=%d outDMA=%d blocks=%d\n", - val, AESMode, InputDMASize, OutputDMASize, RemBlocks); + printf("AES CNT: %08X / mode=%d key=%d inDMA=%d outDMA=%d blocks=%d\n", + val, AESMode, (val >> 26) & 0x3, InputDMASize, OutputDMASize, RemBlocks); } void WriteBlkCnt(u32 val) @@ -219,6 +292,8 @@ void WriteBlkCnt(u32 val) u32 ReadOutputFIFO() { + if (OutputFIFO->IsEmpty()) printf("!!! AES OUTPUT FIFO EMPTY\n"); + u32 ret = OutputFIFO->Read(); if (Cnt & (1<<31)) @@ -241,6 +316,8 @@ void WriteInputFIFO(u32 val) { // TODO: add some delay to processing + if (InputFIFO->IsFull()) printf("!!! AES INPUT FIFO FULL\n"); + InputFIFO->Write(val); if (!(Cnt & (1<<31))) return; @@ -276,6 +353,7 @@ void Update() { switch (AESMode) { + case 0: ProcessBlock_CCM_Decrypt(); break; case 2: case 3: ProcessBlock_CTR(); break; default: @@ -293,6 +371,28 @@ void Update() if (RemBlocks == 0) { + if (AESMode == 0) + { + Ctx.Iv[13] = 0x00; + Ctx.Iv[14] = 0x00; + Ctx.Iv[15] = 0x00;_printhex(Ctx.Iv, 16); + AES_CTR_xcrypt_buffer(&Ctx, CurMAC, 16); + + //printf("FINAL MAC: "); _printhexR(CurMAC, 16); + //printf("INPUT MAC: "); _printhex(MAC, 16); + + Cnt |= (1<<21); + for (int i = 0; i < 16; i++) + { + if (CurMAC[15-i] != MAC[i]) Cnt &= ~(1<<21); + } + } + else + { + // CHECKME + Cnt &= ~(1<<21); + } + Cnt &= ~(1<<31); if (Cnt & (1<<30)) NDS::SetIRQ2(NDS::IRQ2_DSi_AES); DSi::StopNDMAs(1, 0x2A); @@ -313,15 +413,15 @@ void WriteIV(u32 offset, u32 val, u32 mask) *(u32*)&IV[offset] = (old & ~mask) | (val & mask); //printf("AES: IV: "); _printhex(IV, 16); - - u8 tmp[16]; - Swap16(tmp, IV); - AES_ctx_set_iv(&Ctx, tmp); } void WriteMAC(u32 offset, u32 val, u32 mask) { - // + u32 old = *(u32*)&MAC[offset]; + + *(u32*)&MAC[offset] = (old & ~mask) | (val & mask); + + //printf("AES: MAC: "); _printhex(MAC, 16); } void DeriveNormalKey(u32 slot) @@ -355,6 +455,8 @@ void WriteKeyNormal(u32 slot, u32 offset, u32 val, u32 mask) u32 old = *(u32*)&KeyNormal[slot][offset]; *(u32*)&KeyNormal[slot][offset] = (old & ~mask) | (val & mask); + + //printf("KeyNormal(%d): ", slot); _printhex(KeyNormal[slot], 16); } void WriteKeyX(u32 slot, u32 offset, u32 val, u32 mask) @@ -362,6 +464,8 @@ void WriteKeyX(u32 slot, u32 offset, u32 val, u32 mask) u32 old = *(u32*)&KeyX[slot][offset]; *(u32*)&KeyX[slot][offset] = (old & ~mask) | (val & mask); + + //printf("KeyX(%d): ", slot); _printhex(KeyX[slot], 16); } void WriteKeyY(u32 slot, u32 offset, u32 val, u32 mask) @@ -370,6 +474,8 @@ void WriteKeyY(u32 slot, u32 offset, u32 val, u32 mask) *(u32*)&KeyY[slot][offset] = (old & ~mask) | (val & mask); + //printf("[%08X] KeyY(%d): ", NDS::GetPC(1), slot); _printhex(KeyY[slot], 16); + if (offset >= 0xC) { DeriveNormalKey(slot); diff --git a/src/DSi_NDMA.cpp b/src/DSi_NDMA.cpp index 37eb687..e7fc7ab 100644 --- a/src/DSi_NDMA.cpp +++ b/src/DSi_NDMA.cpp @@ -123,7 +123,10 @@ void DSi_NDMA::Start() if (((StartMode & 0x1F) != 0x10) && !(Cnt & (1<<29))) { if (IterCount > TotalRemCount) + { IterCount = TotalRemCount; + RemCount = IterCount; + } } if (Cnt & (1<<12)) CurDstAddr = DstAddr; diff --git a/src/DSi_SD.cpp b/src/DSi_SD.cpp index 7367eea..93431b5 100644 --- a/src/DSi_SD.cpp +++ b/src/DSi_SD.cpp @@ -185,6 +185,17 @@ void DSi_SDHost::SendData(u8* data, u32 len) NDS::ScheduleEvent(NDS::Event_DSi_SDTransfer, false, 512, FinishSend, param); } +void DSi_SDHost::FinishReceive(u32 param) +{ + DSi_SDHost* host = (param & 0x1) ? DSi::SDIO : DSi::SDMMC; + DSi_SDDevice* dev = host->Ports[host->PortSelect & 0x1]; + + host->ClearIRQ(24); + host->SetIRQ(25); + + if (dev) dev->ContinueTransfer(); +} + void DSi_SDHost::ReceiveData(u8* data, u32 len) { printf("%s: data TX, len=%d, blkcnt=%d (%d) blklen=%d, irq=%08X\n", SD_DESC, len, BlockCount16, BlockCountInternal, BlockLen16, IRQMask); @@ -481,10 +492,12 @@ void DSi_SDHost::WriteFIFO32(u32 val) // we completed one block, send it to the SD card - ClearIRQ(24); - SetIRQ(25); + //ClearIRQ(24); + //SetIRQ(25); - if (dev) dev->ContinueTransfer(); + //if (dev) dev->ContinueTransfer(); + // TODO measure the actual delay!! + NDS::ScheduleEvent(NDS::Event_DSi_SDTransfer, false, 2048, FinishReceive, Num); } @@ -622,10 +635,10 @@ void DSi_MMCStorage::SendCMD(u8 cmd, u32 param) Host->SendResponse(CSR, true); WriteBlock(RWAddress); RWAddress += BlockSize; - SetState(0x06); + SetState(0x04); return; - case 55: // ?? + case 55: // appcmd prefix CSR |= (1<<5); Host->SendResponse(CSR, true); return; diff --git a/src/DSi_SD.h b/src/DSi_SD.h index 007a8a8..855dd5e 100644 --- a/src/DSi_SD.h +++ b/src/DSi_SD.h @@ -37,6 +37,7 @@ public: void DoSavestate(Savestate* file); static void FinishSend(u32 param); + static void FinishReceive(u32 param); void SendResponse(u32 val, bool last); void SendData(u8* data, u32 len); void ReceiveData(u8* data, u32 len); diff --git a/src/SPU.cpp b/src/SPU.cpp index ee9237f..d31a371 100644 --- a/src/SPU.cpp +++ b/src/SPU.cpp @@ -19,6 +19,7 @@ #include #include #include "NDS.h" +#include "DSi.h" #include "SPU.h" @@ -216,7 +217,8 @@ void Channel::FIFO_BufferData() for (u32 i = 0; i < burstlen; i += 4) { - FIFO[FIFOWritePos] = NDS::ARM7Read32(SrcAddr + FIFOReadOffset); + //FIFO[FIFOWritePos] = NDS::ARM7Read32(SrcAddr + FIFOReadOffset); + FIFO[FIFOWritePos] = DSi::ARM7Read32(SrcAddr + FIFOReadOffset); FIFOReadOffset += 4; FIFOWritePos++; FIFOWritePos &= 0x7; @@ -499,7 +501,8 @@ void CaptureUnit::FIFO_FlushData() { for (u32 i = 0; i < 4; i++) { - NDS::ARM7Write32(DstAddr + FIFOWriteOffset, FIFO[FIFOReadPos]); + //NDS::ARM7Write32(DstAddr + FIFOWriteOffset, FIFO[FIFOReadPos]); + DSi::ARM7Write32(DstAddr + FIFOWriteOffset, FIFO[FIFOReadPos]); FIFOReadPos++; FIFOReadPos &= 0x3; -- cgit v1.2.3 From 06716794a1d69512312e1dc251b9762d27b15c8d Mon Sep 17 00:00:00 2001 From: Arisotura Date: Wed, 24 Jul 2019 18:48:52 +0200 Subject: lots of things. attempting to make wifi init work. not there yet. --- src/DSi.cpp | 55 ++++++++++---- src/DSi_AES.cpp | 23 ++++++ src/DSi_NWifi.cpp | 214 +++++++++++++++++++++++++++++++++++++++++++++++++----- src/DSi_NWifi.h | 27 +++++++ src/DSi_SD.cpp | 70 ++++++++++++++---- src/DSi_SD.h | 2 +- src/NDS.h | 3 +- 7 files changed, 344 insertions(+), 50 deletions(-) (limited to 'src/DSi_AES.cpp') diff --git a/src/DSi.cpp b/src/DSi.cpp index 26a67f4..aed6b89 100644 --- a/src/DSi.cpp +++ b/src/DSi.cpp @@ -73,6 +73,7 @@ u64 ConsoleID; u8 eMMC_CID[16]; u8 ITCMInit[0x8000]; +u8 ARM7Init[0x3C00]; bool Init() @@ -120,6 +121,9 @@ void Reset() memcpy(NDS::ARM9->ITCM, ITCMInit, 0x8000); + for (u32 i = 0; i < 0x3C00; i+=4) + ARM7Write32(0x03FFC400+i, *(u32*)&ARM7Init[i]); + DSi_I2C::Reset(); DSi_AES::Reset(); @@ -138,9 +142,16 @@ void Reset() NDS::MapSharedWRAM(3); - // TEST - u8 derp[16] = {0xE5, 0xCC, 0x5A, 0x8B, 0x56, 0xD0, 0xC9, 0x72, 0x9C, 0x17, 0xE8, 0xDC, 0x39, 0x12, 0x36, 0xA9}; - for (int i = 0; i < 16; i+=4) ARM7Write32(0x03FFC580+i, *(u32*)&derp[i]); + u32 eaddr = 0x03FFE6E4; + ARM7Write32(eaddr+0x00, *(u32*)&eMMC_CID[0]); + ARM7Write32(eaddr+0x04, *(u32*)&eMMC_CID[4]); + ARM7Write32(eaddr+0x08, *(u32*)&eMMC_CID[8]); + ARM7Write32(eaddr+0x0C, *(u32*)&eMMC_CID[12]); + ARM7Write16(eaddr+0x2C, 0x0001); + ARM7Write16(eaddr+0x2E, 0x0001); + ARM7Write16(eaddr+0x3C, 0x0100); + ARM7Write16(eaddr+0x3E, 0x40E0); + ARM7Write16(eaddr+0x42, 0x0001); } bool LoadBIOS() @@ -328,19 +339,31 @@ bool LoadNAND() } memset(ITCMInit, 0, 0x8000); + memset(ARM7Init, 0, 0x3C00); - f = fopen("dsikeys.bin", "rb"); + f = fopen("initmem9.bin", "rb"); if (f) { // first 0x2524 bytes are loaded to 0x01FFC400 u32 dstaddr = 0x01FFC400; - fread(&ITCMInit[dstaddr & 0x7FFF], 0x2524, 1, f); + fread(&ITCMInit[dstaddr & 0x7FFF], /*0x2524*/0x3C00, 1, f); + fclose(f); + } + else + { + printf("DSi ARM9 meminit not found\n"); + } + + f = fopen("initmem7.bin", "rb"); + if (f) + { + fread(ARM7Init, 0x3C00, 1, f); fclose(f); } else { - printf("DSi keys not found\n"); + printf("DSi ARM7 meminit not found\n"); } return true; @@ -559,7 +582,7 @@ void MapNWRAMRange(u32 cpu, u32 num, u32 val) u8 ARM9Read8(u32 addr) -{ +{if (addr>=0x2FFD7BC && addr<0x2FFD800) printf("EMMCGONP 8 9 %08X %08X\n", addr, NDS::GetPC(0)); switch (addr & 0xFF000000) { case 0x03000000: @@ -588,7 +611,7 @@ u8 ARM9Read8(u32 addr) } u16 ARM9Read16(u32 addr) -{ +{if (addr>=0x2FFD7BC && addr<0x2FFD800) printf("EMMCGONP 16 9 %08X %08X\n", addr, NDS::GetPC(0)); switch (addr & 0xFF000000) { case 0x03000000: @@ -617,7 +640,8 @@ u16 ARM9Read16(u32 addr) } u32 ARM9Read32(u32 addr) -{ +{if(addr==0x029D02D8) printf("READ SHITTY VTABLE: %08X\n", NDS::GetPC(0)); +if (addr>=0x2FFD7BC && addr<0x2FFD800) printf("EMMCGONP 32 9 %08X %08X\n", addr, NDS::GetPC(0)); switch (addr & 0xFF000000) { case 0x03000000: @@ -712,7 +736,7 @@ void ARM9Write16(u32 addr, u16 val) } void ARM9Write32(u32 addr, u32 val) -{ +{if(addr==0x02B05E34) printf("VGONP. %08X, %08X\n", val, NDS::GetPC(0)); switch (addr & 0xFF000000) { case 0x03000000: @@ -768,7 +792,8 @@ bool ARM9GetMemRegion(u32 addr, bool write, NDS::MemRegion* region) u8 ARM7Read8(u32 addr) -{ +{if(addr>=0x3FFC400 && addr<0x3FFE728) printf("OGON 8 %08X %08X\n", addr, NDS::GetPC(1)); +if (addr>=0x2FFD7BC && addr<0x2FFD800) printf("EMMCGONP 8 7 %08X %08X\n", addr, NDS::GetPC(1)); switch (addr & 0xFF800000) { case 0x03000000: @@ -797,7 +822,8 @@ u8 ARM7Read8(u32 addr) } u16 ARM7Read16(u32 addr) -{ +{if(addr>=0x3FFC400 && addr<0x3FFE728) printf("OGON 16 %08X %08X\n", addr, NDS::GetPC(1)); +if (addr>=0x2FFD7BC && addr<0x2FFD800) printf("EMMCGONP 16 7 %08X %08X\n", addr, NDS::GetPC(1)); switch (addr & 0xFF800000) { case 0x03000000: @@ -826,7 +852,8 @@ u16 ARM7Read16(u32 addr) } u32 ARM7Read32(u32 addr) -{ +{if(addr>=0x3FFC400 && addr<0x3FFE728) printf("OGON 32 %08X %08X\n", addr, NDS::GetPC(1)); +if (addr>=0x2FFD7BC && addr<0x2FFD800) printf("EMMCGONP 32 7 %08X %08X\n", addr, NDS::GetPC(1)); switch (addr & 0xFF800000) { case 0x03000000: @@ -855,7 +882,7 @@ u32 ARM7Read32(u32 addr) } void ARM7Write8(u32 addr, u8 val) -{ +{if(addr==0x0228CD74) printf("RAKAKA %02X %08X\n", val, NDS::GetPC(1)); switch (addr & 0xFF800000) { case 0x03000000: diff --git a/src/DSi_AES.cpp b/src/DSi_AES.cpp index 8ae9082..4aa97bc 100644 --- a/src/DSi_AES.cpp +++ b/src/DSi_AES.cpp @@ -22,6 +22,7 @@ #include "DSi_AES.h" #include "FIFO.h" #include "tiny-AES-c/aes.hpp" +#include "Platform.h" namespace DSi_AES @@ -130,6 +131,7 @@ void Reset() // initialize keys, as per GBAtek +#if 0 // slot 0: modcrypt *(u32*)&KeyX[0][0] = 0x746E694E; *(u32*)&KeyX[0][4] = 0x6F646E65; @@ -148,6 +150,27 @@ void Reset() *(u32*)&KeyY[3][0] = 0x0AB9DC76; *(u32*)&KeyY[3][4] = 0xBD4DC4D3; *(u32*)&KeyY[3][8] = 0x202DDD1D; +#endif + FILE* f = Platform::OpenLocalFile("aeskeys.bin", "rb"); + if (f) + { + fread(KeyNormal[0], 16, 1, f); + fread(KeyX[0], 16, 1, f); + fread(KeyY[0], 16, 1, f); + fread(KeyNormal[1], 16, 1, f); + fread(KeyX[1], 16, 1, f); + fread(KeyY[1], 16, 1, f); + fread(KeyNormal[2], 16, 1, f); + fread(KeyX[2], 16, 1, f); + fread(KeyY[2], 16, 1, f); + fread(KeyNormal[3], 16, 1, f); + fread(KeyX[3], 16, 1, f); + fread(KeyY[3], 16, 1, f); + + fclose(f); + } + else + printf("AES: aeskeys.bin not found\n"); } diff --git a/src/DSi_NWifi.cpp b/src/DSi_NWifi.cpp index 5236551..e0591fb 100644 --- a/src/DSi_NWifi.cpp +++ b/src/DSi_NWifi.cpp @@ -114,11 +114,20 @@ DSi_NWifi::DSi_NWifi(DSi_SDHost* host) : DSi_SDDevice(host) { TransferCmd = 0xFFFFFFFF; RemSize = 0; + + WindowData = 0; + WindowReadAddr = 0; + WindowWriteAddr = 0; + + // TODO: check the actual mailbox size (presumably 0x200) + for (int i = 0; i < 8; i++) + Mailbox[i] = new FIFO(0x200); } DSi_NWifi::~DSi_NWifi() { - // + for (int i = 0; i < 8; i++) + delete Mailbox[i]; } @@ -165,9 +174,54 @@ void DSi_NWifi::F0_Write(u32 addr, u8 val) u8 DSi_NWifi::F1_Read(u32 addr) -{ - switch (addr) +{printf("F1 READ %05X\n", addr); + if (addr < 0x100) + { + return Mailbox[4]->Read(); + } + else if (addr < 0x200) + { + return Mailbox[5]->Read(); + } + else if (addr < 0x300) + { + return Mailbox[6]->Read(); + } + else if (addr < 0x400) + { + return Mailbox[7]->Read(); + } + else if (addr < 0x800) + { + switch (addr) + { + case 0x00450: return 1; // HAX!! + + case 0x00474: return WindowData & 0xFF; + case 0x00475: return (WindowData >> 8) & 0xFF; + case 0x00476: return (WindowData >> 16) & 0xFF; + case 0x00477: return WindowData >> 24; + } + } + else if (addr < 0x1000) + { + return Mailbox[4]->Read(); + } + else if (addr < 0x1800) + { + return Mailbox[5]->Read(); + } + else if (addr < 0x2000) + { + return Mailbox[6]->Read(); + } + else if (addr < 0x2800) + { + return Mailbox[7]->Read(); + } + else { + return Mailbox[4]->Read(); } printf("NWIFI: unknown func1 read %05X\n", addr); @@ -175,7 +229,91 @@ u8 DSi_NWifi::F1_Read(u32 addr) } void DSi_NWifi::F1_Write(u32 addr, u8 val) -{ +{printf("F1 WRITE %05X %02X\n", addr, val); + if (addr < 0x100) + { + if (Mailbox[0]->IsFull()) printf("!!! NWIFI: MBOX0 FULL\n"); + Mailbox[0]->Write(val); + if (addr == 0xFF) BMI_Command(); + return; + } + else if (addr < 0x200) + { + if (Mailbox[1]->IsFull()) printf("!!! NWIFI: MBOX1 FULL\n"); + Mailbox[1]->Write(val); + return; + } + else if (addr < 0x300) + { + if (Mailbox[2]->IsFull()) printf("!!! NWIFI: MBOX2 FULL\n"); + Mailbox[2]->Write(val); + return; + } + else if (addr < 0x400) + { + if (Mailbox[3]->IsFull()) printf("!!! NWIFI: MBOX3 FULL\n"); + Mailbox[3]->Write(val); + return; + } + else if (addr < 0x800) + { + switch (addr) + { + case 0x00474: WindowData = (WindowData & 0xFFFFFF00) | val; return; + case 0x00475: WindowData = (WindowData & 0xFFFF00FF) | (val << 8); return; + case 0x00476: WindowData = (WindowData & 0xFF00FFFF) | (val << 16); return; + case 0x00477: WindowData = (WindowData & 0x00FFFFFF) | (val << 24); return; + + case 0x00478: + WindowWriteAddr = (WindowWriteAddr & 0xFFFFFF00) | val; + WindowWrite(); + return; + case 0x00479: WindowWriteAddr = (WindowWriteAddr & 0xFFFF00FF) | (val << 8); return; + case 0x0047A: WindowWriteAddr = (WindowWriteAddr & 0xFF00FFFF) | (val << 16); return; + case 0x0047B: WindowWriteAddr = (WindowWriteAddr & 0x00FFFFFF) | (val << 24); return; + + case 0x0047C: + WindowReadAddr = (WindowReadAddr & 0xFFFFFF00) | val; + WindowRead(); + return; + case 0x0047D: WindowReadAddr = (WindowReadAddr & 0xFFFF00FF) | (val << 8); return; + case 0x0047E: WindowReadAddr = (WindowReadAddr & 0xFF00FFFF) | (val << 16); return; + case 0x0047F: WindowReadAddr = (WindowReadAddr & 0x00FFFFFF) | (val << 24); return; + } + } + else if (addr < 0x1000) + { + if (Mailbox[0]->IsFull()) printf("!!! NWIFI: MBOX0 FULL\n"); + Mailbox[0]->Write(val); + if (addr == 0xFFF) BMI_Command(); + return; + } + else if (addr < 0x1800) + { + if (Mailbox[1]->IsFull()) printf("!!! NWIFI: MBOX1 FULL\n"); + Mailbox[1]->Write(val); + return; + } + else if (addr < 0x2000) + { + if (Mailbox[2]->IsFull()) printf("!!! NWIFI: MBOX2 FULL\n"); + Mailbox[2]->Write(val); + return; + } + else if (addr < 0x2800) + { + if (Mailbox[3]->IsFull()) printf("!!! NWIFI: MBOX3 FULL\n"); + Mailbox[3]->Write(val); + return; + } + else + { + if (Mailbox[0]->IsFull()) printf("!!! NWIFI: MBOX0 FULL\n"); + Mailbox[0]->Write(val); + if (addr == 0x3FFF) BMI_Command(); // CHECKME + return; + } + printf("NWIFI: unknown func1 write %05X %02X\n", addr, val); } @@ -185,6 +323,7 @@ u8 DSi_NWifi::SDIO_Read(u32 func, u32 addr) switch (func) { case 0: return F0_Read(addr); + case 1: return F1_Read(addr); } printf("NWIFI: unknown SDIO read %d %05X\n", func, addr); @@ -196,6 +335,7 @@ void DSi_NWifi::SDIO_Write(u32 func, u32 addr, u8 val) switch (func) { case 0: return F0_Write(addr, val); + case 1: return F1_Write(addr, val); } printf("NWIFI: unknown SDIO write %d %05X %02X\n", func, addr, val); @@ -203,7 +343,7 @@ void DSi_NWifi::SDIO_Write(u32 func, u32 addr, u8 val) void DSi_NWifi::SendCMD(u8 cmd, u32 param) -{ +{printf("NWIFI CMD %d %08X %08X\n", cmd, param, NDS::GetPC(1)); switch (cmd) { case 52: // IO_RW_DIRECT @@ -315,24 +455,62 @@ void DSi_NWifi::WriteBlock() u32 len = (TransferCmd & (1<<27)) ? 0x200 : RemSize; u8 data[0x200]; - Host->ReceiveData(data, len); - - for (u32 i = 0; i < len; i++) + if (Host->ReceiveData(data, len)) { - SDIO_Write(func, TransferAddr, data[i]); - if (TransferCmd & (1<<26)) + for (u32 i = 0; i < len; i++) { - TransferAddr++; - TransferAddr &= 0x1FFFF; // checkme + SDIO_Write(func, TransferAddr, data[i]); + if (TransferCmd & (1<<26)) + { + TransferAddr++; + TransferAddr &= 0x1FFFF; // checkme + } } - } - if (RemSize > 0) - { - RemSize -= len; - if (RemSize == 0) + if (RemSize > 0) { - // TODO? + RemSize -= len; + if (RemSize == 0) + { + // TODO? + } } } } + + +void DSi_NWifi::BMI_Command() +{ + // HLE command handling stub + u32 cmd = MB_Read32(0); + printf("BMI: cmd %08X\n", cmd); + + switch (cmd) + { + case 0x08: // BMI_GET_TARGET_ID + MB_Write32(4, 0xFFFFFFFF); + MB_Write32(4, 0x0000000C); + MB_Write32(4, 0x20000118); + MB_Write32(4, 0x00000002); + return; + } +} + + +void DSi_NWifi::WindowRead() +{ + printf("NWifi: window read %08X\n", WindowReadAddr); + + switch (WindowReadAddr) + { + case 0x40EC: WindowData = 0x02000001; return; + + // SOC_RESET_CAUSE + case 0x40C0: WindowData = 2; return; + } +} + +void DSi_NWifi::WindowWrite() +{ + printf("NWifi: window write %08X %08X\n", WindowWriteAddr, WindowData); +} diff --git a/src/DSi_NWifi.h b/src/DSi_NWifi.h index 5d61951..4ec010e 100644 --- a/src/DSi_NWifi.h +++ b/src/DSi_NWifi.h @@ -20,6 +20,7 @@ #define DSI_NWIFI_H #include "DSi_SD.h" +#include "FIFO.h" class DSi_NWifi : public DSi_SDDevice { @@ -48,6 +49,32 @@ private: void ReadBlock(); void WriteBlock(); + + void BMI_Command(); + + void WindowRead(); + void WindowWrite(); + + u32 MB_Read32(int n) + { + u32 ret = Mailbox[n]->Read(); + ret |= (Mailbox[n]->Read() << 8); + ret |= (Mailbox[n]->Read() << 16); + ret |= (Mailbox[n]->Read() << 24); + return ret; + } + + void MB_Write32(int n, u32 val) + { + Mailbox[n]->Write(val & 0xFF); val >>= 8; + Mailbox[n]->Write(val & 0xFF); val >>= 8; + Mailbox[n]->Write(val & 0xFF); val >>= 8; + Mailbox[n]->Write(val & 0xFF); + } + + FIFO* Mailbox[8]; + + u32 WindowData, WindowReadAddr, WindowWriteAddr; }; #endif // DSI_NWIFI_H diff --git a/src/DSi_SD.cpp b/src/DSi_SD.cpp index 6e73df5..c9edd78 100644 --- a/src/DSi_SD.cpp +++ b/src/DSi_SD.cpp @@ -185,7 +185,8 @@ void DSi_SDHost::SendData(u8* data, u32 len) // but if IRQ24 is thrown instantly, the handler clears IRQ0 before the // send-command function starts polling IRQ status u32 param = Num | (last << 1); - NDS::ScheduleEvent(NDS::Event_DSi_SDTransfer, false, 512, FinishSend, param); + NDS::ScheduleEvent(Num ? NDS::Event_DSi_SDIOTransfer : NDS::Event_DSi_SDMMCTransfer, + false, 512, FinishSend, param); } void DSi_SDHost::FinishReceive(u32 param) @@ -199,13 +200,19 @@ void DSi_SDHost::FinishReceive(u32 param) if (dev) dev->ContinueTransfer(); } -void DSi_SDHost::ReceiveData(u8* data, u32 len) +bool DSi_SDHost::ReceiveData(u8* data, u32 len) { printf("%s: data TX, len=%d, blkcnt=%d (%d) blklen=%d, irq=%08X\n", SD_DESC, len, BlockCount16, BlockCountInternal, BlockLen16, IRQMask); if (len != BlockLen16) printf("!! BAD BLOCKLEN\n"); - DSi_SDDevice* dev = Ports[PortSelect & 0x1]; u32 f = CurFIFO; + if ((DataFIFO[f]->Level() << 1) < len) + { + printf("%s: FIFO not full enough for a transfer (%d / %d)\n", SD_DESC, DataFIFO[f]->Level()<<1, len); + return false; + } + + DSi_SDDevice* dev = Ports[PortSelect & 0x1]; for (u32 i = 0; i < len; i += 2) *(u16*)&data[i] = DataFIFO[f]->Read(); @@ -213,7 +220,7 @@ void DSi_SDHost::ReceiveData(u8* data, u32 len) if (BlockCountInternal <= 1) { - printf("%s: data32 TX complete", SD_DESC); + printf("%s: data TX complete", SD_DESC); if (StopAction & (1<<8)) { @@ -232,12 +239,14 @@ void DSi_SDHost::ReceiveData(u8* data, u32 len) { BlockCountInternal--; } + + return true; } u16 DSi_SDHost::Read(u32 addr) { - //printf("SDMMC READ %08X %08X\n", addr, NDS::GetPC(1)); + //if(Num)printf("SDIO READ %08X %08X\n", addr, NDS::GetPC(1)); switch (addr & 0x1FF) { @@ -383,7 +392,7 @@ u32 DSi_SDHost::ReadFIFO32() void DSi_SDHost::Write(u32 addr, u16 val) { - //printf("SDMMC WRITE %08X %04X %08X\n", addr, val, NDS::GetPC(1)); + //if(Num)printf("SDIO WRITE %08X %04X %08X\n", addr, val, NDS::GetPC(1)); switch (addr & 0x1FF) { @@ -421,7 +430,11 @@ void DSi_SDHost::Write(u32 addr, u16 val) case 0x01C: IRQStatus &= (val | 0xFFFF0000); return; case 0x01E: IRQStatus &= ((val << 16) | 0xFFFF); return; case 0x020: IRQMask = (IRQMask & 0x8B7F0000) | (val & 0x031D); return; - case 0x022: IRQMask = (IRQMask & 0x0000031D) | ((val & 0x8B7F) << 16); return; + case 0x022: + IRQMask = (IRQMask & 0x0000031D) | ((val & 0x8B7F) << 16); + if (!DataFIFO[CurFIFO]->IsEmpty()) SetIRQ(24); // checkme + if (DataFIFO[CurFIFO]->IsEmpty()) SetIRQ(25); // checkme + return; case 0x024: SDClock = val & 0x03FF; return; case 0x026: @@ -430,6 +443,33 @@ void DSi_SDHost::Write(u32 addr, u16 val) return; case 0x028: SDOption = val & 0xC1FF; return; + case 0x030: // FIFO16 + { + DSi_SDDevice* dev = Ports[PortSelect & 0x1]; + u32 f = CurFIFO; + if (DataFIFO[f]->IsFull()) + { + // TODO + printf("!!!! %s FIFO FULL\n", SD_DESC); + return; + } + + DataFIFO[f]->Write(val); + + if (DataFIFO[f]->Level() < (BlockLen16>>1)) + { + ClearIRQ(25); + SetIRQ(24); + return; + } + + // we completed one block, send it to the SD card + // TODO measure the actual delay!! + NDS::ScheduleEvent(Num ? NDS::Event_DSi_SDIOTransfer : NDS::Event_DSi_SDMMCTransfer, + false, 2048, FinishReceive, Num); + } + return; + case 0x0D8: DataCtl = (val & 0x0022); DataMode = ((DataCtl >> 1) & 0x1) & ((Data32IRQ >> 1) & 0x1); @@ -494,13 +534,9 @@ void DSi_SDHost::WriteFIFO32(u32 val) } // we completed one block, send it to the SD card - - //ClearIRQ(24); - //SetIRQ(25); - - //if (dev) dev->ContinueTransfer(); // TODO measure the actual delay!! - NDS::ScheduleEvent(NDS::Event_DSi_SDTransfer, false, 2048, FinishReceive, Num); + NDS::ScheduleEvent(Num ? NDS::Event_DSi_SDIOTransfer : NDS::Event_DSi_SDMMCTransfer, + false, 2048, FinishReceive, Num); } @@ -726,7 +762,9 @@ void DSi_MMCStorage::WriteBlock(u64 addr) printf("SD/MMC: write block @ %08X, len=%08X\n", addr, BlockSize); u8 data[0x200]; - Host->ReceiveData(data, BlockSize); - fseek(File, addr, SEEK_SET); - fwrite(data, 1, BlockSize, File); + if (Host->ReceiveData(data, BlockSize)) + { + fseek(File, addr, SEEK_SET); + fwrite(data, 1, BlockSize, File); + } } diff --git a/src/DSi_SD.h b/src/DSi_SD.h index 855dd5e..22475d6 100644 --- a/src/DSi_SD.h +++ b/src/DSi_SD.h @@ -40,7 +40,7 @@ public: static void FinishReceive(u32 param); void SendResponse(u32 val, bool last); void SendData(u8* data, u32 len); - void ReceiveData(u8* data, u32 len); + bool ReceiveData(u8* data, u32 len); u16 Read(u32 addr); void Write(u32 addr, u16 val); diff --git a/src/NDS.h b/src/NDS.h index 850e829..e32908b 100644 --- a/src/NDS.h +++ b/src/NDS.h @@ -43,7 +43,8 @@ enum Event_Sqrt, // DSi - Event_DSi_SDTransfer, + Event_DSi_SDMMCTransfer, + Event_DSi_SDIOTransfer, Event_MAX }; -- cgit v1.2.3 From dcda848cdfd94aaa5549841d8ba3cb54370f9cbc Mon Sep 17 00:00:00 2001 From: Arisotura Date: Wed, 7 Aug 2019 12:57:12 +0200 Subject: * base for potentially re-encrypting modcrypt, doesn't seem to be required? but can also serve to decrypt it * revise SD IRQ behavior (fixing potential hang when loading DS games) --- src/DSi_AES.cpp | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/DSi_AES.h | 3 +++ src/DSi_SD.cpp | 29 ++++++++++++++++++++++----- src/DSi_SD.h | 1 + src/NDSCart.cpp | 23 ++++++++++++++++++++++ 5 files changed, 111 insertions(+), 6 deletions(-) (limited to 'src/DSi_AES.cpp') diff --git a/src/DSi_AES.cpp b/src/DSi_AES.cpp index 4aa97bc..e49ebf5 100644 --- a/src/DSi_AES.cpp +++ b/src/DSi_AES.cpp @@ -398,7 +398,7 @@ void Update() { Ctx.Iv[13] = 0x00; Ctx.Iv[14] = 0x00; - Ctx.Iv[15] = 0x00;_printhex(Ctx.Iv, 16); + Ctx.Iv[15] = 0x00; AES_CTR_xcrypt_buffer(&Ctx, CurMAC, 16); //printf("FINAL MAC: "); _printhexR(CurMAC, 16); @@ -505,4 +505,63 @@ void WriteKeyY(u32 slot, u32 offset, u32 val, u32 mask) } } + +// utility + +void GetModcryptKey(u8* romheader, u8* key) +{ + if ((romheader[0x01C] & 0x04) || (romheader[0x1BF] & 0x80)) + { + // dev key + memcpy(key, &romheader[0x000], 16); + return; + } + + u8 oldkeys[16*3]; + memcpy(&oldkeys[16*0], KeyX[0], 16); + memcpy(&oldkeys[16*1], KeyY[0], 16); + memcpy(&oldkeys[16*2], KeyNormal[0], 16); + + KeyX[0][8] = romheader[0x00C]; + KeyX[0][9] = romheader[0x00D]; + KeyX[0][10] = romheader[0x00E]; + KeyX[0][11] = romheader[0x00F]; + KeyX[0][12] = romheader[0x00F]; + KeyX[0][13] = romheader[0x00E]; + KeyX[0][14] = romheader[0x00D]; + KeyX[0][15] = romheader[0x00C]; + + memcpy(KeyY[0], &romheader[0x350], 16); + + DeriveNormalKey(0); + memcpy(key, KeyNormal[0], 16); + + memcpy(KeyX[0], &oldkeys[16*0], 16); + memcpy(KeyY[0], &oldkeys[16*1], 16); + memcpy(KeyNormal[0], &oldkeys[16*2], 16); +} + +void ApplyModcrypt(u8* data, u32 len, u8* key, u8* iv) +{ + u8 key_rev[16], iv_rev[16]; + u8 data_rev[16]; + u8 oldkeys[16*2]; + memcpy(&oldkeys[16*0], Ctx.RoundKey, 16); + memcpy(&oldkeys[16*1], Ctx.Iv, 16); + + Swap16(key_rev, key); + Swap16(iv_rev, iv); + AES_init_ctx_iv(&Ctx, key_rev, iv_rev); + + for (u32 i = 0; i < len; i += 16) + { + Swap16(data_rev, &data[i]); + AES_CTR_xcrypt_buffer(&Ctx, data_rev, 16); + Swap16(&data[i], data_rev); + } + + memcpy(Ctx.RoundKey, &oldkeys[16*0], 16); + memcpy(Ctx.Iv, &oldkeys[16*1], 16); +} + } diff --git a/src/DSi_AES.h b/src/DSi_AES.h index 5e726cd..354c4a7 100644 --- a/src/DSi_AES.h +++ b/src/DSi_AES.h @@ -46,6 +46,9 @@ void WriteKeyNormal(u32 slot, u32 offset, u32 val, u32 mask); void WriteKeyX(u32 slot, u32 offset, u32 val, u32 mask); void WriteKeyY(u32 slot, u32 offset, u32 val, u32 mask); +void GetModcryptKey(u8* romheader, u8* key); +void ApplyModcrypt(u8* data, u32 len, u8* key, u8* iv); + } #endif // DSI_AES_H diff --git a/src/DSi_SD.cpp b/src/DSi_SD.cpp index 44d8d62..796466d 100644 --- a/src/DSi_SD.cpp +++ b/src/DSi_SD.cpp @@ -149,6 +149,15 @@ void DSi_SDHost::SetIRQ(u32 irq) if (irq == 24 || irq == 25) UpdateData32IRQ(); } +void DSi_SDHost::UpdateIRQ(u32 oldmask) +{ + u32 oldflags = IRQStatus & ~oldmask; + u32 newflags = IRQStatus & ~IRQMask; + + if ((oldflags == 0) && (newflags != 0)) + NDS::SetIRQ2(Num ? NDS::IRQ2_DSi_SDIO : NDS::IRQ2_DSi_SDMMC); +} + void DSi_SDHost::SetCardIRQ() { if (!(CardIRQCtl & (1<<0))) return; @@ -424,7 +433,7 @@ u32 DSi_SDHost::ReadFIFO32() return ret; } -int morp = 0; + void DSi_SDHost::Write(u32 addr, u16 val) { //if(Num)printf("SDIO WRITE %08X %04X %08X\n", addr, val, NDS::GetPC(1)); @@ -464,11 +473,21 @@ void DSi_SDHost::Write(u32 addr, u16 val) case 0x01C: IRQStatus &= (val | 0xFFFF0000); return; case 0x01E: IRQStatus &= ((val << 16) | 0xFFFF); return; - case 0x020: IRQMask = (IRQMask & 0x8B7F0000) | (val & 0x031D); return; + case 0x020: + { + u32 oldmask = IRQMask; + IRQMask = (IRQMask & 0x8B7F0000) | (val & 0x031D); + UpdateIRQ(oldmask); + } + return; case 0x022: - IRQMask = (IRQMask & 0x0000031D) | ((val & 0x8B7F) << 16); - if (!DataFIFO[CurFIFO]->IsEmpty()) SetIRQ(24); // checkme - if (DataFIFO[CurFIFO]->IsEmpty()) SetIRQ(25); // checkme + { + u32 oldmask = IRQMask; + IRQMask = (IRQMask & 0x0000031D) | ((val & 0x8B7F) << 16); + UpdateIRQ(oldmask); + if (!DataFIFO[CurFIFO]->IsEmpty()) SetIRQ(24); // checkme + if (DataFIFO[CurFIFO]->IsEmpty()) SetIRQ(25); // checkme + } return; case 0x024: SDClock = val & 0x03FF; return; diff --git a/src/DSi_SD.h b/src/DSi_SD.h index 149b72a..f4ca26c 100644 --- a/src/DSi_SD.h +++ b/src/DSi_SD.h @@ -84,6 +84,7 @@ private: void UpdateData32IRQ(); void ClearIRQ(u32 irq); void SetIRQ(u32 irq); + void UpdateIRQ(u32 oldmask); }; diff --git a/src/NDSCart.cpp b/src/NDSCart.cpp index c3765d8..65cf8ae 100644 --- a/src/NDSCart.cpp +++ b/src/NDSCart.cpp @@ -23,6 +23,7 @@ #include "NDSCart.h" #include "ARM.h" #include "CRC32.h" +#include "DSi_AES.h" #include "Platform.h" @@ -599,6 +600,15 @@ void Key2_Encrypt(u8* data, u32 len) } +void ApplyModcrypt(u32 addr, u32 len, u8* iv) +{return; + u8 key[16]; + + DSi_AES::GetModcryptKey(&CartROM[0], key); + DSi_AES::ApplyModcrypt(&CartROM[addr], len, key, iv); +} + + bool Init() { if (!NDSCart_SRAM::Init()) return false; @@ -980,6 +990,19 @@ bool LoadROM(const char* path, const char* sram, bool direct) CartIsHomebrew = true; } + // re-encrypt modcrypt areas if needed + // TODO: somehow detect whether those are already encrypted + if (true) + { + u32 mod1 = *(u32*)&CartROM[0x220]; + u32 mod2 = *(u32*)&CartROM[0x228]; + + printf("Re-encrypting modcrypt areas: %08X, %08X\n", mod1, mod2); + + if (mod1) ApplyModcrypt(mod1, *(u32*)&CartROM[0x224], &CartROM[0x300]); + if (mod2) ApplyModcrypt(mod2, *(u32*)&CartROM[0x22C], &CartROM[0x314]); + } + // save printf("Save file: %s\n", sram); -- cgit v1.2.3 From e82364f010f6ad4e4883c241a05a4aac10cd75d6 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sat, 19 Oct 2019 16:03:59 +0200 Subject: * some fixes to SD controller support, make it clear that there is no SD inserted, makes Flipnote work somewhat better * immediately clear AES busy flag when the block count is zero (occurs when loading DSi cart games) * implement NDMA start modes that have an old-DMA equivalent (except for GXFIFO mode) now it boots DSi carts! --- src/DSi.cpp | 16 +++++++++- src/DSi.h | 1 + src/DSi_AES.cpp | 90 +++++++++++++++++++++++++------------------------------- src/DSi_NDMA.cpp | 6 ++-- src/DSi_SD.cpp | 62 +++++++++++++++++++++++++++++++++----- src/NDS.cpp | 42 ++++++++++++++++++++++++++ src/NDSCart.cpp | 4 +-- 7 files changed, 159 insertions(+), 62 deletions(-) (limited to 'src/DSi_AES.cpp') diff --git a/src/DSi.cpp b/src/DSi.cpp index 9f07fa1..ef4e6da 100644 --- a/src/DSi.cpp +++ b/src/DSi.cpp @@ -411,6 +411,16 @@ void StallNDMAs() // TODO } +bool NDMAsInMode(u32 cpu, u32 mode) +{ + cpu <<= 2; + if (NDMAs[cpu+0]->IsInMode(mode)) return true; + if (NDMAs[cpu+1]->IsInMode(mode)) return true; + if (NDMAs[cpu+2]->IsInMode(mode)) return true; + if (NDMAs[cpu+3]->IsInMode(mode)) return true; + return false; +} + bool NDMAsRunning(u32 cpu) { cpu <<= 2; @@ -1156,7 +1166,7 @@ u8 ARM9IORead8(u32 addr) return NDS::ARM9IORead8(addr); } - +//u16 dicks = 0; u16 ARM9IORead16(u32 addr) { switch (addr) @@ -1174,6 +1184,8 @@ u16 ARM9IORead16(u32 addr) CASE_READ16_32BIT(0x04004058, MBK[0][6]) CASE_READ16_32BIT(0x0400405C, MBK[0][7]) CASE_READ16_32BIT(0x04004060, MBK[0][8]) + + //case 0x04004202: return dicks & 0xEF1F; } return NDS::ARM9IORead16(addr); @@ -1318,6 +1330,8 @@ void ARM9IOWrite16(u32 addr, u16 val) MapNWRAM_C(6, val & 0xFF); MapNWRAM_C(7, val >> 8); return; + + //case 0x04004202: dicks = val & 0xEF3F; return; } return NDS::ARM9IOWrite16(addr, val); diff --git a/src/DSi.h b/src/DSi.h index bd37550..5697237 100644 --- a/src/DSi.h +++ b/src/DSi.h @@ -47,6 +47,7 @@ bool LoadNAND(); void RunNDMAs(u32 cpu); void StallNDMAs(); +bool NDMAsInMode(u32 cpu, u32 mode); bool NDMAsRunning(u32 cpu); void CheckNDMAs(u32 cpu, u32 mode); void StopNDMAs(u32 cpu, u32 mode); diff --git a/src/DSi_AES.cpp b/src/DSi_AES.cpp index e49ebf5..7aae8f3 100644 --- a/src/DSi_AES.cpp +++ b/src/DSi_AES.cpp @@ -129,28 +129,8 @@ void Reset() memset(CurKey, 0, sizeof(CurKey)); memset(CurMAC, 0, sizeof(CurMAC)); - // initialize keys, as per GBAtek - -#if 0 - // slot 0: modcrypt - *(u32*)&KeyX[0][0] = 0x746E694E; - *(u32*)&KeyX[0][4] = 0x6F646E65; - - // slot 1: 'Tad'/dev.kp - *(u32*)&KeyX[1][0] = 0x4E00004A; - *(u32*)&KeyX[1][4] = 0x4A00004E; - *(u32*)&KeyX[1][8] = (u32)(DSi::ConsoleID >> 32) ^ 0xC80C4B72; - *(u32*)&KeyX[1][12] = (u32)DSi::ConsoleID; - - // slot 3: console-unique eMMC crypto - *(u32*)&KeyX[3][0] = (u32)DSi::ConsoleID; - *(u32*)&KeyX[3][4] = (u32)DSi::ConsoleID ^ 0x24EE6906; - *(u32*)&KeyX[3][8] = (u32)(DSi::ConsoleID >> 32) ^ 0xE65B601D; - *(u32*)&KeyX[3][12] = (u32)(DSi::ConsoleID >> 32); - *(u32*)&KeyY[3][0] = 0x0AB9DC76; - *(u32*)&KeyY[3][4] = 0xBD4DC4D3; - *(u32*)&KeyY[3][8] = 0x202DDD1D; -#endif + // initialize keys + FILE* f = Platform::OpenLocalFile("aeskeys.bin", "rb"); if (f) { @@ -233,12 +213,12 @@ u32 ReadCnt() ret |= InputFIFO->Level(); ret |= (OutputFIFO->Level() << 5); - +//printf("READ AES CNT: %08X, LEVELS: IN=%d OUT=%d\n", ret, InputFIFO->Level(), OutputFIFO->Level()); return ret; } void WriteCnt(u32 val) -{ +{printf("AES CNT = %08X\n", val); u32 oldcnt = Cnt; Cnt = val & 0xFC1FF000; @@ -267,41 +247,51 @@ void WriteCnt(u32 val) // transfer start (checkme) RemBlocks = BlkCnt >> 16; - u8 key[16]; - u8 iv[16]; + if (RemBlocks > 0) + { + u8 key[16]; + u8 iv[16]; - Swap16(key, CurKey); - Swap16(iv, IV); + Swap16(key, CurKey); + Swap16(iv, IV); - if (AESMode < 2) - { - if (BlkCnt & 0xFFFF) printf("AES: CCM EXTRA LEN TODO\n"); + if (AESMode < 2) + { + if (BlkCnt & 0xFFFF) printf("AES: CCM EXTRA LEN TODO\n"); - u32 maclen = (val >> 16) & 0x7; - if (maclen < 1) maclen = 1; + u32 maclen = (val >> 16) & 0x7; + if (maclen < 1) maclen = 1; - iv[0] = 0x02; - for (int i = 0; i < 12; i++) iv[1+i] = iv[4+i]; - iv[13] = 0x00; - iv[14] = 0x00; - iv[15] = 0x01; + iv[0] = 0x02; + for (int i = 0; i < 12; i++) iv[1+i] = iv[4+i]; + iv[13] = 0x00; + iv[14] = 0x00; + iv[15] = 0x01; - AES_init_ctx_iv(&Ctx, key, iv); + AES_init_ctx_iv(&Ctx, key, iv); - iv[0] |= (maclen << 3) | ((BlkCnt & 0xFFFF) ? (1<<6) : 0); - iv[13] = RemBlocks >> 12; - iv[14] = RemBlocks >> 4; - iv[15] = RemBlocks << 4; + iv[0] |= (maclen << 3) | ((BlkCnt & 0xFFFF) ? (1<<6) : 0); + iv[13] = RemBlocks >> 12; + iv[14] = RemBlocks >> 4; + iv[15] = RemBlocks << 4; - memcpy(CurMAC, iv, 16); - AES_ECB_encrypt(&Ctx, CurMAC); + memcpy(CurMAC, iv, 16); + AES_ECB_encrypt(&Ctx, CurMAC); + } + else + { + AES_init_ctx_iv(&Ctx, key, iv); + } + + DSi::CheckNDMAs(1, 0x2A); } else { - AES_init_ctx_iv(&Ctx, key, iv); - } + // no blocks to process? oh well. mark it finished + // CHECKME: does this trigger any IRQ or shit? - DSi::CheckNDMAs(1, 0x2A); + Cnt &= ~(1<<31); + } } printf("AES CNT: %08X / mode=%d key=%d inDMA=%d outDMA=%d blocks=%d\n", @@ -309,7 +299,7 @@ void WriteCnt(u32 val) } void WriteBlkCnt(u32 val) -{ +{printf("AES BLOCK CNT %08X / %d\n", val, val>>16); BlkCnt = val; } @@ -415,7 +405,7 @@ void Update() // CHECKME Cnt &= ~(1<<21); } - +printf("AES: FINISHED\n"); Cnt &= ~(1<<31); if (Cnt & (1<<30)) NDS::SetIRQ2(NDS::IRQ2_DSi_AES); DSi::StopNDMAs(1, 0x2A); diff --git a/src/DSi_NDMA.cpp b/src/DSi_NDMA.cpp index e7fc7ab..19c72b6 100644 --- a/src/DSi_NDMA.cpp +++ b/src/DSi_NDMA.cpp @@ -101,8 +101,10 @@ void DSi_NDMA::WriteCnt(u32 val) Start(); if (StartMode != 0x10 && StartMode != 0x30 && - StartMode != 0x2A && StartMode != 0x2B) - printf("UNIMPLEMENTED ARM%d NDMA%d START MODE %02X, %08X->%08X\n", CPU?7:9, Num, StartMode, SrcAddr, DstAddr); + StartMode != 0x04 && StartMode != 0x06 && StartMode != 0x07 && StartMode != 0x08 && StartMode != 0x09 && + StartMode != 0x24 && StartMode != 0x26 && StartMode != 0x28 && StartMode != 0x29 && StartMode != 0x2A && StartMode != 0x2B) + printf("UNIMPLEMENTED ARM%d NDMA%d START MODE %02X, %08X->%08X LEN=%d BLK=%d CNT=%08X\n", + CPU?7:9, Num, StartMode, SrcAddr, DstAddr, TotalLength, BlockLength, Cnt); } } diff --git a/src/DSi_SD.cpp b/src/DSi_SD.cpp index 796466d..a45a8ce 100644 --- a/src/DSi_SD.cpp +++ b/src/DSi_SD.cpp @@ -91,10 +91,16 @@ void DSi_SDHost::Reset() if (Num == 0) { + // TODO: eventually pull from host filesystem + /*DSi_MMCStorage* sd = new DSi_MMCStorage(this, false, "sd.bin"); + u8 sd_cid[16] = {0xBD, 0x12, 0x34, 0x56, 0x78, 0x03, 0x4D, 0x30, 0x30, 0x46, 0x50, 0x41, 0x00, 0x00, 0x15, 0x00}; + sd->SetCID(sd_cid);*/ + DSi_MMCStorage* sd = NULL; + DSi_MMCStorage* mmc = new DSi_MMCStorage(this, true, "nand.bin"); mmc->SetCID(DSi::eMMC_CID); - // TODO: port 0 (SD) + Ports[0] = sd; Ports[1] = mmc; } else @@ -196,6 +202,14 @@ void DSi_SDHost::FinishSend(u32 param) host->ClearIRQ(25); host->SetIRQ(24); //if (param & 0x2) host->SetIRQ(2); + + // TODO: this is an assumption and should eventually be confirmed + // Flipnote sets DMA blocklen to 128 words and totallen to 1024 words + // so, presumably, DMA should trigger when the FIFO is full + // 'full' being when it reaches whatever BlockLen16 is set to, or the + // other blocklen register, or when it is actually full (but that makes + // less sense) + DSi::CheckNDMAs(1, host->Num ? 0x29 : 0x28); } u32 DSi_SDHost::SendData(u8* data, u32 len) @@ -286,7 +300,7 @@ u32 DSi_SDHost::GetTransferrableLen(u32 len) u16 DSi_SDHost::Read(u32 addr) { - //if(Num)printf("SDIO READ %08X %08X\n", addr, NDS::GetPC(1)); + if(!Num)printf("SDMMC READ %08X %08X\n", addr, NDS::GetPC(1)); switch (addr & 0x1FF) { @@ -307,7 +321,24 @@ u16 DSi_SDHost::Read(u32 addr) case 0x018: return ResponseBuffer[6]; case 0x01A: return ResponseBuffer[7]; - case 0x01C: return (IRQStatus & 0x031D) | 0x0030; // TODO: adjust insert flags for SD card + case 0x01C: + { + u16 ret = (IRQStatus & 0x031D); + + if (!Num) + { + if (Ports[0]) // basic check of whether the SD card is inserted + ret |= 0x0030; + else + ret |= 0x0008; + } + else + { + // SDIO wifi is always inserted, I guess + ret |= 0x0030; + } + return ret; + } case 0x01E: return ((IRQStatus >> 16) & 0x8B7F); case 0x020: return IRQMask & 0x031D; case 0x022: return (IRQMask >> 16) & 0x8B7F; @@ -436,7 +467,7 @@ u32 DSi_SDHost::ReadFIFO32() void DSi_SDHost::Write(u32 addr, u16 val) { - //if(Num)printf("SDIO WRITE %08X %04X %08X\n", addr, val, NDS::GetPC(1)); + if(!Num)printf("SDMMC WRITE %08X %04X %08X\n", addr, val, NDS::GetPC(1)); switch (addr & 0x1FF) { @@ -464,7 +495,7 @@ void DSi_SDHost::Write(u32 addr, u16 val) } return; - case 0x002: PortSelect = val; printf("%s: PORT SELECT %04X\n", SD_DESC, val); return; + case 0x002: PortSelect = (val & 0x040F) | (PortSelect & 0x0300); printf("%s: PORT SELECT %04X (%04X)\n", SD_DESC, val, PortSelect); return; case 0x004: Param = (Param & 0xFFFF0000) | val; return; case 0x006: Param = (Param & 0x0000FFFF) | (val << 16); return; @@ -504,7 +535,7 @@ void DSi_SDHost::Write(u32 addr, u16 val) if (DataFIFO[f]->IsFull()) { // TODO - printf("!!!! %s FIFO FULL\n", SD_DESC); + printf("!!!! %s FIFO (16) FULL\n", SD_DESC); return; } @@ -582,12 +613,14 @@ void DSi_SDHost::WriteFIFO32(u32 val) { if (DataMode != 1) return; + printf("%s: WRITE FIFO32: LEVEL=%d/%d\n", SD_DESC, DataFIFO[CurFIFO]->Level(), (BlockLen16>>1)); + DSi_SDDevice* dev = Ports[PortSelect & 0x1]; u32 f = CurFIFO; if (DataFIFO[f]->IsFull()) { // TODO - printf("!!!! %s FIFO FULL\n", SD_DESC); + printf("!!!! %s FIFO (32) FULL\n", SD_DESC); return; } @@ -608,12 +641,26 @@ void DSi_SDHost::WriteFIFO32(u32 val) } +#define MMC_DESC (Internal?"NAND":"SDcard") + DSi_MMCStorage::DSi_MMCStorage(DSi_SDHost* host, bool internal, const char* path) : DSi_SDDevice(host) { Internal = internal; strncpy(FilePath, path, 1023); FilePath[1023] = '\0'; File = Platform::OpenLocalFile(path, "r+b"); + if (!File) + { + if (internal) + { + // TODO: proper failure + printf("!! MMC file %s does not exist\n", path); + } + else + { + File = Platform::OpenLocalFile(path, "w+b"); + } + } CSR = 0x00000100; // checkme @@ -674,6 +721,7 @@ void DSi_MMCStorage::SendCMD(u8 cmd, u32 param) { // TODO printf("CMD3 on SD card: TODO\n"); + Host->SendResponse((CSR & 0x1FFF) | ((CSR >> 6) & 0x2000) | ((CSR >> 8) & 0xC000) | (1 << 16), true); } return; diff --git a/src/NDS.cpp b/src/NDS.cpp index 95265cf..6933e95 100644 --- a/src/NDS.cpp +++ b/src/NDS.cpp @@ -1371,6 +1371,29 @@ void RunTimers(u32 cpu) +// matching NDMA modes for DSi +const u32 NDMAModes[] = +{ + // ARM9 + + 0x10, // immediate + 0x06, // VBlank + 0x07, // HBlank + 0x08, // scanline start + 0x09, // mainmem FIFO + 0x04, // DS cart slot + 0xFF, // GBA cart slot + 0x0A, // GX FIFO + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + + // ARM7 + + 0x30, // immediate + 0x26, // VBlank + 0x24, // DS cart slot + 0xFF, // wifi / GBA cart slot (TODO) +}; + bool DMAsInMode(u32 cpu, u32 mode) { cpu <<= 2; @@ -1378,6 +1401,13 @@ bool DMAsInMode(u32 cpu, u32 mode) if (DMAs[cpu+1]->IsInMode(mode)) return true; if (DMAs[cpu+2]->IsInMode(mode)) return true; if (DMAs[cpu+3]->IsInMode(mode)) return true; + + if (true) + { + cpu >>= 2; + return DSi::NDMAsInMode(cpu, NDMAModes[mode]); + } + return false; } @@ -1399,6 +1429,12 @@ void CheckDMAs(u32 cpu, u32 mode) DMAs[cpu+1]->StartIfNeeded(mode); DMAs[cpu+2]->StartIfNeeded(mode); DMAs[cpu+3]->StartIfNeeded(mode); + + if (true) + { + cpu >>= 2; + DSi::CheckNDMAs(cpu, NDMAModes[mode]); + } } void StopDMAs(u32 cpu, u32 mode) @@ -1408,6 +1444,12 @@ void StopDMAs(u32 cpu, u32 mode) DMAs[cpu+1]->StopIfNeeded(mode); DMAs[cpu+2]->StopIfNeeded(mode); DMAs[cpu+3]->StopIfNeeded(mode); + + if (true) + { + cpu >>= 2; + DSi::StopNDMAs(cpu, NDMAModes[mode]); + } } diff --git a/src/NDSCart.cpp b/src/NDSCart.cpp index 65cf8ae..b0e9837 100644 --- a/src/NDSCart.cpp +++ b/src/NDSCart.cpp @@ -1227,11 +1227,11 @@ void WriteROMCnt(u32 val) *(u32*)&cmd[4] = *(u32*)&ROMCommand[4]; } - printf("ROM COMMAND %04X %08X %02X%02X%02X%02X%02X%02X%02X%02X SIZE %04X\n", + /*printf("ROM COMMAND %04X %08X %02X%02X%02X%02X%02X%02X%02X%02X SIZE %04X\n", SPICnt, ROMCnt, cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7], - datasize); + datasize);*/ switch (cmd[0]) { -- cgit v1.2.3 From 77f4663f49caffbfb948ab14e42b6f8ade11d58d Mon Sep 17 00:00:00 2001 From: Arisotura Date: Mon, 1 Jun 2020 16:24:59 +0200 Subject: betterer SD/MMC code. Flipnote can save shit! --- src/DSi_AES.cpp | 12 +- src/DSi_I2C.cpp | 16 +-- src/DSi_NWifi.cpp | 10 +- src/DSi_SD.cpp | 398 +++++++++++++++++++++++++++++------------------------- src/DSi_SD.h | 18 ++- 5 files changed, 253 insertions(+), 201 deletions(-) (limited to 'src/DSi_AES.cpp') diff --git a/src/DSi_AES.cpp b/src/DSi_AES.cpp index 7aae8f3..4cb1169 100644 --- a/src/DSi_AES.cpp +++ b/src/DSi_AES.cpp @@ -213,12 +213,12 @@ u32 ReadCnt() ret |= InputFIFO->Level(); ret |= (OutputFIFO->Level() << 5); -//printf("READ AES CNT: %08X, LEVELS: IN=%d OUT=%d\n", ret, InputFIFO->Level(), OutputFIFO->Level()); + return ret; } void WriteCnt(u32 val) -{printf("AES CNT = %08X\n", val); +{ u32 oldcnt = Cnt; Cnt = val & 0xFC1FF000; @@ -294,12 +294,12 @@ void WriteCnt(u32 val) } } - printf("AES CNT: %08X / mode=%d key=%d inDMA=%d outDMA=%d blocks=%d\n", - val, AESMode, (val >> 26) & 0x3, InputDMASize, OutputDMASize, RemBlocks); + //printf("AES CNT: %08X / mode=%d key=%d inDMA=%d outDMA=%d blocks=%d\n", + // val, AESMode, (val >> 26) & 0x3, InputDMASize, OutputDMASize, RemBlocks); } void WriteBlkCnt(u32 val) -{printf("AES BLOCK CNT %08X / %d\n", val, val>>16); +{ BlkCnt = val; } @@ -405,7 +405,7 @@ void Update() // CHECKME Cnt &= ~(1<<21); } -printf("AES: FINISHED\n"); + Cnt &= ~(1<<31); if (Cnt & (1<<30)) NDS::SetIRQ2(NDS::IRQ2_DSi_AES); DSi::StopNDMAs(1, 0x2A); diff --git a/src/DSi_I2C.cpp b/src/DSi_I2C.cpp index b2ca6e4..9984f5e 100644 --- a/src/DSi_I2C.cpp +++ b/src/DSi_I2C.cpp @@ -84,7 +84,7 @@ u8 Read(bool last) return 0; } - printf("BPTWL: read %02X -> %02X\n", CurPos, Registers[CurPos]); + //printf("BPTWL: read %02X -> %02X\n", CurPos, Registers[CurPos]); return Registers[CurPos++]; } @@ -124,7 +124,7 @@ void Write(u8 val, bool last) Registers[CurPos] = val; } - printf("BPTWL: write %02X -> %02X\n", CurPos, val); + //printf("BPTWL: write %02X -> %02X\n", CurPos, val); CurPos++; // CHECKME } @@ -166,7 +166,7 @@ void Reset() void WriteCnt(u8 val) { - printf("I2C: write CNT %02X, %08X\n", val, NDS::GetPC(1)); + //printf("I2C: write CNT %02X, %08X\n", val, NDS::GetPC(1)); // TODO: check ACK flag // TODO: transfer delay @@ -193,7 +193,7 @@ void WriteCnt(u8 val) break; } - printf("I2C read, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast); + //printf("I2C read, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast); } else { @@ -204,7 +204,7 @@ void WriteCnt(u8 val) if (val & (1<<1)) { Device = Data & 0xFE; - printf("I2C: %s start, device=%02X\n", (Data&0x01)?"read":"write", Device); + //printf("I2C: %s start, device=%02X\n", (Data&0x01)?"read":"write", Device); switch (Device) { @@ -219,7 +219,7 @@ void WriteCnt(u8 val) } else { - printf("I2C write, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast); + //printf("I2C write, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast); switch (Device) { @@ -243,12 +243,12 @@ void WriteCnt(u8 val) } u8 ReadData() -{printf("I2C: read data: %02X\n", Data); +{ return Data; } void WriteData(u8 val) -{printf("I2C: write data: %02X\n", val); +{ Data = val; } diff --git a/src/DSi_NWifi.cpp b/src/DSi_NWifi.cpp index 013173f..79bc632 100644 --- a/src/DSi_NWifi.cpp +++ b/src/DSi_NWifi.cpp @@ -515,6 +515,12 @@ void DSi_NWifi::SendCMD(u8 cmd, u32 param) { switch (cmd) { + case 12: + // stop command + // CHECKME: does the SDIO controller actually send those?? + // DSi firmware sets it to send them + return; + case 52: // IO_RW_DIRECT { u32 func = (param >> 28) & 0x7; @@ -608,7 +614,7 @@ void DSi_NWifi::ReadBlock() TransferAddr &= 0x1FFFF; // checkme } } - len = Host->SendData(data, len); + len = Host->DataRX(data, len); if (RemSize > 0) { @@ -628,7 +634,7 @@ void DSi_NWifi::WriteBlock() len = Host->GetTransferrableLen(len); u8 data[0x200]; - if (len = Host->ReceiveData(data, len)) + if (len = Host->DataTX(data, len)) { for (u32 i = 0; i < len; i++) { diff --git a/src/DSi_SD.cpp b/src/DSi_SD.cpp index a45a8ce..5231b99 100644 --- a/src/DSi_SD.cpp +++ b/src/DSi_SD.cpp @@ -24,7 +24,27 @@ #include "Platform.h" -#define SD_DESC (Num?"SDIO":"SD/MMC") +// observed IRQ behavior during transfers +// +// during reads: +// * bit23 is cleared during the first block, always set otherwise. weird +// * bit24 (RXRDY) gets set when the FIFO is full +// +// during reads with FIFO32: +// * FIFO16 drains directly into FIFO32 +// * when bit24 is set, FIFO32 is already full (with contents from the other FIFO) +// * reading from an empty FIFO just wraps around (and sets bit21) +// * FIFO32 starts filling when bit24 would be set? +// +// +// TX: +// * when sending command, if current FIFO full +// * upon ContinueTransfer(), if current FIFO full +// * -> upon DataTX() if current FIFO full +// * when filling FIFO + + +#define SD_DESC Num?"SDIO":"SD/MMC" DSi_SDHost::DSi_SDHost(u32 num) @@ -33,6 +53,7 @@ DSi_SDHost::DSi_SDHost(u32 num) DataFIFO[0] = new FIFO(0x100); DataFIFO[1] = new FIFO(0x100); + DataFIFO32 = new FIFO(0x80); Ports[0] = NULL; Ports[1] = NULL; @@ -42,6 +63,7 @@ DSi_SDHost::~DSi_SDHost() { delete DataFIFO[0]; delete DataFIFO[1]; + delete DataFIFO32; if (Ports[0]) delete Ports[0]; if (Ports[1]) delete Ports[1]; @@ -69,6 +91,7 @@ void DSi_SDHost::Reset() DataFIFO[0]->Clear(); DataFIFO[1]->Clear(); CurFIFO = 0; + DataFIFO32->Clear(); IRQStatus = 0; IRQMask = 0x8B7F031D; @@ -84,6 +107,8 @@ void DSi_SDHost::Reset() BlockLen16 = 0; BlockLen32 = 0; StopAction = 0; + TXReq = false; + if (Ports[0]) delete Ports[0]; if (Ports[1]) delete Ports[1]; Ports[0] = NULL; @@ -125,8 +150,8 @@ void DSi_SDHost::UpdateData32IRQ() oldflags &= (Data32IRQ >> 11); Data32IRQ &= ~0x0300; - if (IRQStatus & (1<<24)) Data32IRQ |= (1<<8); - if (!(IRQStatus & (1<<25))) Data32IRQ |= (1<<9); + if (DataFIFO32->Level() >= (BlockLen32>>2)) Data32IRQ |= (1<<8); + if (!DataFIFO32->IsEmpty()) Data32IRQ |= (1<<9); u32 newflags = ((Data32IRQ >> 8) & 0x1) | (((~Data32IRQ) >> 8) & 0x2); newflags &= (Data32IRQ >> 11); @@ -138,8 +163,6 @@ void DSi_SDHost::UpdateData32IRQ() void DSi_SDHost::ClearIRQ(u32 irq) { IRQStatus &= ~(1<CurFIFO ^= 1; + host->CheckSwapFIFO(); - host->ClearIRQ(25); - host->SetIRQ(24); - //if (param & 0x2) host->SetIRQ(2); - - // TODO: this is an assumption and should eventually be confirmed - // Flipnote sets DMA blocklen to 128 words and totallen to 1024 words - // so, presumably, DMA should trigger when the FIFO is full - // 'full' being when it reaches whatever BlockLen16 is set to, or the - // other blocklen register, or when it is actually full (but that makes - // less sense) - DSi::CheckNDMAs(1, host->Num ? 0x29 : 0x28); + if (host->DataMode == 1) + host->UpdateFIFO32(); + else + host->SetIRQ(24); } -u32 DSi_SDHost::SendData(u8* data, u32 len) +u32 DSi_SDHost::DataRX(u8* data, u32 len) { - //printf("%s: data RX, len=%d, blkcnt=%d (%d) blklen=%d, irq=%08X\n", SD_DESC, len, BlockCount16, BlockCountInternal, BlockLen16, IRQMask); if (len != BlockLen16) { printf("!! BAD BLOCKLEN\n"); len = BlockLen16; } bool last = (BlockCountInternal == 0); @@ -232,52 +245,112 @@ u32 DSi_SDHost::SendData(u8* data, u32 len) // send-command function starts polling IRQ status u32 param = Num | (last << 1); NDS::ScheduleEvent(Num ? NDS::Event_DSi_SDIOTransfer : NDS::Event_DSi_SDMMCTransfer, - false, 512, FinishSend, param); + false, 512, FinishRX, param); return len; } -void DSi_SDHost::FinishReceive(u32 param) +void DSi_SDHost::FinishTX(u32 param) { DSi_SDHost* host = (param & 0x1) ? DSi::SDIO : DSi::SDMMC; DSi_SDDevice* dev = host->Ports[host->PortSelect & 0x1]; - host->ClearIRQ(24); - host->SetIRQ(25); + if (host->BlockCountInternal == 0) + { + if (host->StopAction & (1<<8)) + { + if (dev) dev->SendCMD(12, 0); + } - if (dev) dev->ContinueTransfer(); + // CHECKME: presumably IRQ2 should not trigger here, but rather + // when the data transfer is done + //SetIRQ(0); + host->SetIRQ(2); + host->TXReq = false; + } + else + { + if (dev) dev->ContinueTransfer(); + } } -u32 DSi_SDHost::ReceiveData(u8* data, u32 len) +u32 DSi_SDHost::DataTX(u8* data, u32 len) { - printf("%s: data TX, len=%d, blkcnt=%d (%d) blklen=%d, irq=%08X\n", SD_DESC, len, BlockCount16, BlockCountInternal, BlockLen16, IRQMask); - if (len != BlockLen16) { printf("!! BAD BLOCKLEN\n"); len = BlockLen16; } + TXReq = true; u32 f = CurFIFO; - if ((DataFIFO[f]->Level() << 1) < len) + + if (DataMode == 1) { - printf("%s: FIFO not full enough for a transfer (%d / %d)\n", SD_DESC, DataFIFO[f]->Level()<<1, len); - return 0; + if ((DataFIFO32->Level() << 2) < len) + { + if (DataFIFO32->IsEmpty()) + { + SetIRQ(25); + DSi::CheckNDMAs(1, Num ? 0x29 : 0x28); + } + return 0; + } + + // drain FIFO32 into FIFO16 + + if (!DataFIFO[f]->IsEmpty()) printf("VERY BAD!! TRYING TO DRAIN FIFO32 INTO FIFO16 BUT IT CONTAINS SHIT ALREADY\n"); + for (;;) + { + u32 f = CurFIFO; + if ((DataFIFO[f]->Level() << 1) >= BlockLen16) break; + if (DataFIFO32->IsEmpty()) break; + + u32 val = DataFIFO32->Read(); + DataFIFO[f]->Write(val & 0xFFFF); + DataFIFO[f]->Write(val >> 16); + } + + UpdateData32IRQ(); + + if (BlockCount32 > 1) + BlockCount32--; + } + else + { + if ((DataFIFO[f]->Level() << 1) < len) + { + if (DataFIFO[f]->IsEmpty()) SetIRQ(25); + return 0; + } } - DSi_SDDevice* dev = Ports[PortSelect & 0x1]; for (u32 i = 0; i < len; i += 2) *(u16*)&data[i] = DataFIFO[f]->Read(); CurFIFO ^= 1; + BlockCountInternal--; + + NDS::ScheduleEvent(Num ? NDS::Event_DSi_SDIOTransfer : NDS::Event_DSi_SDMMCTransfer, + false, 512, FinishTX, Num); + + return len; +} + +u32 DSi_SDHost::GetTransferrableLen(u32 len) +{ + if (len > BlockLen16) len = BlockLen16; // checkme + return len; +} + +void DSi_SDHost::CheckRX() +{ + DSi_SDDevice* dev = Ports[PortSelect & 0x1]; + + CheckSwapFIFO(); if (BlockCountInternal <= 1) { - printf("%s: data TX complete", SD_DESC); - if (StopAction & (1<<8)) { - printf(", sending CMD12"); if (dev) dev->SendCMD(12, 0); } - printf("\n"); - // CHECKME: presumably IRQ2 should not trigger here, but rather // when the data transfer is done //SetIRQ(0); @@ -286,22 +359,34 @@ u32 DSi_SDHost::ReceiveData(u8* data, u32 len) else { BlockCountInternal--; - } - return len; + if (dev) dev->ContinueTransfer(); + } } -u32 DSi_SDHost::GetTransferrableLen(u32 len) +void DSi_SDHost::CheckTX() { - if (len > BlockLen16) len = BlockLen16; // checkme - return len; + if (!TXReq) return; + + if (DataMode == 1) + { + if ((DataFIFO32->Level() << 2) < BlockLen32) + return; + } + else + { + u32 f = CurFIFO; + if ((DataFIFO[f]->Level() << 1) < BlockLen16) + return; + } + + DSi_SDDevice* dev = Ports[PortSelect & 0x1]; + if (dev) dev->ContinueTransfer(); } u16 DSi_SDHost::Read(u32 addr) { - if(!Num)printf("SDMMC READ %08X %08X\n", addr, NDS::GetPC(1)); - switch (addr & 0x1FF) { case 0x000: return Command; @@ -353,53 +438,7 @@ u16 DSi_SDHost::Read(u32 addr) case 0x036: return CardIRQStatus; case 0x038: return CardIRQMask; - case 0x030: // FIFO16 - { - // TODO: decrement BlockLen???? - - u32 f = CurFIFO; - if (DataFIFO[f]->IsEmpty()) - { - // TODO - return 0; - } - - DSi_SDDevice* dev = Ports[PortSelect & 0x1]; - u16 ret = DataFIFO[f]->Read(); - - if (DataFIFO[f]->IsEmpty()) - { - ClearIRQ(24); - - if (BlockCountInternal <= 1) - { - printf("%s: data RX complete", SD_DESC); - - if (StopAction & (1<<8)) - { - printf(", sending CMD12"); - if (dev) dev->SendCMD(12, 0); - } - - printf("\n"); - - // CHECKME: presumably IRQ2 should not trigger here, but rather - // when the data transfer is done - //SetIRQ(0); - SetIRQ(2); - } - else - { - BlockCountInternal--; - - if (dev) dev->ContinueTransfer(); - } - - SetIRQ(25); - } - - return ret; - } + case 0x030: return ReadFIFO16(); case 0x0D8: return DataCtl; @@ -414,61 +453,52 @@ u16 DSi_SDHost::Read(u32 addr) return 0; } -u32 DSi_SDHost::ReadFIFO32() +u16 DSi_SDHost::ReadFIFO16() { - if (DataMode != 1) return 0; - - // TODO: decrement BlockLen???? - u32 f = CurFIFO; if (DataFIFO[f]->IsEmpty()) { // TODO + // on hardware it seems to wrap around. underflow bit is set upon the first 'empty' read. return 0; } DSi_SDDevice* dev = Ports[PortSelect & 0x1]; - u32 ret = DataFIFO[f]->Read(); - ret |= (DataFIFO[f]->Read() << 16); + u16 ret = DataFIFO[f]->Read(); if (DataFIFO[f]->IsEmpty()) { - ClearIRQ(24); - - if (BlockCountInternal <= 1) - { - printf("%s: data32 RX complete", SD_DESC); + CheckRX(); + } - if (StopAction & (1<<8)) - { - printf(", sending CMD12"); - if (dev) dev->SendCMD(12, 0); - } + return ret; +} - printf("\n"); +u32 DSi_SDHost::ReadFIFO32() +{ + if (DataMode != 1) return 0; - // CHECKME: presumably IRQ2 should not trigger here, but rather - // when the data transfer is done - //SetIRQ(0); - SetIRQ(2); - } - else - { - BlockCountInternal--; + if (DataFIFO32->IsEmpty()) + { + // TODO + return 0; + } - if (dev) dev->ContinueTransfer(); - } + DSi_SDDevice* dev = Ports[PortSelect & 0x1]; + u32 ret = DataFIFO32->Read(); - SetIRQ(25); + if (DataFIFO32->IsEmpty()) + { + CheckRX(); } + UpdateData32IRQ(); + return ret; } void DSi_SDHost::Write(u32 addr, u16 val) { - if(!Num)printf("SDMMC WRITE %08X %04X %08X\n", addr, val, NDS::GetPC(1)); - switch (addr & 0x1FF) { case 0x000: @@ -528,36 +558,10 @@ void DSi_SDHost::Write(u32 addr, u16 val) return; case 0x028: SDOption = val & 0xC1FF; return; - case 0x030: // FIFO16 - { - DSi_SDDevice* dev = Ports[PortSelect & 0x1]; - u32 f = CurFIFO; - if (DataFIFO[f]->IsFull()) - { - // TODO - printf("!!!! %s FIFO (16) FULL\n", SD_DESC); - return; - } - - DataFIFO[f]->Write(val); - - if (DataFIFO[f]->Level() < (BlockLen16>>1)) - { - ClearIRQ(25); - SetIRQ(24); - return; - } - - // we completed one block, send it to the SD card - // TODO measure the actual delay!! - NDS::ScheduleEvent(Num ? NDS::Event_DSi_SDIOTransfer : NDS::Event_DSi_SDMMCTransfer, - false, 2048, FinishReceive, Num); - } - return; + case 0x030: WriteFIFO16(val); return; case 0x034: CardIRQCtl = val & 0x0305; - printf("[%d] CardIRQCtl = %04X\n", Num, val); SetCardIRQ(); return; case 0x036: @@ -565,7 +569,6 @@ void DSi_SDHost::Write(u32 addr, u16 val) return; case 0x038: CardIRQMask = val & 0xC007; - printf("[%d] CardIRQMask = %04X\n", Num, val); SetCardIRQ(); return; @@ -593,12 +596,7 @@ void DSi_SDHost::Write(u32 addr, u16 val) case 0x100: Data32IRQ = (val & 0x1802) | (Data32IRQ & 0x0300); - if (val & (1<<10)) - { - // kind of hacky - u32 f = CurFIFO; - DataFIFO[f]->Clear(); - } + if (val & (1<<10)) DataFIFO32->Clear(); DataMode = ((DataCtl >> 1) & 0x1) & ((Data32IRQ >> 1) & 0x1); printf("%s: data mode %d-bit\n", SD_DESC, DataMode?32:16); return; @@ -609,35 +607,76 @@ void DSi_SDHost::Write(u32 addr, u16 val) printf("unknown %s write %08X %04X\n", SD_DESC, addr, val); } -void DSi_SDHost::WriteFIFO32(u32 val) +void DSi_SDHost::WriteFIFO16(u16 val) { - if (DataMode != 1) return; - - printf("%s: WRITE FIFO32: LEVEL=%d/%d\n", SD_DESC, DataFIFO[CurFIFO]->Level(), (BlockLen16>>1)); - DSi_SDDevice* dev = Ports[PortSelect & 0x1]; u32 f = CurFIFO; if (DataFIFO[f]->IsFull()) { // TODO - printf("!!!! %s FIFO (32) FULL\n", SD_DESC); + printf("!!!! %s FIFO (16) FULL\n", SD_DESC); return; } - DataFIFO[f]->Write(val & 0xFFFF); - DataFIFO[f]->Write(val >> 16); + DataFIFO[f]->Write(val); + + CheckTX(); +} + +void DSi_SDHost::WriteFIFO32(u32 val) +{ + if (DataMode != 1) return; - if (DataFIFO[f]->Level() < (BlockLen16>>1)) + if (DataFIFO32->IsFull()) { - ClearIRQ(25); - SetIRQ(24); + // TODO + printf("!!!! %s FIFO (32) FULL\n", SD_DESC); return; } - // we completed one block, send it to the SD card - // TODO measure the actual delay!! - NDS::ScheduleEvent(Num ? NDS::Event_DSi_SDIOTransfer : NDS::Event_DSi_SDMMCTransfer, - false, 2048, FinishReceive, Num); + DataFIFO32->Write(val); + + CheckTX(); + + UpdateData32IRQ(); +} + +void DSi_SDHost::UpdateFIFO32() +{ + // check whether we can drain FIFO32 into FIFO16, or vice versa + + if (DataMode != 1) return; + + if (!DataFIFO32->IsEmpty()) printf("VERY BAD!! TRYING TO DRAIN FIFO16 INTO FIFO32 BUT IT CONTAINS SHIT ALREADY\n"); + for (;;) + { + u32 f = CurFIFO; + if ((DataFIFO32->Level() << 2) >= BlockLen32) break; + if (DataFIFO[f]->IsEmpty()) break; + + u32 val = DataFIFO[f]->Read(); + val |= (DataFIFO[f]->Read() << 16); + DataFIFO32->Write(val); + } + + UpdateData32IRQ(); + + if ((DataFIFO32->Level() << 2) >= BlockLen32) + { + DSi::CheckNDMAs(1, Num ? 0x29 : 0x28); + } +} + +void DSi_SDHost::CheckSwapFIFO() +{ + // check whether we can swap the FIFOs + + u32 f = CurFIFO; + bool cur_empty = (DataMode == 1) ? DataFIFO32->IsEmpty() : DataFIFO[f]->IsEmpty(); + if (cur_empty && ((DataFIFO[f^1]->Level() << 1) >= BlockLen16)) + { + CurFIFO ^= 1; + } } @@ -813,7 +852,7 @@ void DSi_MMCStorage::SendACMD(u8 cmd, u32 param) case 13: // get SSR Host->SendResponse(CSR, true); - Host->SendData(SSR, 64); + Host->DataRX(SSR, 64); return; case 41: // set operating conditions @@ -834,7 +873,7 @@ void DSi_MMCStorage::SendACMD(u8 cmd, u32 param) case 51: // get SCR Host->SendResponse(CSR, true); - Host->SendData(SCR, 8); + Host->DataRX(SCR, 8); return; } @@ -863,8 +902,6 @@ void DSi_MMCStorage::ContinueTransfer() u32 DSi_MMCStorage::ReadBlock(u64 addr) { - //printf("SD/MMC: reading block @ %08X, len=%08X\n", addr, BlockSize); - u32 len = BlockSize; len = Host->GetTransferrableLen(len); @@ -874,18 +911,17 @@ u32 DSi_MMCStorage::ReadBlock(u64 addr) fseek(File, addr, SEEK_SET); fread(data, 1, len, File); } - return Host->SendData(data, len); + + return Host->DataRX(data, len); } u32 DSi_MMCStorage::WriteBlock(u64 addr) { - printf("SD/MMC: write block @ %08X, len=%08X\n", addr, BlockSize); - u32 len = BlockSize; len = Host->GetTransferrableLen(len); u8 data[0x200]; - if (len = Host->ReceiveData(data, len)) + if (len = Host->DataTX(data, len)) { if (File) { diff --git a/src/DSi_SD.h b/src/DSi_SD.h index f4ca26c..2862173 100644 --- a/src/DSi_SD.h +++ b/src/DSi_SD.h @@ -36,20 +36,29 @@ public: void DoSavestate(Savestate* file); - static void FinishSend(u32 param); - static void FinishReceive(u32 param); + static void FinishRX(u32 param); + static void FinishTX(u32 param); void SendResponse(u32 val, bool last); - u32 SendData(u8* data, u32 len); - u32 ReceiveData(u8* data, u32 len); + u32 DataRX(u8* data, u32 len); + u32 DataTX(u8* data, u32 len); u32 GetTransferrableLen(u32 len); + void CheckRX(); + void CheckTX(); + bool TXReq; + void SetCardIRQ(); u16 Read(u32 addr); void Write(u32 addr, u16 val); + u16 ReadFIFO16(); + void WriteFIFO16(u16 val); u32 ReadFIFO32(); void WriteFIFO32(u32 val); + void UpdateFIFO32(); + void CheckSwapFIFO(); + private: u32 Num; @@ -78,6 +87,7 @@ private: FIFO* DataFIFO[2]; u32 CurFIFO; // FIFO accessible for read/write + FIFO* DataFIFO32; DSi_SDDevice* Ports[2]; -- cgit v1.2.3 From ee9fe327e2c1c5b9289540a710d4ad2ac04e65c8 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Mon, 1 Jun 2020 23:13:38 +0200 Subject: remove requirement for aeskeys.bin and boot2_7/9.bin --- src/DSi.cpp | 87 +++++++++++++++++++++++++++++++++------------------------ src/DSi_AES.cpp | 38 ++++++++++++------------- 2 files changed, 69 insertions(+), 56 deletions(-) (limited to 'src/DSi_AES.cpp') diff --git a/src/DSi.cpp b/src/DSi.cpp index 520b269..6a60f80 100644 --- a/src/DSi.cpp +++ b/src/DSi.cpp @@ -31,6 +31,8 @@ #include "DSi_SD.h" #include "DSi_AES.h" +#include "tiny-AES-c/aes.hpp" + namespace NDS { @@ -341,52 +343,65 @@ bool LoadNAND() MBK[0][8] = mbk[11]; MBK[1][8] = mbk[11]; - // load binaries - // TODO: optionally support loading from actual NAND? - // currently decrypted binaries have to be provided - // they can be decrypted with twltool + // load boot2 binaries - FILE* bin; + AES_ctx ctx; + const u8 boot2key[16] = {0xAD, 0x34, 0xEC, 0xF9, 0x62, 0x6E, 0xC2, 0x3A, 0xF6, 0xB4, 0x6C, 0x00, 0x80, 0x80, 0xEE, 0x98}; + u8 boot2iv[16]; + u8 tmp[16]; + u32 dstaddr; - bin = Platform::OpenLocalFile("boot2_9.bin", "rb"); - if (bin) - { - u32 dstaddr = bootparams[2]; - for (u32 i = 0; i < bootparams[1]; i += 4) - { - u32 _tmp; - fread(&_tmp, 4, 1, bin); - ARM9Write32(dstaddr, _tmp); - dstaddr += 4; - } + *(u32*)&tmp[0] = bootparams[3]; + *(u32*)&tmp[4] = -bootparams[3]; + *(u32*)&tmp[8] = ~bootparams[3]; + *(u32*)&tmp[12] = 0; + for (int i = 0; i < 16; i++) boot2iv[i] = tmp[15-i]; - fclose(bin); - } - else - { - printf("ARM9 boot2 not found\n"); - } + AES_init_ctx_iv(&ctx, boot2key, boot2iv); - bin = Platform::OpenLocalFile("boot2_7.bin", "rb"); - if (bin) + fseek(f, bootparams[0], SEEK_SET); + dstaddr = bootparams[2]; + for (u32 i = 0; i < bootparams[3]; i += 16) { - u32 dstaddr = bootparams[6]; - for (u32 i = 0; i < bootparams[5]; i += 4) - { - u32 _tmp; - fread(&_tmp, 4, 1, bin); - ARM7Write32(dstaddr, _tmp); - dstaddr += 4; - } + u8 data[16]; + fread(data, 16, 1, f); + + for (int j = 0; j < 16; j++) tmp[j] = data[15-j]; + AES_CTR_xcrypt_buffer(&ctx, tmp, 16); + for (int j = 0; j < 16; j++) data[j] = tmp[15-j]; - fclose(bin); + ARM9Write32(dstaddr, *(u32*)&data[0]); dstaddr += 4; + ARM9Write32(dstaddr, *(u32*)&data[4]); dstaddr += 4; + ARM9Write32(dstaddr, *(u32*)&data[8]); dstaddr += 4; + ARM9Write32(dstaddr, *(u32*)&data[12]); dstaddr += 4; } - else + + *(u32*)&tmp[0] = bootparams[7]; + *(u32*)&tmp[4] = -bootparams[7]; + *(u32*)&tmp[8] = ~bootparams[7]; + *(u32*)&tmp[12] = 0; + for (int i = 0; i < 16; i++) boot2iv[i] = tmp[15-i]; + + AES_init_ctx_iv(&ctx, boot2key, boot2iv); + + fseek(f, bootparams[4], SEEK_SET); + dstaddr = bootparams[6]; + for (u32 i = 0; i < bootparams[7]; i += 16) { - printf("ARM7 boot2 not found\n"); + u8 data[16]; + fread(data, 16, 1, f); + + for (int j = 0; j < 16; j++) tmp[j] = data[15-j]; + AES_CTR_xcrypt_buffer(&ctx, tmp, 16); + for (int j = 0; j < 16; j++) data[j] = tmp[15-j]; + + ARM7Write32(dstaddr, *(u32*)&data[0]); dstaddr += 4; + ARM7Write32(dstaddr, *(u32*)&data[4]); dstaddr += 4; + ARM7Write32(dstaddr, *(u32*)&data[8]); dstaddr += 4; + ARM7Write32(dstaddr, *(u32*)&data[12]); dstaddr += 4; } - // repoint CPUs to the boot2 binaries + // repoint the CPUs to the boot2 binaries BootAddr[0] = bootparams[2]; BootAddr[1] = bootparams[6]; diff --git a/src/DSi_AES.cpp b/src/DSi_AES.cpp index 4cb1169..6a8ffad 100644 --- a/src/DSi_AES.cpp +++ b/src/DSi_AES.cpp @@ -131,26 +131,24 @@ void Reset() // initialize keys - FILE* f = Platform::OpenLocalFile("aeskeys.bin", "rb"); - if (f) - { - fread(KeyNormal[0], 16, 1, f); - fread(KeyX[0], 16, 1, f); - fread(KeyY[0], 16, 1, f); - fread(KeyNormal[1], 16, 1, f); - fread(KeyX[1], 16, 1, f); - fread(KeyY[1], 16, 1, f); - fread(KeyNormal[2], 16, 1, f); - fread(KeyX[2], 16, 1, f); - fread(KeyY[2], 16, 1, f); - fread(KeyNormal[3], 16, 1, f); - fread(KeyX[3], 16, 1, f); - fread(KeyY[3], 16, 1, f); - - fclose(f); - } - else - printf("AES: aeskeys.bin not found\n"); + // slot 0: modcrypt + *(u32*)&KeyX[0][0] = 0x746E694E; + *(u32*)&KeyX[0][4] = 0x6F646E65; + + // slot 1: 'Tad'/dev.kp + *(u32*)&KeyX[1][0] = 0x4E00004A; + *(u32*)&KeyX[1][4] = 0x4A00004E; + *(u32*)&KeyX[1][8] = (u32)(DSi::ConsoleID >> 32) ^ 0xC80C4B72; + *(u32*)&KeyX[1][12] = (u32)DSi::ConsoleID; + + // slot 3: console-unique eMMC crypto + *(u32*)&KeyX[3][0] = (u32)DSi::ConsoleID; + *(u32*)&KeyX[3][4] = (u32)DSi::ConsoleID ^ 0x24EE6906; + *(u32*)&KeyX[3][8] = (u32)(DSi::ConsoleID >> 32) ^ 0xE65B601D; + *(u32*)&KeyX[3][12] = (u32)(DSi::ConsoleID >> 32); + *(u32*)&KeyY[3][0] = 0x0AB9DC76; + *(u32*)&KeyY[3][4] = 0xBD4DC4D3; + *(u32*)&KeyY[3][8] = 0x202DDD1D; } -- cgit v1.2.3