Updated PCI IDs to latest snapshot.
[tangerine.git] / rom / exec / allocmem.c
blob3febf57057bad050b32f157ac527716f6e7e0fec
1 /*
2 Copyright © 1995-2008, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Allocate some memory
6 Lang: english
7 */
8 #include <exec/alerts.h>
9 #include <exec/execbase.h>
10 #include <aros/libcall.h>
11 #include <aros/asmcall.h>
12 #include <aros/rt.h>
13 #include <aros/macros.h>
14 #include <aros/config.h>
15 #include <aros/arossupportbase.h>
16 #include "memory.h"
17 #include <exec/memory.h>
18 #include <exec/memheaderext.h>
19 #include <exec/nodes.h>
20 #include <dos/dos.h>
21 #include <dos/dosextens.h>
22 #include <proto/exec.h>
24 #include <string.h>
26 #include "exec_debug.h"
27 #ifndef DEBUG_AllocMem
28 # define DEBUG_AllocMem 0
29 #endif
30 #undef DEBUG
31 #if DEBUG_AllocMem
32 # define DEBUG 1
33 #endif
34 #define MDEBUG 0
35 # include <aros/debug.h>
37 struct checkMemHandlersState
39 struct Node *cmhs_CurNode;
40 struct MemHandlerData cmhs_Data;
43 static APTR stdAlloc(struct MemHeader *mh, ULONG byteSize, ULONG requiements);
44 static ULONG checkMemHandlers(struct checkMemHandlersState *cmhs);
46 /*****************************************************************************
48 NAME */
50 AROS_LH2(APTR, AllocMem,
52 /* SYNOPSIS */
53 AROS_LHA(ULONG, byteSize, D0),
54 AROS_LHA(ULONG, requirements, D1),
56 /* LOCATION */
57 struct ExecBase *, SysBase, 33, Exec)
59 /* FUNCTION
60 Allocate some memory from the sytem memory pool with the given
61 requirements.
63 INPUTS
64 byteSize - Number of bytes you want to get
65 requirements - Type of memory
67 RESULT
68 A pointer to the number of bytes you wanted or NULL if the memory
69 couldn't be allocated
71 NOTES
72 The memory is aligned to sizeof(struct MemChunk). All requests
73 are rounded up to a multiple of that size.
75 EXAMPLE
76 mytask=(struct Task *)AllocMem(sizeof(struct Task),MEMF_PUBLIC|MEMF_CLEAR);
78 BUGS
80 SEE ALSO
81 FreeMem()
83 INTERNALS
85 ******************************************************************************/
87 AROS_LIBFUNC_INIT
89 APTR res = NULL;
90 struct checkMemHandlersState cmhs;
92 #if ENABLE_RT || AROS_MUNGWALL_DEBUG
93 ULONG origSize = byteSize;
94 ULONG origRequirements = requirements;
95 #endif
97 D(if (SysBase->DebugAROSBase))
98 D(bug("Call AllocMem (%d, %08x)\n", byteSize, requirements));
100 /* Zero bytes requested? May return everything ;-). */
101 if(!byteSize)
102 return NULL;
104 #if AROS_MUNGWALL_DEBUG
105 /* Make room for safety walls around allocated block and an some more extra space
106 for other interesting things, actually --> the size.
108 This all will look like this:
110 [MEMCHUNK_FOR_EXTRA_STUFF][BEFORE-MUNGWALL][<alloced-memory-for-user>][AFTER_MUNGWALL]
112 The first ULONG in MEMCHUNK_FOR_EXTRA_STUFF is used to save the original alloc
113 size (byteSize) param. So it is possible in FreeMem to check, if freemem size
114 matches allocmem size or not.
117 byteSize += MUNGWALL_SIZE * 2 + MUNGWALLHEADER_SIZE;
118 #endif /* AROS_MUNGWALL_DEBUG */
120 /* First round byteSize to a multiple of MEMCHUNK_TOTAL */
121 byteSize = AROS_ROUNDUP2(byteSize, MEMCHUNK_TOTAL);
123 cmhs.cmhs_CurNode = (struct Node *)SysBase->ex_MemHandlers.mlh_Head;
124 cmhs.cmhs_Data.memh_RequestSize = byteSize;
125 cmhs.cmhs_Data.memh_RequestFlags = requirements;
126 cmhs.cmhs_Data.memh_Flags = 0;
128 /* Protect memory list against other tasks */
129 Forbid();
133 struct MemHeader *mh;
135 /* Loop over MemHeader structures */
136 ForeachNode(&SysBase->MemList, mh)
139 Check for the right requirements and enough free memory.
140 The requirements are OK if there's no bit in the
141 'attributes' that isn't set in the 'mh->mh_Attributes'.
142 MEMF_CLEAR, MEMF_REVERSE and MEMF_NO_EXPUNGE are treated
143 as if they were always set in the memheader.
145 if((requirements & ~(MEMF_CLEAR|MEMF_REVERSE|
146 MEMF_NO_EXPUNGE|mh->mh_Attributes))
147 || mh->mh_Free < byteSize)
148 continue;
150 if (mh->mh_Attributes & MEMF_MANAGED)
152 struct MemHeaderExt *mhe = (struct MemHeaderExt *)mh;
153 if (mhe->mhe_Alloc)
154 res = mhe->mhe_Alloc(mhe, byteSize, &requirements);
156 else
158 res = stdAlloc(mh, byteSize, requirements);
160 if (res)
161 break;
163 } while (res == NULL && checkMemHandlers(&cmhs) == MEM_TRY_AGAIN);
165 Permit();
167 if(res && (requirements & MEMF_CLEAR))
168 memset(res, 0, byteSize);
170 #if ENABLE_RT
171 RT_Add (RTT_MEMORY, res, origSize);
172 #endif
174 #if AROS_MUNGWALL_DEBUG
175 requirements = origRequirements;
177 if (res)
179 struct MungwallHeader *header;
180 struct List *allocmemlist;
182 /* Save orig byteSize before wall (there is one room of MUNGWALLHEADER_SIZE
183 bytes before wall for such stuff (see above).
186 header = (struct MungwallHeader *)res;
188 header->mwh_magicid = MUNGWALL_HEADER_ID;
189 header->mwh_allocsize = origSize;
191 /* Check whether list exists. AllocMem() might have been
192 called before PrepareAROSSupportBase(), which is responsible for
193 initialization of AllocMemList */
195 if (SysBase->DebugAROSBase)
197 allocmemlist = (struct List *)&((struct AROSSupportBase *)SysBase->DebugAROSBase)->AllocMemList;
198 Forbid();
199 AddHead(allocmemlist, (struct Node *)&header->mwh_node);
200 Permit();
202 else
204 header->mwh_node.mln_Pred = (struct MinNode *)0x44332211;
205 header->mwh_node.mln_Succ = (struct MinNode *)0xCCBBAA99;
208 /* Skip to the start of the pre-wall */
209 res += MUNGWALLHEADER_SIZE;
211 /* Initialize pre-wall */
212 BUILD_WALL(res, 0xDB, MUNGWALL_SIZE);
214 /* move over the block between the walls */
215 res += MUNGWALL_SIZE;
217 /* Fill the block with weird stuff to exploit bugs in applications */
218 if (!(requirements & MEMF_CLEAR))
219 MUNGE_BLOCK(res, MEMFILL_ALLOC, byteSize - MUNGWALL_SIZE * 2 - MEMCHUNK_TOTAL);
221 /* Initialize post-wall */
222 BUILD_WALL(res + origSize, 0xDB, MUNGWALL_SIZE + AROS_ROUNDUP2(origSize, MEMCHUNK_TOTAL) - origSize);
224 #endif /* AROS_MUNGWALL_DEBUG */
226 /* Set DOS error if called from a process */
227 if (res == NULL)
229 struct Process *process = (struct Process *)FindTask(NULL);
230 if (process->pr_Task.tc_Node.ln_Type == NT_PROCESS)
231 process->pr_Result2 = ERROR_NO_FREE_STORE;
234 #if DEBUG
235 if (SysBase->DebugAROSBase)
236 ReturnPtr ("AllocMem", APTR, res)
237 else
238 return res;
239 #else
240 ReturnPtr ("AllocMem", APTR, res);
241 #endif
243 AROS_LIBFUNC_EXIT
245 } /* AllocMem */
248 static APTR stdAlloc(struct MemHeader *mh, ULONG byteSize, ULONG requirements)
250 struct MemChunk *mc=NULL, *p1, *p2;
253 The free memory list is only single linked, i.e. to remove
254 elements from the list I need node's predessor. For the
255 first element I can use mh->mh_First instead of a real predessor.
257 p1 = (struct MemChunk *)&mh->mh_First;
258 p2 = p1->mc_Next;
260 /* Is there anything in the list? */
261 if (p2 != NULL)
263 /* Then follow it */
264 for (;;)
266 #if !defined(NO_CONSISTENCY_CHECKS)
267 /* Consistency check: Check alignment restrictions */
268 if( ((IPTR)p2|(ULONG)p2->mc_Bytes)
269 & (MEMCHUNK_TOTAL-1) )
270 Alert(AN_MemCorrupt|AT_DeadEnd);
271 #endif
273 /* Check if the current block is large enough */
274 if(p2->mc_Bytes>=byteSize)
276 /* It is. */
277 mc=p1;
278 /* Use this one if MEMF_REVERSE is not set.*/
279 if(!(requirements&MEMF_REVERSE))
280 break;
281 /* Else continue - there may be more to come. */
284 /* Go to next block */
285 p1=p2;
286 p2=p1->mc_Next;
288 /* Check if this was the end */
289 if(p2==NULL)
290 break;
291 #if !defined(NO_CONSISTENCY_CHECKS)
293 Consistency check:
294 If the end of the last block+1 is bigger or equal to
295 the start of the current block something must be wrong.
297 if((UBYTE *)p2<=(UBYTE *)p1+p1->mc_Bytes)
298 Alert(AN_MemCorrupt|AT_DeadEnd);
299 #endif
302 /* Something found? */
303 if (mc != NULL)
306 Remember: if MEMF_REVERSE is set
307 p1 and p2 are now invalid.
309 p1=mc;
310 p2=p1->mc_Next;
312 /* Remove the block from the list and return it. */
313 if(p2->mc_Bytes == byteSize)
315 /* Fits exactly. Just relink the list. */
316 p1->mc_Next = p2->mc_Next;
317 mc = p2;
319 else
321 if(requirements & MEMF_REVERSE)
323 /* Return the last bytes. */
324 p1->mc_Next=p2;
325 mc=(struct MemChunk *)((UBYTE *)p2+p2->mc_Bytes-byteSize);
327 else
329 /* Return the first bytes. */
330 p1->mc_Next=(struct MemChunk *)((UBYTE *)p2+byteSize);
331 mc=p2;
334 p1 = p1->mc_Next;
335 p1->mc_Next = p2->mc_Next;
336 p1->mc_Bytes = p2->mc_Bytes-byteSize;
339 mh->mh_Free -= byteSize;
343 return mc;
346 ULONG checkMemHandlers(struct checkMemHandlersState *cmhs)
348 struct Node *tmp;
349 struct Interrupt *lmh;
351 if (cmhs->cmhs_Data.memh_RequestFlags & MEMF_NO_EXPUNGE)
352 return MEM_DID_NOTHING;
354 /* Loop over low memory handlers. Handlers can remove
355 themselves from the list while being invoked, thus
356 we need to be careful! */
359 lmh = (struct Interrupt *)cmhs->cmhs_CurNode;
360 (tmp = lmh->is_Node.ln_Succ);
361 lmh = (struct Interrupt *)(cmhs->cmhs_CurNode = tmp)
364 ULONG ret;
366 ret = AROS_UFC3 (LONG, lmh->is_Code,
367 AROS_UFCA(struct MemHandlerData *, &cmhs->cmhs_Data, A0),
368 AROS_UFCA(APTR, lmh->is_Data, A1),
369 AROS_UFCA(struct ExecBase *, SysBase, A6)
372 if (ret == MEM_TRY_AGAIN)
374 /* MemHandler said he did something. Try again. */
375 /* Is there any program that depends on this flag??? */
376 cmhs->cmhs_Data.memh_Flags |= MEMHF_RECYCLE;
377 return MEM_TRY_AGAIN;
379 else
381 /* Nothing more to expect from this handler. */
382 cmhs->cmhs_Data.memh_Flags &= ~MEMHF_RECYCLE;
386 return MEM_DID_NOTHING;