2 Copyright � 1995-2011, The AROS Development Team. All rights reserved.
5 Desc: System memory allocator for MMU-less systems.
6 Used also as boot-time memory allocator on systems with MMU.
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>
18 #include "exec_intern.h"
19 #include "exec_util.h"
22 APTR
nommu_AllocMem(IPTR byteSize
, ULONG flags
, struct TraceLocation
*loc
, struct ExecBase
*SysBase
)
26 ULONG requirements
= flags
& MEMF_PHYSICAL_MASK
;
28 /* Protect memory list against other tasks */
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
)
45 struct MemHeaderExt
*mhe
= (struct MemHeaderExt
*)mh
;
48 res
= mhe
->mhe_Alloc(mhe
, byteSize
, &flags
);
52 res
= stdAlloc(mh
, mhac_GetSysCtx(mh
, SysBase
), byteSize
, flags
, loc
, SysBase
);
63 APTR
nommu_AllocAbs(APTR location
, IPTR byteSize
, struct ExecBase
*SysBase
)
67 APTR endlocation
= location
+ byteSize
;
69 /* Protect the memory list from access by other tasks. */
72 /* Loop over MemHeader structures */
73 ForeachNode(&SysBase
->MemList
, mh
)
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
);
91 if (mh
->mh_Lower
<= location
&& mh
->mh_Upper
>= endlocation
)
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
117 p1
= (struct MemChunk
*)&mh
->mh_First
;
120 /* Follow the list to find a chunk with our memory. */
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
);
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
);
156 /* Found a chunk that fits? */
157 if((UBYTE
*)p2
+p2
->mc_Bytes
>=(UBYTE
*)p4
&&p2
<=p3
)
159 /* Since AllocAbs allocations never allocate/update a ctx, they need to clear it if it exists */
160 mhac_ClearSysCtx(mh
, SysBase
);
162 /* Check if there's memory left at the end. */
163 if((UBYTE
*)p2
+p2
->mc_Bytes
!=(UBYTE
*)p4
)
165 /* Yes. Add it to the list */
166 p4
->mc_Next
= p2
->mc_Next
;
167 p4
->mc_Bytes
= (UBYTE
*)p2
+p2
->mc_Bytes
-(UBYTE
*)p4
;
171 /* Check if there's memory left at the start. */
173 /* Yes. Adjust the size */
174 p2
->mc_Bytes
=(UBYTE
*)p3
-(UBYTE
*)p2
;
176 /* No. Skip the old chunk */
177 p1
->mc_Next
=p2
->mc_Next
;
179 /* Adjust free memory count */
180 mh
->mh_Free
-=byteSize
;
182 /* Return the memory */
186 /* goto next chunk */
198 void nommu_FreeMem(APTR memoryBlock
, IPTR byteSize
, struct TraceLocation
*loc
, struct ExecBase
*SysBase
)
200 struct MemHeader
*mh
;
203 /* It is legal to free zero bytes */
207 blockEnd
= memoryBlock
+ byteSize
;
209 /* Protect the memory list from access by other tasks. */
212 ForeachNode(&SysBase
->MemList
, mh
)
214 if (IsManagedMem(mh
))
216 struct MemHeaderExt
*mhe
= (struct MemHeaderExt
*)mh
;
218 if (mhe
->mhe_InBounds(mhe
, memoryBlock
, blockEnd
))
222 mhe
->mhe_Free(mhe
, memoryBlock
, byteSize
);
231 /* Test if the memory belongs to this MemHeader. */
232 if (mh
->mh_Lower
> memoryBlock
|| mh
->mh_Upper
< blockEnd
)
235 stdDealloc(mh
, mhac_GetSysCtx(mh
, SysBase
), memoryBlock
, byteSize
, loc
, SysBase
);
238 ReturnVoid ("nommu_FreeMem");
243 #if !defined(NO_CONSISTENCY_CHECKS)
244 /* Some memory that didn't fit into any MemHeader? */
245 bug("[MM] Chunk allocator error\n");
246 bug("[MM] Attempt to free %u bytes at 0x%p\n", byteSize
, memoryBlock
);
247 bug("[MM] The block does not belong to any MemHeader\n");
249 Alert(AN_BadFreeAddr
);
252 ReturnVoid ("nommu_FreeMem");
255 IPTR
nommu_AvailMem(ULONG attributes
, struct ExecBase
*SysBase
)
258 struct MemHeader
*mh
;
259 ULONG physFlags
= attributes
& MEMF_PHYSICAL_MASK
;
261 D(bug("[MM] nommu_AvailMem(0x%08X)\n", attributes
));
262 D(bug("[MM] physical memory flags: 0x%08X\n", physFlags
));
264 /* Nobody else should access the memory lists now. */
267 ForeachNode(&SysBase
->MemList
, mh
)
269 D(bug("[MM] Checking MemHeader 0x%p\n", mh
));
272 * The current memheader is OK if there's no bit in the
273 * 'physFlags' that isn't set in the 'mh->mh_Attributes'.
275 if (physFlags
& ~mh
->mh_Attributes
)
277 D(bug("[MM] Skipping (mh_Attributes = 0x%08X\n", mh
->mh_Attributes
));
281 if (IsManagedMem(mh
))
283 struct MemHeaderExt
*mhe
= (struct MemHeaderExt
*)mh
;
287 IPTR val
= mhe
->mhe_Avail(mhe
, attributes
);
289 if (attributes
& MEMF_LARGEST
)
301 /* Find largest chunk? */
302 if (attributes
& MEMF_LARGEST
)
305 * Yes. Follow the list of MemChunks and set 'ret' to
306 * each value that is bigger than all previous ones.
310 for (mc
= mh
->mh_First
; mc
; mc
= mc
->mc_Next
)
312 #if !defined(NO_CONSISTENCY_CHECKS)
314 * Do some constistency checks:
315 * 1. All MemChunks must be aligned to MEMCHUNK_TOTAL.
317 if (((IPTR
)mc
| mc
->mc_Bytes
) & (MEMCHUNK_TOTAL
-1))
319 bug("[MM] Chunk allocator error in MemHeader 0x%p\n", mh
);
320 bug("[MM] Misaligned chunk at 0x%p (%u bytes)\n", mc
, mc
->mc_Bytes
);
322 Alert(AN_MemoryInsane
|AT_DeadEnd
);
324 /* 2. The end (+1) of the current MemChunk must be lower than the start of the next one. */
325 if (mc
->mc_Next
&& ((UBYTE
*)mc
+ mc
->mc_Bytes
>= (UBYTE
*)mc
->mc_Next
))
327 bug("[MM] Chunk allocator error in MemHeader 0x%p\n");
328 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
);
330 Alert(AN_MemoryInsane
|AT_DeadEnd
);
333 if (mc
->mc_Bytes
>ret
)
337 else if (attributes
& MEMF_TOTAL
)
338 /* Determine total size. */
339 ret
+= (IPTR
)mh
->mh_Upper
- (IPTR
)mh
->mh_Lower
;
341 /* Sum up free memory. */