1
2/*
3 * Licensed Materials - Property of IBM
4 *
5 * trousers - An open source TCG Software Stack
6 *
7 * (C) Copyright International Business Machines Corp. 2004
8 *
9 */
10
11
12#include <stdlib.h>
13#include <stdio.h>
14#include <string.h>
15
16#include "trousers/tss.h"
17#include "trousers_types.h"
18#include "spi_utils.h"
19#include "capabilities.h"
20#include "memmgr.h"
21#include "tsplog.h"
22#include "obj.h"
23
24static struct memTable *
25__tspi_createTable()
26{
27	struct memTable *table = NULL;
28	/*
29	 * No table has yet been created to hold the memory allocations of
30	 * this context, so we need to create one
31	 */
32	table = calloc(1, sizeof(struct memTable));
33	if (table == NULL) {
34		LogError("malloc of %zd bytes failed.", sizeof(struct memTable));
35		return NULL;
36	}
37	return (table);
38}
39
40/* caller needs to lock memtable lock */
41struct memTable *
42getTable(TSS_HCONTEXT tspContext)
43{
44	struct memTable *tmp;
45
46	for (tmp = SpiMemoryTable; tmp; tmp = tmp->nextTable)
47		if (tmp->tspContext == tspContext)
48			return tmp;
49
50	return NULL;
51}
52
53/* caller needs to lock memtable lock */
54static void
55__tspi_addTable(struct memTable *new)
56{
57	struct memTable *tmp = SpiMemoryTable;
58
59	/* base case, this is the first table */
60	if (SpiMemoryTable == NULL) {
61		SpiMemoryTable = new;
62		return;
63	}
64
65	/* else add @new onto the end */
66	for (; tmp; tmp = tmp->nextTable)
67		if (tmp->nextTable == NULL) {
68			tmp->nextTable = new;
69			break;
70		}
71}
72
73/* caller needs to lock memtable lock and be sure the context mem slot for
74 * @tspContext exists before calling.
75 */
76void
77__tspi_addEntry(TSS_HCONTEXT tspContext, struct memEntry *new)
78{
79	struct memTable *tmp = getTable(tspContext);
80	struct memEntry *tmp_entry;
81
82	if (tmp == NULL) {
83		if ((tmp = __tspi_createTable()) == NULL)
84			return;
85		tmp->tspContext = tspContext;
86		__tspi_addTable(tmp);
87	}
88
89	tmp_entry = tmp->entries;
90
91	if (tmp->entries == NULL) {
92		tmp->entries = new;
93		return;
94	}
95
96	/* else tack @new onto the end */
97	for (; tmp_entry; tmp_entry = tmp_entry->nextEntry) {
98		if (tmp_entry->nextEntry == NULL) {
99			tmp_entry->nextEntry = new;
100			break;
101		}
102	}
103}
104
105/* caller needs to lock memtable lock */
106TSS_RESULT
107__tspi_freeTable(TSS_HCONTEXT tspContext)
108{
109	struct memTable *prev = NULL, *index = NULL, *next = NULL;
110	struct memEntry *entry = NULL, *entry_next = NULL;
111
112	for(index = SpiMemoryTable; index; index = index->nextTable) {
113		next = index->nextTable;
114		if (index->tspContext == tspContext) {
115			for (entry = index->entries; entry; entry = entry_next) {
116				/* this needs to be set before we do free(entry) */
117				entry_next = entry->nextEntry;
118				free(entry->memPointer);
119				free(entry);
120			}
121
122			if (prev != NULL)
123				prev->nextTable = next;
124			else
125				SpiMemoryTable = NULL;
126
127			free(index);
128			break;
129		}
130		prev = index;
131	}
132
133	return TSS_SUCCESS;
134}
135
136TSS_RESULT
137__tspi_freeEntry(struct memTable *table, void *pointer)
138{
139	struct memEntry *index = NULL;
140	struct memEntry *prev = NULL;
141	struct memEntry *toKill = NULL;
142
143	for (index = table->entries; index; prev = index, index = index->nextEntry) {
144		if (index->memPointer == pointer) {
145			toKill = index;
146			if (prev == NULL)
147				table->entries = toKill->nextEntry;
148			else
149				prev->nextEntry = toKill->nextEntry;
150
151			free(pointer);
152			free(toKill);
153			return TSS_SUCCESS;
154		}
155	}
156
157	return TSPERR(TSS_E_INVALID_RESOURCE);
158}
159
160TSS_RESULT
161__tspi_add_mem_entry(TSS_HCONTEXT tspContext, void *allocd_mem)
162{
163	struct memEntry *newEntry = calloc(1, sizeof(struct memEntry));
164	if (newEntry == NULL) {
165		LogError("malloc of %zd bytes failed.", sizeof(struct memEntry));
166		return TSPERR(TSS_E_OUTOFMEMORY);
167	}
168
169	newEntry->memPointer = allocd_mem;
170
171	MUTEX_LOCK(memtable_lock);
172
173	__tspi_addEntry(tspContext, newEntry);
174
175	MUTEX_UNLOCK(memtable_lock);
176
177	return TSS_SUCCESS;
178}
179
180/*
181 * calloc_tspi will be called by functions outside of this file. All locking
182 * is done here.
183 */
184void *
185calloc_tspi(TSS_HCONTEXT tspContext, UINT32 howMuch)
186{
187	struct memTable *table = NULL;
188	struct memEntry *newEntry = NULL;
189
190	MUTEX_LOCK(memtable_lock);
191
192	table = getTable(tspContext);
193	if (table == NULL) {
194		if ((table = __tspi_createTable()) == NULL) {
195			MUTEX_UNLOCK(memtable_lock);
196			return NULL;
197		}
198		table->tspContext = tspContext;
199		__tspi_addTable(table);
200	}
201
202	newEntry = calloc(1, sizeof(struct memEntry));
203	if (newEntry == NULL) {
204		LogError("malloc of %zd bytes failed.", sizeof(struct memEntry));
205		MUTEX_UNLOCK(memtable_lock);
206		return NULL;
207	}
208
209	newEntry->memPointer = calloc(1, howMuch);
210	if (newEntry->memPointer == NULL) {
211		LogError("malloc of %d bytes failed.", howMuch);
212		free(newEntry);
213		MUTEX_UNLOCK(memtable_lock);
214		return NULL;
215	}
216
217	/* this call must happen inside the lock or else another thread could
218	 * remove the context mem slot, causing a segfault
219	 */
220	__tspi_addEntry(tspContext, newEntry);
221
222	MUTEX_UNLOCK(memtable_lock);
223
224	return newEntry->memPointer;
225}
226
227/*
228 * free_tspi will be called by functions outside of this file. All locking
229 * is done here.
230 */
231TSS_RESULT
232free_tspi(TSS_HCONTEXT tspContext, void *memPointer)
233{
234	struct memTable *index;
235	TSS_RESULT result;
236
237	MUTEX_LOCK(memtable_lock);
238
239	if (memPointer == NULL) {
240		result = __tspi_freeTable(tspContext);
241		MUTEX_UNLOCK(memtable_lock);
242		return result;
243	}
244
245	if ((index = getTable(tspContext)) == NULL) {
246		MUTEX_UNLOCK(memtable_lock);
247		/* Tspi_Context_FreeMemory checks that the TSP context is good before calling us,
248		 * so we can be sure that the problem is with memPointer */
249		return TSPERR(TSS_E_INVALID_RESOURCE);
250	}
251
252	/* just free one entry */
253	result = __tspi_freeEntry(index, memPointer);
254
255	MUTEX_UNLOCK(memtable_lock);
256
257	return result;
258}
259
260/* definition for a memset that cannot be optimized away */
261void * __no_optimize
262__tspi_memset(void *s, int c, size_t n)
263{
264	return memset(s, c, n);
265}
266