support for MEMF_MANAGED memory is back in the system. Moreover, the MemHeaderExt...
[AROS.git] / rom / exec / memory_nommu.c
blob3d19000619107f6fe4e1f89af26587a78ea0e90e
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->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 MEM_UNLOCK;
84 return mhe->mhe_AllocAbs(mhe, byteSize, location);
88 else
89 if (mh->mh_Lower <= location && mh->mh_Upper >= endlocation)
90 break;
93 /* If no header was found which matched the requirements, just give up. */
94 if (mh->mh_Node.ln_Succ)
96 struct MemChunk *p1, *p2, *p3, *p4;
98 /* Align size to the requirements */
99 byteSize += (IPTR)location&(MEMCHUNK_TOTAL - 1);
100 byteSize = (byteSize + MEMCHUNK_TOTAL-1) & ~(MEMCHUNK_TOTAL-1);
102 /* Align the location as well */
103 location=(APTR)((IPTR)location & ~(MEMCHUNK_TOTAL-1));
105 /* Start and end(+1) of the block */
106 p3=(struct MemChunk *)location;
107 p4=(struct MemChunk *)((UBYTE *)p3+byteSize);
110 The free memory list is only single linked, i.e. to remove
111 elements from the list I need the node's predessor. For the
112 first element I can use freeList->mh_First instead of a real
113 predecessor.
115 p1 = (struct MemChunk *)&mh->mh_First;
116 p2 = p1->mc_Next;
118 /* Follow the list to find a chunk with our memory. */
119 while (p2 != NULL)
121 #if !defined(NO_CONSISTENCY_CHECKS)
123 * Memory list consistency checks.
124 * 1. Check alignment restrictions
126 if (((IPTR)p2|(IPTR)p2->mc_Bytes) & (MEMCHUNK_TOTAL-1))
128 if (SysBase && SysBase->DebugAROSBase)
130 bug("[MM] Chunk allocator error\n");
131 bug("[MM] Attempt to allocate %lu bytes at 0x%p from MemHeader 0x%p\n", byteSize, location, mh);
132 bug("[MM] Misaligned chunk at 0x%p (%u bytes)\n", p2, p2->mc_Bytes);
134 Alert(AN_MemoryInsane|AT_DeadEnd);
136 break;
139 /* 2. Check against overlapping blocks */
140 if (p2->mc_Next && ((UBYTE *)p2 + p2->mc_Bytes >= (UBYTE *)p2->mc_Next))
142 if (SysBase && SysBase->DebugAROSBase)
144 bug("[MM] Chunk allocator error\n");
145 bug("[MM] Attempt to allocate %lu bytes at 0x%p from MemHeader 0x%p\n", byteSize, location, mh);
146 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);
148 Alert(AN_MemoryInsane|AT_DeadEnd);
150 break;
152 #endif
154 /* Found a chunk that fits? */
155 if((UBYTE *)p2+p2->mc_Bytes>=(UBYTE *)p4&&p2<=p3)
157 mhac_MemChunkClaimed(p2, mhac_GetSysCtx(mh, SysBase));
159 /* Check if there's memory left at the end. */
160 if((UBYTE *)p2+p2->mc_Bytes!=(UBYTE *)p4)
162 /* Yes. Add it to the list */
163 p4->mc_Next = p2->mc_Next;
164 p4->mc_Bytes = (UBYTE *)p2+p2->mc_Bytes-(UBYTE *)p4;
165 p2->mc_Next = p4;
168 /* Check if there's memory left at the start. */
169 if(p2!=p3)
170 /* Yes. Adjust the size */
171 p2->mc_Bytes=(UBYTE *)p3-(UBYTE *)p2;
172 else
173 /* No. Skip the old chunk */
174 p1->mc_Next=p2->mc_Next;
176 /* Adjust free memory count */
177 mh->mh_Free-=byteSize;
179 /* Return the memory */
180 ret = p3;
181 break;
183 /* goto next chunk */
185 p1=p2;
186 p2=p2->mc_Next;
190 MEM_UNLOCK;
192 return ret;
195 void nommu_FreeMem(APTR memoryBlock, IPTR byteSize, struct TraceLocation *loc, struct ExecBase *SysBase)
197 struct MemHeader *mh;
198 APTR blockEnd;
200 /* It is legal to free zero bytes */
201 if (!byteSize)
202 return;
204 blockEnd = memoryBlock + byteSize;
206 /* Protect the memory list from access by other tasks. */
207 MEM_LOCK;
209 ForeachNode(&SysBase->MemList, mh)
211 if (mh->mh_Attributes & MEMF_MANAGED)
213 struct MemHeaderExt *mhe = (struct MemHeaderExt *)mh;
215 if (mhe->mhe_InBounds(mhe, location, blockEnd))
217 if (mhe->mhe_Free)
219 mhe->mhe_Free(mhe, location, byteSize);
221 MEM_UNLOCK;
222 return;
226 else
228 /* Test if the memory belongs to this MemHeader. */
229 if (mh->mh_Lower > memoryBlock || mh->mh_Upper < blockEnd)
230 continue;
232 stdDealloc(mh, mhac_GetSysCtx(mh, SysBase), memoryBlock, byteSize, loc, SysBase);
234 MEM_UNLOCK;
235 ReturnVoid ("nommu_FreeMem");
238 MEM_UNLOCK;
240 #if !defined(NO_CONSISTENCY_CHECKS)
241 /* Some memory that didn't fit into any MemHeader? */
242 bug("[MM] Chunk allocator error\n");
243 bug("[MM] Attempt to free %u bytes at 0x%p\n", byteSize, memoryBlock);
244 bug("[MM] The block does not belong to any MemHeader\n");
246 Alert(AN_BadFreeAddr);
247 #endif
249 ReturnVoid ("nommu_FreeMem");
252 IPTR nommu_AvailMem(ULONG attributes, struct ExecBase *SysBase)
254 IPTR ret = 0;
255 struct MemHeader *mh;
256 ULONG physFlags = attributes & MEMF_PHYSICAL_MASK;
258 D(bug("[MM] nommu_AvailMem(0x%08X)\n", attributes));
259 D(bug("[MM] physical memory flags: 0x%08X\n", physFlags));
261 /* Nobody else should access the memory lists now. */
262 MEM_LOCK_SHARED;
264 ForeachNode(&SysBase->MemList, mh)
266 D(bug("[MM] Checking MemHeader 0x%p\n", mh));
269 * The current memheader is OK if there's no bit in the
270 * 'physFlags' that isn't set in the 'mh->mh_Attributes'.
272 if (physFlags & ~mh->mh_Attributes)
274 D(bug("[MM] Skipping (mh_Attributes = 0x%08X\n", mh->mh_Attributes));
275 continue;
278 if (mh->mh_Attributes & MEMF_MANAGED)
280 struct MemHeaderExt *mhe = (struct MemHeaderExt *)mh;
282 if (mhe->mhe_Avail)
284 IPTR val = mhe->mhe_Avail(mhe, attributes);
286 if (attributes & MEMF_LARGEST)
288 if (val > ret)
289 ret = val;
291 else
292 ret += val;
294 continue;
298 /* Find largest chunk? */
299 if (attributes & MEMF_LARGEST)
302 * Yes. Follow the list of MemChunks and set 'ret' to
303 * each value that is bigger than all previous ones.
305 struct MemChunk *mc;
307 for (mc = mh->mh_First; mc; mc = mc->mc_Next)
309 #if !defined(NO_CONSISTENCY_CHECKS)
311 * Do some constistency checks:
312 * 1. All MemChunks must be aligned to MEMCHUNK_TOTAL.
314 if (((IPTR)mc | mc->mc_Bytes) & (MEMCHUNK_TOTAL-1))
316 bug("[MM] Chunk allocator error in MemHeader 0x%p\n", mh);
317 bug("[MM] Misaligned chunk at 0x%p (%u bytes)\n", mc, mc->mc_Bytes);
319 Alert(AN_MemoryInsane|AT_DeadEnd);
321 /* 2. The end (+1) of the current MemChunk must be lower than the start of the next one. */
322 if (mc->mc_Next && ((UBYTE *)mc + mc->mc_Bytes >= (UBYTE *)mc->mc_Next))
324 bug("[MM] Chunk allocator error in MemHeader 0x%p\n");
325 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);
327 Alert(AN_MemoryInsane|AT_DeadEnd);
329 #endif
330 if (mc->mc_Bytes>ret)
331 ret=mc->mc_Bytes;
334 else if (attributes & MEMF_TOTAL)
335 /* Determine total size. */
336 ret += (IPTR)mh->mh_Upper - (IPTR)mh->mh_Lower;
337 else
338 /* Sum up free memory. */
339 ret += mh->mh_Free;
342 /* All done */
343 MEM_UNLOCK;
345 return ret;