support for MEMF_MANAGED memory extended. Now pools can be handled by
[AROS.git] / rom / exec / memory_nommu.c
blob1645c09c8dee1f1c0d730a46f7c7ab6bf3eee8bf
1 /*
2 Copyright � 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: System memory allocator for MMU-less systems.
6 Used also as boot-time memory allocator on systems with MMU.
7 Lang: english
8 */
10 #include <aros/debug.h>
11 #include <exec/execbase.h>
12 #include <exec/memory.h>
13 #include <exec/memheaderext.h>
14 #include <proto/exec.h>
16 #include <string.h>
18 #include "exec_intern.h"
19 #include "exec_util.h"
20 #include "memory.h"
22 APTR nommu_AllocMem(IPTR byteSize, ULONG flags, struct TraceLocation *loc, struct ExecBase *SysBase)
24 APTR res = NULL;
25 struct MemHeader *mh;
26 ULONG requirements = flags & MEMF_PHYSICAL_MASK;
28 /* Protect memory list against other tasks */
29 MEM_LOCK;
31 /* Loop over MemHeader structures */
32 ForeachNode(&SysBase->MemList, mh)
35 * Check for the right requirements and enough free memory.
36 * The requirements are OK if there's no bit in the
37 * 'attributes' that isn't set in the 'mh->mh_Attributes'.
39 if ((requirements & ~mh->mh_Attributes)
40 || mh->mh_Free < byteSize)
41 continue;
43 if (mh->mh_Attributes & MEMF_MANAGED)
45 struct MemHeaderExt *mhe = (struct MemHeaderExt *)mh;
47 if (mhe->mhe_Alloc)
48 res = mhe->mhe_Alloc(mhe, byteSize, &requirements);
50 else
52 res = stdAlloc(mh, mhac_GetSysCtx(mh, SysBase), byteSize, flags, loc, SysBase);
54 if (res)
55 break;
58 MEM_UNLOCK;
60 return res;
63 APTR nommu_AllocAbs(APTR location, IPTR byteSize, struct ExecBase *SysBase)
65 struct MemHeader *mh;
66 APTR ret = NULL;
67 APTR endlocation = location + byteSize;
69 /* Protect the memory list from access by other tasks. */
70 MEM_LOCK;
72 /* Loop over MemHeader structures */
73 ForeachNode(&SysBase->MemList, mh)
75 if (mh->mh_Attributes & MEMF_MANAGED)
77 struct MemHeaderExt *mhe = (struct MemHeaderExt *)mh;
78 if (mhe->mhe_InBounds(mhe, location, endlocation))
80 if (mhe->mhe_AllocAbs)
82 void * ret = mhe->mhe_AllocAbs(mhe, byteSize, location);
84 MEM_UNLOCK;
86 return ret;
90 else
91 if (mh->mh_Lower <= location && mh->mh_Upper >= endlocation)
92 break;
95 /* If no header was found which matched the requirements, just give up. */
96 if (mh->mh_Node.ln_Succ)
98 struct MemChunk *p1, *p2, *p3, *p4;
100 /* Align size to the requirements */
101 byteSize += (IPTR)location&(MEMCHUNK_TOTAL - 1);
102 byteSize = (byteSize + MEMCHUNK_TOTAL-1) & ~(MEMCHUNK_TOTAL-1);
104 /* Align the location as well */
105 location=(APTR)((IPTR)location & ~(MEMCHUNK_TOTAL-1));
107 /* Start and end(+1) of the block */
108 p3=(struct MemChunk *)location;
109 p4=(struct MemChunk *)((UBYTE *)p3+byteSize);
112 The free memory list is only single linked, i.e. to remove
113 elements from the list I need the node's predessor. For the
114 first element I can use freeList->mh_First instead of a real
115 predecessor.
117 p1 = (struct MemChunk *)&mh->mh_First;
118 p2 = p1->mc_Next;
120 /* Follow the list to find a chunk with our memory. */
121 while (p2 != NULL)
123 #if !defined(NO_CONSISTENCY_CHECKS)
125 * Memory list consistency checks.
126 * 1. Check alignment restrictions
128 if (((IPTR)p2|(IPTR)p2->mc_Bytes) & (MEMCHUNK_TOTAL-1))
130 if (SysBase && SysBase->DebugAROSBase)
132 bug("[MM] Chunk allocator error\n");
133 bug("[MM] Attempt to allocate %lu bytes at 0x%p from MemHeader 0x%p\n", byteSize, location, mh);
134 bug("[MM] Misaligned chunk at 0x%p (%u bytes)\n", p2, p2->mc_Bytes);
136 Alert(AN_MemoryInsane|AT_DeadEnd);
138 break;
141 /* 2. Check against overlapping blocks */
142 if (p2->mc_Next && ((UBYTE *)p2 + p2->mc_Bytes >= (UBYTE *)p2->mc_Next))
144 if (SysBase && SysBase->DebugAROSBase)
146 bug("[MM] Chunk allocator error\n");
147 bug("[MM] Attempt to allocate %lu bytes at 0x%p from MemHeader 0x%p\n", byteSize, location, mh);
148 bug("[MM] Overlapping chunks 0x%p (%u bytes) and 0x%p (%u bytes)\n", p2, p2->mc_Bytes, p2->mc_Next, p2->mc_Next->mc_Bytes);
150 Alert(AN_MemoryInsane|AT_DeadEnd);
152 break;
154 #endif
156 /* Found a chunk that fits? */
157 if((UBYTE *)p2+p2->mc_Bytes>=(UBYTE *)p4&&p2<=p3)
159 mhac_MemChunkClaimed(p2, mhac_GetSysCtx(mh, SysBase));
161 /* Check if there's memory left at the end. */
162 if((UBYTE *)p2+p2->mc_Bytes!=(UBYTE *)p4)
164 /* Yes. Add it to the list */
165 p4->mc_Next = p2->mc_Next;
166 p4->mc_Bytes = (UBYTE *)p2+p2->mc_Bytes-(UBYTE *)p4;
167 p2->mc_Next = p4;
170 /* Check if there's memory left at the start. */
171 if(p2!=p3)
172 /* Yes. Adjust the size */
173 p2->mc_Bytes=(UBYTE *)p3-(UBYTE *)p2;
174 else
175 /* No. Skip the old chunk */
176 p1->mc_Next=p2->mc_Next;
178 /* Adjust free memory count */
179 mh->mh_Free-=byteSize;
181 /* Return the memory */
182 ret = p3;
183 break;
185 /* goto next chunk */
187 p1=p2;
188 p2=p2->mc_Next;
192 MEM_UNLOCK;
194 return ret;
197 void nommu_FreeMem(APTR memoryBlock, IPTR byteSize, struct TraceLocation *loc, struct ExecBase *SysBase)
199 struct MemHeader *mh;
200 APTR blockEnd;
202 /* It is legal to free zero bytes */
203 if (!byteSize)
204 return;
206 blockEnd = memoryBlock + byteSize;
208 /* Protect the memory list from access by other tasks. */
209 MEM_LOCK;
211 ForeachNode(&SysBase->MemList, mh)
213 if (mh->mh_Attributes & MEMF_MANAGED)
215 struct MemHeaderExt *mhe = (struct MemHeaderExt *)mh;
217 if (mhe->mhe_InBounds(mhe, memoryBlock, blockEnd))
219 if (mhe->mhe_Free)
221 mhe->mhe_Free(mhe, memoryBlock, byteSize);
223 MEM_UNLOCK;
224 return;
228 else
230 /* Test if the memory belongs to this MemHeader. */
231 if (mh->mh_Lower > memoryBlock || mh->mh_Upper < blockEnd)
232 continue;
234 stdDealloc(mh, mhac_GetSysCtx(mh, SysBase), memoryBlock, byteSize, loc, SysBase);
236 MEM_UNLOCK;
237 ReturnVoid ("nommu_FreeMem");
240 MEM_UNLOCK;
242 #if !defined(NO_CONSISTENCY_CHECKS)
243 /* Some memory that didn't fit into any MemHeader? */
244 bug("[MM] Chunk allocator error\n");
245 bug("[MM] Attempt to free %u bytes at 0x%p\n", byteSize, memoryBlock);
246 bug("[MM] The block does not belong to any MemHeader\n");
248 Alert(AN_BadFreeAddr);
249 #endif
251 ReturnVoid ("nommu_FreeMem");
254 IPTR nommu_AvailMem(ULONG attributes, struct ExecBase *SysBase)
256 IPTR ret = 0;
257 struct MemHeader *mh;
258 ULONG physFlags = attributes & MEMF_PHYSICAL_MASK;
260 D(bug("[MM] nommu_AvailMem(0x%08X)\n", attributes));
261 D(bug("[MM] physical memory flags: 0x%08X\n", physFlags));
263 /* Nobody else should access the memory lists now. */
264 MEM_LOCK_SHARED;
266 ForeachNode(&SysBase->MemList, mh)
268 D(bug("[MM] Checking MemHeader 0x%p\n", mh));
271 * The current memheader is OK if there's no bit in the
272 * 'physFlags' that isn't set in the 'mh->mh_Attributes'.
274 if (physFlags & ~mh->mh_Attributes)
276 D(bug("[MM] Skipping (mh_Attributes = 0x%08X\n", mh->mh_Attributes));
277 continue;
280 if (mh->mh_Attributes & MEMF_MANAGED)
282 struct MemHeaderExt *mhe = (struct MemHeaderExt *)mh;
284 if (mhe->mhe_Avail)
286 IPTR val = mhe->mhe_Avail(mhe, attributes);
288 if (attributes & MEMF_LARGEST)
290 if (val > ret)
291 ret = val;
293 else
294 ret += val;
296 continue;
300 /* Find largest chunk? */
301 if (attributes & MEMF_LARGEST)
304 * Yes. Follow the list of MemChunks and set 'ret' to
305 * each value that is bigger than all previous ones.
307 struct MemChunk *mc;
309 for (mc = mh->mh_First; mc; mc = mc->mc_Next)
311 #if !defined(NO_CONSISTENCY_CHECKS)
313 * Do some constistency checks:
314 * 1. All MemChunks must be aligned to MEMCHUNK_TOTAL.
316 if (((IPTR)mc | mc->mc_Bytes) & (MEMCHUNK_TOTAL-1))
318 bug("[MM] Chunk allocator error in MemHeader 0x%p\n", mh);
319 bug("[MM] Misaligned chunk at 0x%p (%u bytes)\n", mc, mc->mc_Bytes);
321 Alert(AN_MemoryInsane|AT_DeadEnd);
323 /* 2. The end (+1) of the current MemChunk must be lower than the start of the next one. */
324 if (mc->mc_Next && ((UBYTE *)mc + mc->mc_Bytes >= (UBYTE *)mc->mc_Next))
326 bug("[MM] Chunk allocator error in MemHeader 0x%p\n");
327 bug("[MM] Overlapping chunks 0x%p (%u bytes) and 0x%p (%u bytes)\n", mc, mc->mc_Bytes, mc->mc_Next, mc->mc_Next->mc_Bytes);
329 Alert(AN_MemoryInsane|AT_DeadEnd);
331 #endif
332 if (mc->mc_Bytes>ret)
333 ret=mc->mc_Bytes;
336 else if (attributes & MEMF_TOTAL)
337 /* Determine total size. */
338 ret += (IPTR)mh->mh_Upper - (IPTR)mh->mh_Lower;
339 else
340 /* Sum up free memory. */
341 ret += mh->mh_Free;
344 /* All done */
345 MEM_UNLOCK;
347 return ret;