aboutsummaryrefslogtreecommitdiffstats
path: root/security/smc/omap4/scx_public_crypto.c
blob: d6b751c53b83709899d47fb3d0bbaa890bee9aa3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
/*
 * Copyright (c) 2006-2010 Trusted Logic S.A.
 * All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 *
 * 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
 */

#include "scxlnx_defs.h"
#include "scxlnx_util.h"
#include "scxlnx_mshield.h"
#include "scx_public_crypto.h"
#include "scx_public_dma.h"

#define IO_ADDRESS OMAP2_L4_IO_ADDRESS

#define S_SUCCESS		0x00000000
#define S_ERROR_GENERIC		0xFFFF0000
#define S_ERROR_ACCESS_DENIED	0xFFFF0001
#define S_ERROR_BAD_FORMAT	0xFFFF0005
#define S_ERROR_BAD_PARAMETERS	0xFFFF0006
#define S_ERROR_OUT_OF_MEMORY	0xFFFF000C
#define S_ERROR_SHORT_BUFFER	0xFFFF0010
#define S_ERROR_UNREACHABLE	0xFFFF3013
#define S_ERROR_SERVICE		0xFFFF1000

#define CKR_OK			0x00000000

#define PUBLIC_CRYPTO_TIMEOUT_CONST	0x000FFFFF

#define RPC_AES1_CODE	PUBLIC_CRYPTO_HWA_AES1
#define RPC_AES2_CODE	PUBLIC_CRYPTO_HWA_AES2
#define RPC_DES_CODE	PUBLIC_CRYPTO_HWA_DES
#define RPC_SHA_CODE	PUBLIC_CRYPTO_HWA_SHA

#define RPC_CRYPTO_COMMAND_MASK	0x000003c0

#define RPC_INSTALL_SHORTCUT_LOCK_ACCELERATOR		0x200
#define RPC_INSTALL_SHORTCUT_LOCK_ACCELERATOR_UNLOCK	0x000
#define RPC_INSTALL_SHORTCUT_LOCK_ACCELERATOR_LOCK	0x001

#define RPC_LOCK_ACCELERATORS_SUSPEND_SHORTCUT			0x240
#define RPC_LOCK_ACCELERATORS_SUSPEND_SHORTCUT_LOCK_AES1	RPC_AES1_CODE
#define RPC_LOCK_ACCELERATORS_SUSPEND_SHORTCUT_LOCK_AES2	RPC_AES2_CODE
#define RPC_LOCK_ACCELERATORS_SUSPEND_SHORTCUT_LOCK_DES		RPC_DES_CODE
#define RPC_LOCK_ACCELERATORS_SUSPEND_SHORTCUT_LOCK_SHA		RPC_SHA_CODE
#define RPC_LOCK_ACCELERATORS_SUSPEND_SHORTCUT_SUSPEND		0x010
#define RPC_LOCK_ACCELERATORS_SUSPEND_SHORTCUT_UNINSTALL	0x020

#define RPC_RESUME_SHORTCUT_UNLOCK_ACCELERATORS			0x280
#define RPC_RESUME_SHORTCUT_UNLOCK_ACCELERATORS_UNLOCK_AES1	RPC_AES1_CODE
#define RPC_RESUME_SHORTCUT_UNLOCK_ACCELERATORS_UNLOCK_AES2	RPC_AES2_CODE
#define RPC_RESUME_SHORTCUT_UNLOCK_ACCELERATORS_UNLOCK_DES	RPC_DES_CODE
#define RPC_RESUME_SHORTCUT_UNLOCK_ACCELERATORS_UNLOCK_SHA	RPC_SHA_CODE
#define RPC_RESUME_SHORTCUT_UNLOCK_ACCELERATORS_RESUME		0x010

#define RPC_CLEAR_GLOBAL_KEY_CONTEXT			0x2c0
#define RPC_CLEAR_GLOBAL_KEY_CONTEXT_CLEARED_AES	0x001
#define RPC_CLEAR_GLOBAL_KEY_CONTEXT_CLEARED_DES	0x002

#define ENABLE_CLOCK	true
#define DISABLE_CLOCK	false

/*---------------------------------------------------------------------------*/
/*RPC IN/OUT structures for CUS implementation                               */
/*---------------------------------------------------------------------------*/

struct RPC_INSTALL_SHORTCUT_LOCK_ACCELERATOR_OUT {
	u32 nShortcutID;
	u32 nError;
};

struct RPC_INSTALL_SHORTCUT_LOCK_ACCELERATOR_IN {
	u32 nDeviceContextID;
	u32 hClientSession;
	u32 nCommandID;
	u32 hKeyContext;
	/**
	 *The identifier of the HWA accelerator that this shortcut uses!
	 *Possible values are:
	 *- 1 (RPC_AES1_CODE)
	 *- 2 (RPC_AES2_CODE)
	 *- 4 (RPC_DES_CODE)
	 *- 8 (RPC_SHA_CODE)
	 **/
	u32 nHWAID;
	/**
	 *This field defines the algorithm, direction, mode, key size.
	 *It contains some of the bits of the corresponding "CTRL" register
	 *of the accelerator.
	 *
	 *More precisely:
	 *For AES1 accelerator, nHWA_CTRL contains the following bits:
	 *- CTR (bit 6):
	 * when 1, selects CTR mode.
	 * when 0, selects CBC or ECB mode (according to CBC bit)
	 *- CBC (bit 5)
	 * when 1, selects CBC mode (but only if CTR=0)
	 * when 0, selects EBC mode (but only if CTR=0)
	 *- DIRECTION (bit 2)
	 *  0: decryption
	 *  1: encryption
	 *
	 *For the DES2 accelerator, nHWA_CTRL contains the following bits:
	 *- CBC (bit 4): 1 for CBC, 0 for ECB
	 *- DIRECTION (bit 2): 0 for decryption, 1 for encryption
	 *
	 *For the SHA accelerator, nHWA_CTRL contains the following bits:
	 *- ALGO (bit 2:1):
	 *  0x0: MD5
	 *  0x1: SHA1
	 *  0x2: SHA-224
	 *  0x3: SHA-256
	 **/
	u32 nHWA_CTRL;
	union PUBLIC_CRYPTO_OPERATION_STATE sOperationState;
};

struct RPC_LOCK_HWA_SUSPEND_SHORTCUT_OUT {
	union PUBLIC_CRYPTO_OPERATION_STATE sOperationState;
};

struct RPC_LOCK_HWA_SUSPEND_SHORTCUT_IN {
	u32 nShortcutID;
};

struct RPC_RESUME_SHORTCUT_UNLOCK_HWA_IN {
	u32 nShortcutID;
	u32 hAES1KeyContext;
	u32 hAES2KeyContext;
	u32 hDESKeyContext;
	union PUBLIC_CRYPTO_OPERATION_STATE sOperationState;
};

/*------------------------------------------------------------------------- */
/*
 * HWA public lock or unlock one HWA according algo specified by nHWAID
 */
void PDrvCryptoLockUnlockHWA(u32 nHWAID, bool bDoLock)
{
	int is_sem = 0;
	struct semaphore *s = NULL;
	struct mutex *m = NULL;
	struct SCXLNX_DEVICE *dev = SCXLNXGetDevice();

	dprintk(KERN_INFO "PDrvCryptoLockUnlockHWA:nHWAID=0x%04X bDoLock=%d\n",
		nHWAID, bDoLock);

	switch (nHWAID) {
	case RPC_AES1_CODE:
		s = &dev->sAES1CriticalSection;
		is_sem = 1;
		break;
	case RPC_AES2_CODE:
		s = &dev->sAES2CriticalSection;
		is_sem = 1;
		break;
	case RPC_DES_CODE:
		m = &dev->sDESCriticalSection;
		break;
	default:
	case RPC_SHA_CODE:
		m = &dev->sSHACriticalSection;
		break;
	}

	if (bDoLock == LOCK_HWA) {
		dprintk(KERN_INFO "PDrvCryptoLockUnlockHWA: "
			"Wait for HWAID=0x%04X\n", nHWAID);
		if (is_sem) {
			while (down_trylock(s))
				cpu_relax();
		} else {
			while (!mutex_trylock(m))
				cpu_relax();
		}
		dprintk(KERN_INFO "PDrvCryptoLockUnlockHWA: "
			"Locked on HWAID=0x%04X\n", nHWAID);
	} else {
		if (is_sem)
			up(s);
		else
			mutex_unlock(m);
		dprintk(KERN_INFO "PDrvCryptoLockUnlockHWA: "
			"Released for HWAID=0x%04X\n", nHWAID);
	}
}

/*------------------------------------------------------------------------- */
/**
 *Initialize the public crypto DMA channels, global HWA semaphores and handles
 */
u32 SCXPublicCryptoInit(void)
{
	struct SCXLNX_DEVICE *pDevice = SCXLNXGetDevice();
	u32 nError = PUBLIC_CRYPTO_OPERATION_SUCCESS;

	/* Initialize HWAs */
	PDrvCryptoAESInit();
	PDrvCryptoDigestInit();

	/*initialize the HWA semaphores */
	sema_init(&pDevice->sAES1CriticalSection, 1);
	sema_init(&pDevice->sAES2CriticalSection, 1);
	mutex_init(&pDevice->sSHACriticalSection);

	/*initialize the current key handle loaded in the AESn/DES HWA */
	pDevice->hAES1SecureKeyContext = 0;
	pDevice->hAES2SecureKeyContext = 0;
	pDevice->bSHAM1IsPublic = false;

	/*initialize the DMA semaphores */
	mutex_init(&pDevice->sm.sDMALock);

	/*allocate DMA buffer */
	pDevice->nDMABufferLength = PAGE_SIZE * 16;
	pDevice->pDMABuffer = dma_alloc_coherent(NULL,
		pDevice->nDMABufferLength,
		&(pDevice->pDMABufferPhys),
		GFP_KERNEL);
	if (pDevice->pDMABuffer == NULL) {
		printk(KERN_ERR
			"SCXPublicCryptoInit: Out of memory for DMA buffer\n");
		nError = S_ERROR_OUT_OF_MEMORY;
	}

	return nError;
}

/*------------------------------------------------------------------------- */
/*
 *Initialize the device context CUS fields (shortcut semaphore and public CUS
 *list)
 */
void SCXPublicCryptoInitDeviceContext(struct SCXLNX_CONNECTION *pDeviceContext)
{
	/*initialize the CUS list in the given device context */
	spin_lock_init(&(pDeviceContext->shortcutListCriticalSectionLock));
	INIT_LIST_HEAD(&(pDeviceContext->ShortcutList));
}

/*------------------------------------------------------------------------- */
/**
 *Terminate the public crypto (including DMA)
 */
void SCXPublicCryptoTerminate()
{
	struct SCXLNX_DEVICE *pDevice = SCXLNXGetDevice();

	if (pDevice->pDMABuffer != NULL) {
		dma_free_coherent(NULL, pDevice->nDMABufferLength,
			pDevice->pDMABuffer,
			pDevice->pDMABufferPhys);
		pDevice->pDMABuffer = NULL;
	}

	PDrvCryptoDigestExit();
	PDrvCryptoAESExit();
}

/*------------------------------------------------------------------------- */

void SCXPublicCryptoWaitForReadyBitInfinitely(u32 *pRegister, u32 vBit)
{
	while (!(INREG32(pRegister) & vBit))
		;
}

/*------------------------------------------------------------------------- */

u32 SCXPublicCryptoWaitForReadyBit(u32 *pRegister, u32 vBit)
{
	u32 timeoutCounter = PUBLIC_CRYPTO_TIMEOUT_CONST;

	while ((!(INREG32(pRegister) & vBit)) && ((--timeoutCounter) != 0))
		;

	if (timeoutCounter == 0)
		return PUBLIC_CRYPTO_ERR_TIMEOUT;

	return PUBLIC_CRYPTO_OPERATION_SUCCESS;
}

/*------------------------------------------------------------------------- */

static DEFINE_SPINLOCK(clk_lock);

void SCXPublicCryptoDisableClock(uint32_t vClockPhysAddr)
{
	u32 *pClockReg;
	u32 val;
	unsigned long flags;

	dprintk(KERN_INFO "SCXPublicCryptoDisableClock: " \
		"vClockPhysAddr=0x%08X\n",
		vClockPhysAddr);

	/* Ensure none concurrent access when changing clock registers */
	spin_lock_irqsave(&clk_lock, flags);

	pClockReg = (u32 *)IO_ADDRESS(vClockPhysAddr);

	val = __raw_readl(pClockReg);
	val &= ~(0x3);
	__raw_writel(val, pClockReg);

	/* Wait for clock to be fully disabled */
	while ((__raw_readl(pClockReg) & 0x30000) == 0)
		;

	spin_unlock_irqrestore(&clk_lock, flags);

	tf_l4sec_clkdm_allow_idle(false, true);
}

/*------------------------------------------------------------------------- */

void SCXPublicCryptoEnableClock(uint32_t vClockPhysAddr)
{
	u32 *pClockReg;
	u32 val;
	unsigned long flags;

	dprintk(KERN_INFO "SCXPublicCryptoEnableClock: " \
		"vClockPhysAddr=0x%08X\n",
		vClockPhysAddr);

	tf_l4sec_clkdm_wakeup(false, true);

	/* Ensure none concurrent access when changing clock registers */
	spin_lock_irqsave(&clk_lock, flags);

	pClockReg = (u32 *)IO_ADDRESS(vClockPhysAddr);

	val = __raw_readl(pClockReg);
	val |= 0x2;
	__raw_writel(val, pClockReg);

	/* Wait for clock to be fully enabled */
	while ((__raw_readl(pClockReg) & 0x30000) != 0)
		;

	spin_unlock_irqrestore(&clk_lock, flags);
}