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
)
43 if (mh
->mh_Attributes
& MEMF_MANAGED
)
45 struct MemHeaderExt
*mhe
= (struct MemHeaderExt
*)mh
;
48 res
= mhe
->mhe_Alloc(mhe
, byteSize
, &requirements
);
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
)
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
);
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 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
;
170 /* Check if there's memory left at the start. */
172 /* Yes. Adjust the size */
173 p2
->mc_Bytes
=(UBYTE
*)p3
-(UBYTE
*)p2
;
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 */
185 /* goto next chunk */
197 void nommu_FreeMem(APTR memoryBlock
, IPTR byteSize
, struct TraceLocation
*loc
, struct ExecBase
*SysBase
)
199 struct MemHeader
*mh
;
202 /* It is legal to free zero bytes */
206 blockEnd
= memoryBlock
+ byteSize
;
208 /* Protect the memory list from access by other tasks. */
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
))
221 mhe
->mhe_Free(mhe
, memoryBlock
, byteSize
);
230 /* Test if the memory belongs to this MemHeader. */
231 if (mh
->mh_Lower
> memoryBlock
|| mh
->mh_Upper
< blockEnd
)
234 stdDealloc(mh
, mhac_GetSysCtx(mh
, SysBase
), memoryBlock
, byteSize
, loc
, SysBase
);
237 ReturnVoid ("nommu_FreeMem");
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
);
251 ReturnVoid ("nommu_FreeMem");
254 IPTR
nommu_AvailMem(ULONG attributes
, struct ExecBase
*SysBase
)
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. */
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
));
280 if (mh
->mh_Attributes
& MEMF_MANAGED
)
282 struct MemHeaderExt
*mhe
= (struct MemHeaderExt
*)mh
;
286 IPTR val
= mhe
->mhe_Avail(mhe
, attributes
);
288 if (attributes
& MEMF_LARGEST
)
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.
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
);
332 if (mc
->mc_Bytes
>ret
)
336 else if (attributes
& MEMF_TOTAL
)
337 /* Determine total size. */
338 ret
+= (IPTR
)mh
->mh_Upper
- (IPTR
)mh
->mh_Lower
;
340 /* Sum up free memory. */