iBoot/drivers/samsung/sha1/sha1.c

213 lines
5.2 KiB
C

/*
* Copyright (C) 2007-2008 Apple Inc. All rights reserved.
* Copyright (C) 2006 Apple Computer, 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 <arch.h>
#include <debug.h>
#include <platform/clocks.h>
#include <platform/int.h>
#include <platform/soc/hwclocks.h>
#include <sys.h>
#include <sys/task.h>
#include "sha1.h"
static const sha1_regs sha1_reg = {
&rSHA1_ADDR_CONF, &rSHA1_ADDR_SWRESET, &rSHA1_ADDR_INT_SRC, &rSHA1_ADDR_INT_MASK,
&rSHA1_ADDR_ENDIAN, &rSHA1_ADDR_CODE0, &rSHA1_ADDR_CODE1, &rSHA1_ADDR_CODE2,
&rSHA1_ADDR_CODE3, &rSHA1_ADDR_CODE4, &rSHA1_ADDR_DATA0, &rSHA1_ADDR_DATA1,
&rSHA1_ADDR_DATA2, &rSHA1_ADDR_DATA3, &rSHA1_ADDR_DATA4, &rSHA1_ADDR_DATA5,
&rSHA1_ADDR_DATA6, &rSHA1_ADDR_DATA7, &rSHA1_ADDR_DATA8, &rSHA1_ADDR_DATA9,
&rSHA1_ADDR_DATA10, &rSHA1_ADDR_DATA11, &rSHA1_ADDR_DATA12, &rSHA1_ADDR_DATA13,
&rSHA1_ADDR_DATA14, &rSHA1_ADDR_DATA15, &rSHA1_MASTER_MODE, &rSHA1_MS_START_ADDR,
&rSHA1_MS_SIZE };
static sha1_status sha1Status = { 0, 0, 0 };
static void sha1Run(u_int8_t *buf);
static void Sha1NewInit(void);
void Sha1NewAddEnd(u_int32_t dataLen, u_int32_t offset, u_int32_t startCmd);
static void Sha1NewInit(void)
{
const sha1_regs *reg;
reg = &sha1_reg;
clock_gate(CLK_SHA1, true);
/* wait for SHA-1 engine idle */
while(*reg->con & (0x1<<0))
;
/* Software reset */
*reg->swreset = 0x1;
*reg->swreset = 0x0;
/* Reset Configuration Register */
*reg->con = 0x0;
/* Always use slave mode */
*reg->mode = 0x0;
/* Always use twist / little endian */
*reg->twist = 0x0;
sha1Status.cmd = 1;
sha1Status.offset = 0;
sha1Status.length = 0;
}
/* Fill the frame buffer and send it out
* the buffer size is always 64 bytes
* Caller is responsible to set the End bit and 0 padding
*/
static void sha1Run(u_int8_t *buf)
{
const sha1_regs *reg;
reg = &sha1_reg;
/* Fill the buffer */
for (int i = 0; i < 16; i++) {
volatile u_int32_t *data;
data = reg->data0;
#if WITH_UNALIGNED_MEM
*(data + i) = ((u_int32_t *)buf)[i];
#else
*(data + i) = (buf[i*4] << 0)|(buf[i*4+1] << 8)|(buf[i*4+2] << 16)|(buf[i*4+3] << 24);
#endif
}
/* Run the SHA1 engine */
if (sha1Status.cmd) {
/* Start new hash code */
*reg->con &= ~(1<<3);
sha1Status.cmd = 0;
} else {
/* Continue hash code */
*reg->con |= (1<<3);
}
*reg->con |= 1<<1;
while(*reg->con & (1<<0))
;
}
/************************************************************************
* void sha1_hw_calculate(const void *buf, size_t len, u_int32_t *result)
* -- We are using slave mode only so the code would be portable
* between H1, H2, M1, M2.
* -- Caller's responsibility to make sure buffer can hold 20 bytes
* SHA1 code.
************************************************************************/
void sha1_hw_calculate(const void *buf, size_t len, u_int32_t *result)
{
u_int32_t length, counter;
u_int8_t *frame;
u_int64_t sha1TotalBits;
u_int8_t sha1TotalLenAdd[8];
const sha1_regs *reg;
Sha1NewInit();
reg = &sha1_reg;
frame = (u_int8_t *)buf;
length = len;
counter =0;
/* Prepare the 64 bits length */
sha1TotalBits = len * 8;
sha1TotalLenAdd[0] = ((sha1TotalBits >> 32) & (0xff << 24)) >> 24;
sha1TotalLenAdd[1] = ((sha1TotalBits >> 32) & (0xff << 16)) >> 16;
sha1TotalLenAdd[2] = ((sha1TotalBits >> 32) & (0xff << 8)) >> 8;
sha1TotalLenAdd[3] = ((sha1TotalBits >> 32) & (0xff << 0)) >> 0;
sha1TotalLenAdd[4] = (sha1TotalBits & (0xff << 24)) >> 24;
sha1TotalLenAdd[5] = (sha1TotalBits & (0xff << 16)) >> 16;
sha1TotalLenAdd[6] = (sha1TotalBits & (0xff << 8)) >> 8;
sha1TotalLenAdd[7] = (sha1TotalBits & (0xff << 0)) >> 0;
while (length > 64) {
sha1Run(&frame[sha1Status.length]);
sha1Status.length += 64;
length -= 64;
counter += 64;
if (0x7FFFF < counter) {
task_yield();
counter = 0;
}
}
if (length > 55) {
/* Not enough space for the length bytes */
u_int8_t frameBuf[64];
for (u_int32_t i = 0; i < 64; i++) {
if (length > i) {
frameBuf[i] = frame[sha1Status.length++];
} else if (length == i) {
frameBuf[i] = 0x80;
} else {
frameBuf[i] = 0x0;
}
}
sha1Run(frameBuf);
/* Add End bit 0x80 if not added above */
if (length == 64) {
frameBuf[0] = 0x80;
} else {
frameBuf[0] = 0x0;
}
/* Start a new frame to hold the length */
for (int j = 1; j < 56; j++) {
frameBuf[j] = 0x0;
}
/* Now store the length */
for (int k = 0; k < 8; k++) {
frameBuf[56 + k] = sha1TotalLenAdd[k];
}
sha1Run(frameBuf);
} else {
/* Add End bit 0x80 and 0 padding */
u_int8_t frameBuf[64];
for (u_int32_t i = 0; i < 56; i++) {
if (length > i) {
frameBuf[i] = frame[sha1Status.length++];
} else if (length == i) {
frameBuf[i] = 0x80;
} else {
frameBuf[i] = 0x0;
}
}
/* Now store the length */
for (int j = 0; j < 8; j++) {
frameBuf[56 + j] = sha1TotalLenAdd[j];
}
sha1Run(frameBuf);
}
/* Get the result */
result[0] = *reg->code0;
result[1] = *reg->code1;
result[2] = *reg->code2;
result[3] = *reg->code3;
result[4] = *reg->code4;
clock_gate(CLK_SHA1, false);
}