2009-04-03 16:27:19 +02:00
|
|
|
/*
|
|
|
|
mini - a Free Software replacement for the Nintendo/BroadOn IOS.
|
|
|
|
|
|
|
|
crypto support
|
|
|
|
|
2009-04-13 02:59:01 +02:00
|
|
|
Copyright (C) 2008, 2009 Haxx Enterprises <bushing@gmail.com>
|
2009-04-13 22:13:45 +02:00
|
|
|
Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
|
2009-04-03 16:27:19 +02:00
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, version 2.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
|
|
|
|
*/
|
2009-01-17 15:05:13 +01:00
|
|
|
#include "crypto.h"
|
|
|
|
#include "hollywood.h"
|
|
|
|
#include "utils.h"
|
|
|
|
#include "memory.h"
|
|
|
|
#include "irq.h"
|
2009-01-30 13:43:35 +01:00
|
|
|
#include "ipc.h"
|
|
|
|
#include "gecko.h"
|
|
|
|
#include "string.h"
|
2009-02-16 13:52:26 +01:00
|
|
|
#include "seeprom.h"
|
2009-01-17 15:05:13 +01:00
|
|
|
|
|
|
|
#define AES_CMD_RESET 0
|
|
|
|
#define AES_CMD_DECRYPT 0x9800
|
|
|
|
|
2009-01-26 16:07:36 +01:00
|
|
|
otp_t otp;
|
2009-02-16 13:52:26 +01:00
|
|
|
seeprom_t seeprom;
|
2009-01-17 15:05:13 +01:00
|
|
|
|
|
|
|
void crypto_read_otp(void)
|
|
|
|
{
|
|
|
|
u32 *otpd = (u32*)&otp;
|
|
|
|
int i;
|
|
|
|
for (i=0; i< 0x20; i++) {
|
|
|
|
write32(HW_OTPCMD,0x80000000|i);
|
|
|
|
*otpd++ = read32(HW_OTPDATA);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-16 13:52:26 +01:00
|
|
|
void crypto_read_seeprom(void)
|
|
|
|
{
|
2009-03-10 07:05:11 +01:00
|
|
|
seeprom_read(&seeprom, 0, sizeof(seeprom) / 2);
|
2009-02-16 13:52:26 +01:00
|
|
|
}
|
2009-01-17 15:05:13 +01:00
|
|
|
|
|
|
|
void crypto_initialize()
|
|
|
|
{
|
|
|
|
crypto_read_otp();
|
2009-02-16 13:52:26 +01:00
|
|
|
crypto_read_seeprom();
|
2009-01-17 15:05:13 +01:00
|
|
|
write32(AES_CMD, 0);
|
|
|
|
while (read32(AES_CMD) != 0);
|
|
|
|
irq_enable(IRQ_AES);
|
|
|
|
}
|
|
|
|
|
2009-01-30 13:43:35 +01:00
|
|
|
void crypto_ipc(volatile ipc_request *req)
|
|
|
|
{
|
|
|
|
switch (req->req) {
|
|
|
|
case IPC_KEYS_GETOTP:
|
|
|
|
memcpy((void *)req->args[0], &otp, sizeof(otp));
|
|
|
|
dc_flushrange((void *)req->args[0], sizeof(otp));
|
|
|
|
break;
|
2009-02-16 13:52:26 +01:00
|
|
|
case IPC_KEYS_GETEEP:
|
|
|
|
memcpy((void *)req->args[0], &seeprom, sizeof(seeprom));
|
|
|
|
dc_flushrange((void *)req->args[0], sizeof(seeprom));
|
|
|
|
break;
|
2009-01-30 13:43:35 +01:00
|
|
|
default:
|
|
|
|
gecko_printf("IPC: unknown SLOW CRYPTO request %04x\n",
|
|
|
|
req->req);
|
|
|
|
}
|
|
|
|
ipc_post(req->code, req->tag, 0);
|
|
|
|
}
|
|
|
|
|
2009-01-17 15:05:13 +01:00
|
|
|
|
|
|
|
static int _aes_irq = 0;
|
|
|
|
|
|
|
|
void aes_irq()
|
|
|
|
{
|
|
|
|
_aes_irq = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void aes_command(u16 cmd, u8 iv_keep, u32 blocks)
|
|
|
|
{
|
|
|
|
if (blocks != 0)
|
|
|
|
blocks--;
|
|
|
|
_aes_irq = 0;
|
|
|
|
write32(AES_CMD, (cmd << 16) | (iv_keep ? 0x1000 : 0) | (blocks&0x7f));
|
|
|
|
while (read32(AES_CMD) & 0x80000000);
|
|
|
|
}
|
|
|
|
|
|
|
|
void aes_reset(void)
|
|
|
|
{
|
|
|
|
write32(AES_CMD, 0);
|
|
|
|
while (read32(AES_CMD) != 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void aes_set_iv(u8 *iv)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for(i = 0; i < 4; i++) {
|
|
|
|
write32(AES_IV, *(u32 *)iv);
|
|
|
|
iv += 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void aes_empty_iv()
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for(i = 0; i < 4; i++)
|
|
|
|
write32(AES_IV, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void aes_set_key(u8 *key)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for(i = 0; i < 4; i++) {
|
|
|
|
write32(AES_KEY, *(u32 *)key);
|
|
|
|
key += 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void aes_decrypt(u8 *src, u8 *dst, u32 blocks, u8 keep_iv)
|
|
|
|
{
|
|
|
|
int this_blocks = 0;
|
|
|
|
while(blocks > 0) {
|
|
|
|
this_blocks = blocks;
|
|
|
|
if (this_blocks > 0x80)
|
|
|
|
this_blocks = 0x80;
|
2009-03-07 20:56:03 +01:00
|
|
|
|
2009-03-06 05:26:34 +01:00
|
|
|
write32(AES_SRC, dma_addr(src));
|
|
|
|
write32(AES_DEST, dma_addr(dst));
|
2009-03-07 20:56:03 +01:00
|
|
|
|
|
|
|
dc_flushrange(src, blocks * 16);
|
2009-03-18 17:51:07 +01:00
|
|
|
dc_invalidaterange(dst, blocks * 16);
|
2009-03-07 20:56:03 +01:00
|
|
|
|
|
|
|
ahb_flush_to(AHB_AES);
|
2009-01-17 15:05:13 +01:00
|
|
|
aes_command(AES_CMD_DECRYPT, keep_iv, this_blocks);
|
2009-03-07 20:56:03 +01:00
|
|
|
ahb_flush_from(AHB_AES);
|
|
|
|
ahb_flush_to(AHB_STARLET);
|
2009-01-17 15:05:13 +01:00
|
|
|
|
|
|
|
blocks -= this_blocks;
|
|
|
|
src += this_blocks<<4;
|
|
|
|
dst += this_blocks<<4;
|
|
|
|
keep_iv = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2009-01-30 13:43:35 +01:00
|
|
|
void aes_ipc(volatile ipc_request *req)
|
|
|
|
{
|
|
|
|
switch (req->req) {
|
|
|
|
case IPC_AES_RESET:
|
|
|
|
aes_reset();
|
|
|
|
break;
|
|
|
|
case IPC_AES_SETIV:
|
|
|
|
aes_set_iv((u8 *)req->args);
|
|
|
|
break;
|
|
|
|
case IPC_AES_SETKEY:
|
|
|
|
aes_set_key((u8 *)req->args);
|
|
|
|
break;
|
|
|
|
case IPC_AES_DECRYPT:
|
|
|
|
aes_decrypt((u8 *)req->args[0], (u8 *)req->args[1],
|
|
|
|
req->args[2], req->args[3]);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
gecko_printf("IPC: unknown SLOW AES request %04x\n",
|
|
|
|
req->req);
|
|
|
|
}
|
|
|
|
ipc_post(req->code, req->tag, 0);
|
|
|
|
}
|
2009-04-13 22:13:45 +02:00
|
|
|
|