summaryrefslogtreecommitdiff
path: root/drivers/mxc/security/rng/shw_dryice.c
blob: bcf1794f735180e52acb741c7b39d7d0e971e2a7 (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
/*
 * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
 */

/*
 * The code contained herein is licensed under the GNU General Public
 * License. You may obtain a copy of the GNU General Public License
 * Version 2 or later at the following locations:
 *
 * http://www.opensource.org/licenses/gpl-license.html
 * http://www.gnu.org/copyleft/gpl.html
 */

#include "shw_driver.h"
#include "../dryice.h"

#include <diagnostic.h>

#ifdef FSL_HAVE_DRYICE

#ifdef LINUX_VERSION_CODE
EXPORT_SYMBOL(fsl_shw_gen_random_pf_key);
#endif
/*!
 * Cause the hardware to create a new random key for secure memory use.
 *
 * Have the hardware use the secure hardware random number generator to load a
 * new secret key into the hardware random key register.
 *
 * @param      user_ctx         A user context from #fsl_shw_register_user().
 *
 * @return    A return code of type #fsl_shw_return_t.
 */
fsl_shw_return_t fsl_shw_gen_random_pf_key(fsl_shw_uco_t * user_ctx)
{
	fsl_shw_return_t ret = FSL_RETURN_ERROR_S;
	di_return_t di_ret;

	/* For now, only blocking mode calls are supported */
	if (!(user_ctx->flags & FSL_UCO_BLOCKING_MODE)) {
		ret = FSL_RETURN_BAD_FLAG_S;
		goto out;
	}

	di_ret = dryice_set_random_key(0);
	if (di_ret != DI_SUCCESS) {
		printk("dryice_set_random_key returned %d\n", di_ret);
		goto out;
	}

	ret = FSL_RETURN_OK_S;

      out:
	return ret;
}

#ifdef LINUX_VERSION_CODE
EXPORT_SYMBOL(fsl_shw_read_tamper_event);
#endif
fsl_shw_return_t fsl_shw_read_tamper_event(fsl_shw_uco_t * user_ctx,
					   fsl_shw_tamper_t * tamperp,
					   uint64_t * timestampp)
{
	fsl_shw_return_t ret = FSL_RETURN_ERROR_S;
	di_return_t di_ret;
	uint32_t di_events = 0;
	uint32_t di_time_stamp;

	/* Only blocking mode calls are supported */
	if (!(user_ctx->flags & FSL_UCO_BLOCKING_MODE)) {
		ret = FSL_RETURN_BAD_FLAG_S;
		goto out;
	}

	di_ret = dryice_get_tamper_event(&di_events, &di_time_stamp, 0);
	if ((di_ret != DI_SUCCESS) && (di_ret != DI_ERR_STATE)) {
#ifdef DIAG_SECURITY_FUNC
		LOG_DIAG_ARGS("dryice_get_tamper_event returned %s\n",
			      di_error_string(di_ret));
#endif
		goto out;
	}

	/* Pass time back to caller */
	*timestampp = (uint64_t) di_time_stamp;

	if (di_events & DI_TAMPER_EVENT_WTD) {
		*tamperp = FSL_SHW_TAMPER_WTD;
	} else if (di_events & DI_TAMPER_EVENT_ETBD) {
		*tamperp = FSL_SHW_TAMPER_ETBD;
	} else if (di_events & DI_TAMPER_EVENT_ETAD) {
		*tamperp = FSL_SHW_TAMPER_ETAD;
	} else if (di_events & DI_TAMPER_EVENT_EBD) {
		*tamperp = FSL_SHW_TAMPER_EBD;
	} else if (di_events & DI_TAMPER_EVENT_SAD) {
		*tamperp = FSL_SHW_TAMPER_SAD;
	} else if (di_events & DI_TAMPER_EVENT_TTD) {
		*tamperp = FSL_SHW_TAMPER_TTD;
	} else if (di_events & DI_TAMPER_EVENT_CTD) {
		*tamperp = FSL_SHW_TAMPER_CTD;
	} else if (di_events & DI_TAMPER_EVENT_VTD) {
		*tamperp = FSL_SHW_TAMPER_VTD;
	} else if (di_events & DI_TAMPER_EVENT_MCO) {
		*tamperp = FSL_SHW_TAMPER_MCO;
	} else if (di_events & DI_TAMPER_EVENT_TCO) {
		*tamperp = FSL_SHW_TAMPER_TCO;
	} else if (di_events != 0) {
		/* Apparentliy a tamper type not known to this driver was detected */
		goto out;
	} else {
		*tamperp = FSL_SHW_TAMPER_NONE;
	}

	ret = FSL_RETURN_OK_S;

      out:
	return ret;
}				/* end fn fsl_shw_read_tamper_event */
#endif
/*!
 * Convert an SHW HW key reference into a DI driver key reference
 *
 * @param shw_pf_key   An SHW HW key value
 * @param di_keyp      Location to store the equivalent DI driver key
 *
 * @return FSL_RETURN_OK_S, or error if key is unknown or cannot translate.
 */
fsl_shw_return_t shw_convert_pf_key(fsl_shw_pf_key_t shw_pf_key,
				    di_key_t * di_keyp)
{
	fsl_shw_return_t ret = FSL_RETURN_BAD_FLAG_S;

	switch (shw_pf_key) {
	case FSL_SHW_PF_KEY_IIM:
		*di_keyp = DI_KEY_FK;
		break;
	case FSL_SHW_PF_KEY_RND:
		*di_keyp = DI_KEY_RK;
		break;
	case FSL_SHW_PF_KEY_IIM_RND:
		*di_keyp = DI_KEY_FRK;
		break;
	case FSL_SHW_PF_KEY_PRG:
		*di_keyp = DI_KEY_PK;
		break;
	case FSL_SHW_PF_KEY_IIM_PRG:
		*di_keyp = DI_KEY_FPK;
		break;
	default:
		goto out;
	}

	ret = FSL_RETURN_OK_S;

      out:
	return ret;
}

#ifdef DIAG_SECURITY_FUNC
const char *di_error_string(int code)
{
	char *str = "unknown";

	switch (code) {
	case DI_SUCCESS:
		str = "operation was successful";
		break;
	case DI_ERR_BUSY:
		str = "device or resource busy";
		break;
	case DI_ERR_STATE:
		str = "dryice is in incompatible state";
		break;
	case DI_ERR_INUSE:
		str = "resource is already in use";
		break;
	case DI_ERR_UNSET:
		str = "resource has not been initialized";
		break;
	case DI_ERR_WRITE:
		str = "error occurred during register write";
		break;
	case DI_ERR_INVAL:
		str = "invalid argument";
		break;
	case DI_ERR_FAIL:
		str = "operation failed";
		break;
	case DI_ERR_HLOCK:
		str = "resource is hard locked";
		break;
	case DI_ERR_SLOCK:
		str = "resource is soft locked";
		break;
	case DI_ERR_NOMEM:
		str = "out of memory";
		break;
	default:
		break;
	}

	return str;
}
#endif				/* HAVE DRYICE */