iBoot/drivers/apple/sha2/sha2.c

209 lines
4.8 KiB
C

/*
* Copyright (C) 2009 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#include <debug.h>
#include <platform/clocks.h>
#include <platform/int.h>
#include <platform/soc/hwclocks.h>
#include <drivers/sha1.h>
#include "sha2.h"
#if (BYTE_ORDER != LITTLE_ENDIAN)
#error "Sha2 driver currently requires a little endian machine"
#endif
#define SHA2_BYTE_REVERSE 0
/* Eventually these move to a global header, but for now we're not
* exporting anything beyond sha1_hw_calculate */
#define SHA_160 160
#define SHA_224 224
#define SHA_256 256
#define SHA_384 384
#define SHA_512 512
static void sha_hw_calculate(int sha_type, const void *buf, size_t len,
u_int32_t *result)
{
const u_int32_t *wptr;
const u_int8_t *bptr;
u_int32_t cmd = SHA2_MSGCTL_FIRST, final[3];
size_t blkwords = (sha_type < SHA_384) ? 16 : 32, hashsize;
unsigned datawords, words, cur_word, index, type, blocks=0;
u_int64_t totalbits = len*8;
clock_gate(CLK_SHA2, true);
/* XXX use CDMA? */
/* PIO sequence:
- configure the registers
- load the first block
- issue rdy command with first flag
- loop:
- load next block
- issue rdy command
- poll til rdy clears
- wait for hash idle
- read hash value
*/
switch (sha_type) {
case SHA_160:
type = SHA_TYPE_160;
hashsize = 5;
break;
case SHA_224:
type = SHA_TYPE_224;
hashsize = 7;
break;
case SHA_256:
type = SHA_TYPE_256;
hashsize = 8;
break;
case SHA_384:
type = SHA_TYPE_384;
hashsize = 12;
break;
case SHA_512:
type = SHA_TYPE_512;
hashsize = 16;
break;
default:
panic("Unknown sha type\n");
}
rSHA2_CONFIG = SHA2_CONFIG_TYPE(type) | SHA2_PIO_MODE;
datawords = len / 4;
final[0] = 0x80;
if (len & 3) {
bptr = (const u_int8_t *)(buf + (datawords*4));
int leftover = len & 3;
if (leftover == 1)
final[0] = bptr[0] | (1 << 15);
else if (leftover == 2)
final[0] = bptr[0] | ((unsigned)bptr[1] << 8) | (1 << 23);
else if (leftover == 3)
final[0] = bptr[0] | ((unsigned)bptr[1] << 8) | ((unsigned)bptr[2] << 16) | (1 << 31);
}
#if SHA2_BYTE_REVERSE
final[0] = swap32(final[0]);
final[1] = totalbits >> 32;
final[2] = totalbits & 0xffffffff;
#else
/* Big endian 64-bit bit-length */
final[1] = swap32(totalbits >> 32);
final[2] = swap32(totalbits & 0xffffffff);
#endif
wptr = (u_int32_t *)buf;
/* This loop takes care of all the complete words in the data,
performing the SHA on any complete message blocks along the
way. */
words = (datawords + 3 + (blkwords - 1)) & ~(blkwords - 1);
for (index = 0, cur_word = 0; cur_word < words; cur_word++, buf+=4) {
if (cur_word < datawords) {
#if WITH_UNALIGNED_MEM
#if SHA2_BYTE_REVERSE
rSHA2_MSGBLK(index) = swap32(*wptr);
wptr++;
#else
rSHA2_MSGBLK(index) = *wptr++; /* rely on little endianness */
#endif
#else
rSHA2_MSGBLK(index) = (buf[0] << 0)|(buf[1] << 8)|(buf[2] << 16)|(buf[3] << 24);
#endif
} else {
if (cur_word == datawords)
rSHA2_MSGBLK(index) = final[0];
else if (cur_word == words-2)
rSHA2_MSGBLK(index) = final[1];
else if (cur_word == words-1)
rSHA2_MSGBLK(index) = final[2];
else
rSHA2_MSGBLK(index) = 0;
}
if (++index == blkwords) {
index = 0;
rSHA2_MSGCTL = SHA2_MSGCTL_RDY | cmd;
if (cmd)
cmd = 0;
else
while (rSHA2_MSGCTL & SHA2_MSGCTL_RDY);
blocks++;
}
}
while (rSHA2_STATUS & SHA2_HASH_BUSY);
for (index = 0; index < hashsize; index++, result++)
#if SHA2_BYTE_REVERSE
*result = swap32(rSHA2_HASH(index));
#else
*result = rSHA2_HASH(index); /* again exploit little endianness */
#endif
clock_gate(CLK_SHA2, false);
}
void sha1_hw_calculate(const void *buf, size_t len, u_int32_t *result)
{
sha_hw_calculate(SHA_160, buf, len, result);
}
#if 0
#include <debug.h>
#include <sys/menu.h>
#if defined(WITH_MENU) && WITH_MENU
int do_sha(int argc, struct cmd_arg *args)
{
u_int8_t hash[64];
u_int32_t cnt, algo = SHA_160;
void *buf;
size_t len;
if (argc < 3) {
printf("not enough arguments.\n");
printf("%s [160,224,256,384,512] <address> <len>\n", args[0].str);
printf(" default is SHA-1 (160)\n");
return -1;
}
if (argc == 4) {
algo = args[1].u;
buf = (void *)args[2].u;
len = args[3].u;
} else {
buf = (void *)args[1].u;
len = args[2].u;
}
if (!security_allow_memory(buf, len)) {
printf("Permission Denied\n");
return -1;
}
memset(hash, 0, sizeof(hash));
sha_hw_calculate(algo, buf, len, (u_int32_t *)hash);
printf("sha-%d of %p for 0x%08lx bytes: ", algo, buf, len);
for (cnt = 0; cnt < (algo/8); cnt++)
printf("%02x%s", hash[cnt]);
printf("\n");
return 0;
}
MENU_COMMAND_DEVELOPMENT(sha, do_sha, "SHA hash of memory", NULL);
#endif
#endif