1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/* ---- includes ----------------------------------------------------------- */
18
19#include "b_BasicEm/MemSeg.h"
20#include "b_BasicEm/Functions.h"
21#include "b_BasicEm/Context.h"
22
23/* ------------------------------------------------------------------------- */
24
25/* ========================================================================= */
26/*                                                                           */
27/* ---- \ghd{ auxiliary functions } ---------------------------------------- */
28/*                                                                           */
29/* ========================================================================= */
30
31/* ------------------------------------------------------------------------- */
32
33/* ========================================================================= */
34/*                                                                           */
35/* ---- \ghd{ constructor / destructor } ----------------------------------- */
36/*                                                                           */
37/* ========================================================================= */
38
39/* ------------------------------------------------------------------------- */
40
41void bbs_MemSeg_init( struct bbs_Context* cpA,
42					  struct bbs_MemSeg* ptrA )
43{
44	ptrA->memPtrE = NULL;
45	ptrA->sizeE = 0;
46	ptrA->allocIndexE = 0;
47	ptrA->sharedE = FALSE;
48	ptrA->idE = 0;
49	ptrA->dynMemManagerPtrE = NULL;
50}
51
52/* ------------------------------------------------------------------------- */
53
54void bbs_MemSeg_exit( struct bbs_Context* cpA,
55					  struct bbs_MemSeg* ptrA )
56{
57	ptrA->memPtrE = NULL;
58	ptrA->sizeE = 0;
59	ptrA->allocIndexE = 0;
60	ptrA->sharedE = FALSE;
61	ptrA->idE = 0;
62	ptrA->dynMemManagerPtrE = NULL;
63}
64
65/* ------------------------------------------------------------------------- */
66
67/* ========================================================================= */
68/*                                                                           */
69/* ---- \ghd{ operators } -------------------------------------------------- */
70/*                                                                           */
71/* ========================================================================= */
72
73/* ------------------------------------------------------------------------- */
74
75/* ========================================================================= */
76/*                                                                           */
77/* ---- \ghd{ query functions } -------------------------------------------- */
78/*                                                                           */
79/* ========================================================================= */
80
81/* ------------------------------------------------------------------------- */
82
83uint32 bbs_MemSeg_availableSize( struct bbs_Context* cpA,
84								 const struct bbs_MemSeg* ptrA )
85{
86	if( ptrA->dynMemManagerPtrE == NULL )
87	{
88		return ( ptrA->sizeE == ptrA->allocIndexE ) ? 0 : ptrA->sizeE - ptrA->allocIndexE - 2 * ptrA->sharedE;
89	}
90	else
91	{
92		return 0xFFFFFFFF;
93	}
94}
95
96/* ------------------------------------------------------------------------- */
97
98uint32 bbs_MemSeg_allocatedSize( struct bbs_Context* cpA,
99								 const struct bbs_MemSeg* ptrA )
100{
101	if( ptrA->dynMemManagerPtrE == NULL )
102	{
103		return ptrA->allocIndexE;
104	}
105	else
106	{
107		return bbs_DynMemManager_allocatedSize( cpA, ptrA->dynMemManagerPtrE );
108	}
109}
110
111/* ------------------------------------------------------------------------- */
112
113uint32 bbs_MemSeg_usedSize( struct bbs_Context* cpA,
114						    const struct bbs_MemSeg* ptrA )
115{
116	if( ptrA->dynMemManagerPtrE == NULL )
117	{
118		if( ptrA->sharedE )
119		{
120			return ptrA->allocIndexE;
121		}
122		else
123		{
124			uint32 indexL = 0;
125			uint32 countL = 0;
126			while( indexL < ptrA->allocIndexE )
127			{
128				uint32 sizeL = *( uint32* )( ptrA->memPtrE + indexL );
129				indexL += ( sizeL & 0xFFFFFFFE );
130				if( ( sizeL & 1 ) == 0 )
131				{
132					countL += sizeL - 2;
133				}
134			}
135			return countL;
136		}
137	}
138	else
139	{
140		return bbs_MemSeg_allocatedSize( cpA, ptrA );
141	}
142}
143
144/* ------------------------------------------------------------------------- */
145
146uint32 bbs_MemSeg_blocks( struct bbs_Context* cpA,
147						  const struct bbs_MemSeg* ptrA )
148{
149	uint32 indexL = 0;
150	uint32 countL = 0;
151
152	if( ptrA->sharedE ) return 0;
153
154	while( indexL < ptrA->allocIndexE )
155	{
156		uint32 sizeL = *( uint32* )( ptrA->memPtrE + indexL );
157		indexL += ( sizeL & 0xFFFFFFFE );
158		countL++;
159	}
160	return countL;
161}
162
163/* ------------------------------------------------------------------------- */
164
165uint32 bbs_MemSeg_usedBlocks( struct bbs_Context* cpA,
166							  const struct bbs_MemSeg* ptrA )
167{
168	uint32 indexL = 0;
169	uint32 countL = 0;
170
171	if( ptrA->sharedE ) return 0;
172
173	while( indexL < ptrA->allocIndexE )
174	{
175		uint32 sizeL = *( uint32* )( ptrA->memPtrE + indexL );
176		indexL += ( sizeL & 0xFFFFFFFE );
177		countL += ( ( sizeL & 1 ) == 0 );
178	}
179	return countL;
180}
181
182/* ------------------------------------------------------------------------- */
183
184/* ========================================================================= */
185/*                                                                           */
186/* ---- \ghd{ modify functions } ------------------------------------------- */
187/*                                                                           */
188/* ========================================================================= */
189
190/* ------------------------------------------------------------------------- */
191
192/* ========================================================================= */
193/*                                                                           */
194/* ---- \ghd{ I/O } -------------------------------------------------------- */
195/*                                                                           */
196/* ========================================================================= */
197
198/* ------------------------------------------------------------------------- */
199
200/* ========================================================================= */
201/*                                                                           */
202/* ---- \ghd{ exec functions } --------------------------------------------- */
203/*                                                                           */
204/* ========================================================================= */
205
206/* ------------------------------------------------------------------------- */
207
208struct bbs_MemSeg bbs_MemSeg_create( struct bbs_Context* cpA,
209									 void* memPtrA, uint32 sizeA )
210{
211	struct bbs_MemSeg memSegL;
212	memSegL.memPtrE     = ( uint16* )memPtrA;
213	memSegL.sizeE       = sizeA & 0xFFFFFFFE; /* enforce even size to avoid overflow problems */
214	memSegL.allocIndexE = 0;
215	memSegL.sharedE     = FALSE;
216	memSegL.idE         = 0;
217	memSegL.dynMemManagerPtrE = NULL;
218	return memSegL;
219}
220
221/* ------------------------------------------------------------------------- */
222
223struct bbs_MemSeg bbs_MemSeg_createShared( struct bbs_Context* cpA,
224										   void* memPtrA, uint32 sizeA )
225{
226	struct bbs_MemSeg memSegL;
227	memSegL.memPtrE     = ( uint16* )memPtrA;
228	memSegL.sizeE       = sizeA;
229	memSegL.allocIndexE = 0;
230	memSegL.sharedE     = TRUE;
231	memSegL.idE         = 0;
232	memSegL.dynMemManagerPtrE = NULL;
233	return memSegL;
234}
235
236/* ------------------------------------------------------------------------- */
237
238void* bbs_MemSeg_alloc( struct bbs_Context* cpA,
239					    struct bbs_MemSeg* ptrA,
240						uint32 sizeA )
241{
242	uint16* memPtrL = NULL;
243
244	if( bbs_Context_error( cpA ) ) return NULL;
245
246	if( !ptrA->sharedE )
247	{
248		if( ptrA->dynMemManagerPtrE == NULL )
249		{
250			uint32 effSizeL = sizeA + ( sizeA & 1 ) + 2; /* effective block size */
251			memPtrL = ptrA->memPtrE + ptrA->allocIndexE;
252			*( ( uint32* )memPtrL ) = effSizeL;
253			memPtrL += 2;
254			if( ptrA->allocIndexE + effSizeL > ptrA->sizeE )
255			{
256				bbs_ERR2( bbs_ERR_MEMORY_OVERFLOW,
257						  "uint16* bbs_MemSeg_alloc( struct bbs_MemSeg* ptrA, uint32 sizeA ):\n"
258						  "Exclusive Memory overflow. Segment size: %i. Requested size: %i", ptrA->sizeE, sizeA );
259				return NULL;
260			}
261			ptrA->allocIndexE += effSizeL;
262		}
263		else
264		{
265			memPtrL = bbs_DynMemManager_alloc( cpA, ptrA->dynMemManagerPtrE, ptrA, sizeA );
266		}
267	}
268	else
269	{
270		uint32 effSizeL = sizeA + ( sizeA & 1 );  /* effective block size */
271
272		if( ptrA->allocIndexE + effSizeL > ptrA->sizeE  + ( ptrA->sizeE & 1 ) )
273		{
274			if( ptrA->dynMemManagerPtrE == NULL )
275			{
276				bbs_ERR2( bbs_ERR_MEMORY_OVERFLOW,
277						  "uint16* bbs_MemSeg_alloc( struct bbs_MemSeg* ptrA, uint32 sizeA ):\n"
278						  "Shared Memory overflow. Segment size: %i. Requested size: %i", ptrA->sizeE, sizeA );
279				return NULL;
280			}
281			else
282			{
283				uint32 actualBlockSizeL = 0;
284				ptrA->memPtrE = bbs_DynMemManager_nextBlock( cpA, ptrA->dynMemManagerPtrE, ptrA, ptrA->memPtrE, effSizeL, &actualBlockSizeL );
285				ptrA->sizeE = actualBlockSizeL;
286				ptrA->allocIndexE = 0;
287			}
288		}
289
290		memPtrL = ptrA->memPtrE + ptrA->allocIndexE;
291		ptrA->allocIndexE += effSizeL;
292	}
293
294	#if defined( HW_TMS320C5x )
295	#ifdef DEBUG2
296	{
297		/* check if segment crosses page boundary */
298		if( ( ( ( uint32 ) ptrA->memPtrE ) >> 16 ) !=
299			( ( ( uint32 ) ptrA->memPtrE + ( ptrA->sizeE - 1 ) ) >> 16 ) )
300		{
301			bbs_ERROR0( "uint16* bbs_MemSeg_alloc( struct bbs_MemSeg* ptrA, uint32 sizeA ):\nSegment crosses page boundary\n" );
302			return NULL;
303		}
304	}
305	#endif
306	#endif
307
308	return memPtrL;
309}
310
311/* ------------------------------------------------------------------------- */
312
313void bbs_MemSeg_free( struct bbs_Context* cpA,
314					  struct bbs_MemSeg* ptrA,
315					  void* memPtrA )
316{
317	bbs_DEF_fNameL( "void bbs_MemSeg_free( struct bbs_MemSeg* ptrA, void* memPtrA )" )
318
319	if( bbs_Context_error( cpA ) ) return;
320
321	/** only valid exclusive segments can be freed */
322	if( ptrA == NULL || memPtrA == NULL || ptrA->sharedE ) return;
323
324	if( ptrA->dynMemManagerPtrE != NULL )
325	{
326		bbs_DynMemManager_free( cpA, ptrA->dynMemManagerPtrE, memPtrA );
327	}
328	else
329	{
330		uint32 indexL, sizeL;
331		uint16* memPtrL;
332
333		if( ptrA == NULL || memPtrA == NULL ) return;
334		if( ptrA->sharedE ) return;
335
336		#ifdef HW_TMS320C5x
337			indexL = ( uint32 ) memPtrA - ( uint32 ) ptrA->memPtrE - 2;
338		#else
339			indexL = ( uint16* )memPtrA - ptrA->memPtrE - 2;
340		#endif
341
342		memPtrL = ptrA->memPtrE + indexL;
343		sizeL = *( ( int32* )memPtrL );
344
345		/* checks */
346		if( indexL > ptrA->allocIndexE || ( indexL & 1 ) != 0 )
347		{
348			bbs_ERROR4( "%s\n: Invalid memory.\n"
349						"sizeE       = %i\n"
350						"allocIndexE = %i\n"
351						"indexL      = %i\n",
352						fNameL,
353						ptrA->sizeE,
354						ptrA->allocIndexE,
355						indexL );
356			return;
357		}
358
359		if( ( sizeL & 1 ) != 0 )
360		{
361			bbs_ERROR1( "%s\n: Memory block was already freed once", fNameL );
362			return;
363		}
364
365		*( ( uint32* )memPtrL ) += 1; /* odd size value indicates unused memory block */
366
367		/* free last unused blocks if any */
368		if( indexL + sizeL == ptrA->allocIndexE )
369		{
370			uint32 newAllocIndexL = 0;
371			indexL = 0;
372			while( indexL < ptrA->allocIndexE )
373			{
374				uint32 sizeL = *( uint32* )( ptrA->memPtrE + indexL );
375				indexL += ( sizeL & 0xFFFFFFFE );
376				if( ( sizeL & 1 ) == 0 )
377				{
378					newAllocIndexL = indexL;
379				}
380			}
381
382			ptrA->allocIndexE = newAllocIndexL;
383		}
384
385	#ifdef DEBUG2
386		bbs_MemSeg_checkConsistency( cpA, ptrA );
387	#endif
388
389	}
390}
391
392/* ------------------------------------------------------------------------- */
393
394void bbs_MemSeg_checkConsistency( struct bbs_Context* cpA,
395								  const struct bbs_MemSeg* ptrA )
396{
397	uint32 indexL = 0;
398
399	if( ptrA->sharedE ) return;
400
401	while( indexL < ptrA->allocIndexE )
402	{
403		uint32 sizeL = *( uint32* )( ptrA->memPtrE + indexL );
404		indexL += ( sizeL & 0xFFFFFFFE );
405	}
406
407	if( indexL != ptrA->allocIndexE )
408	{
409		bbs_ERROR0( "Memory consistency check failed" );
410	}
411}
412
413/* ------------------------------------------------------------------------- */
414
415/* ========================================================================= */
416