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
->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
)
84 return mhe
->mhe_AllocAbs(mhe
, byteSize
, location
);
89 if (mh
->mh_Lower
<= location
&& mh
->mh_Upper
>= endlocation
)
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
115 p1
= (struct MemChunk
*)&mh
->mh_First
;
118 /* Follow the list to find a chunk with our memory. */
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
);
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
);
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
;
168 /* Check if there's memory left at the start. */
170 /* Yes. Adjust the size */
171 p2
->mc_Bytes
=(UBYTE
*)p3
-(UBYTE
*)p2
;
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 */
183 /* goto next chunk */
195 void nommu_FreeMem(APTR memoryBlock
, IPTR byteSize
, struct TraceLocation
*loc
, struct ExecBase
*SysBase
)
197 struct MemHeader
*mh
;
200 /* It is legal to free zero bytes */
204 blockEnd
= memoryBlock
+ byteSize
;
206 /* Protect the memory list from access by other tasks. */
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
))
219 mhe
->mhe_Free(mhe
, location
, byteSize
);
228 /* Test if the memory belongs to this MemHeader. */
229 if (mh
->mh_Lower
> memoryBlock
|| mh
->mh_Upper
< blockEnd
)
232 stdDealloc(mh
, mhac_GetSysCtx(mh
, SysBase
), memoryBlock
, byteSize
, loc
, SysBase
);
235 ReturnVoid ("nommu_FreeMem");
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
);
249 ReturnVoid ("nommu_FreeMem");
252 IPTR
nommu_AvailMem(ULONG attributes
, struct ExecBase
*SysBase
)
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. */
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
));
278 if (mh
->mh_Attributes
& MEMF_MANAGED
)
280 struct MemHeaderExt
*mhe
= (struct MemHeaderExt
*)mh
;
284 IPTR val
= mhe
->mhe_Avail(mhe
, attributes
);
286 if (attributes
& MEMF_LARGEST
)
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.
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
);
330 if (mc
->mc_Bytes
>ret
)
334 else if (attributes
& MEMF_TOTAL
)
335 /* Determine total size. */
336 ret
+= (IPTR
)mh
->mh_Upper
- (IPTR
)mh
->mh_Lower
;
338 /* Sum up free memory. */