revert between 56095 -> 55830 in arch
[AROS.git] / rom / exec / initkicktags.c
blob316b76b50d4f217009aac4bb27415e657ab31df5
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id: initkicktags.c
5 Desc: Handle CoolCapture and KickTags (reset proof residents)
6 Lang: english
7 */
9 #if AROS_SERIAL_DEBUG
10 #define PRINT_LIST
11 #define DEBUG 1
12 #endif
14 #include <aros/debug.h>
15 #include <exec/rawfmt.h>
16 #include <exec/resident.h>
17 #include <proto/exec.h>
19 #include "exec_debug.h"
20 #include "exec_intern.h"
21 #include "exec_util.h"
22 #include "memory.h"
25 /* I don't think KickTag merge can be implemented without ugly hacks.. */
27 static IPTR *CopyResidents(IPTR *list, IPTR *dst, IPTR *oldlist)
29 struct Resident *RomTag;
31 while(*list)
33 IPTR *oldresident;
35 if (*list & RESLIST_NEXT)
37 list = (IPTR *)(*list & ~RESLIST_NEXT);
38 continue;
41 RomTag = (struct Resident*)*list;
43 #ifdef PRINT_LIST
44 bug("* %p: %4d %02x %3d \"%s\"\n",
45 RomTag,
46 RomTag->rt_Pri,
47 RomTag->rt_Flags,
48 RomTag->rt_Version,
49 RomTag->rt_Name);
50 #endif
52 /* Try to find a resident with this name in original list */
53 oldresident = InternalFindResident(RomTag->rt_Name, oldlist);
54 if (oldresident)
57 * If found, check version.
58 * The resident is replaced if:
59 * a) Version of new resident is greater than version of old one.
60 * b) Versions are equal, but priority of new resident is greater than priority of old one.
62 struct Resident *OldRomTag = (struct Resident *)*oldresident;
64 if ((OldRomTag->rt_Version >= RomTag->rt_Version) ||
65 (OldRomTag->rt_Version == RomTag->rt_Version && OldRomTag->rt_Pri >= RomTag->rt_Pri))
67 oldresident = NULL;
71 if (oldresident)
72 *oldresident = *list;
73 else
74 *dst++ = *list;
76 list++;
79 /* Terminate the list */
80 *dst = 0;
81 return dst;
84 /* Count a number of residents in the list */
85 static int CountResidents(IPTR *list)
87 int cnt = 0;
89 while(*list)
91 if (*list & RESLIST_NEXT)
93 list = (IPTR *)(*list & ~RESLIST_NEXT);
94 continue;
97 cnt++;
98 list++;
100 return cnt;
103 static void SortResidents(IPTR *list)
105 BOOL sorted;
106 int i, num;
107 struct Resident **RomTag = (struct Resident**)list;
109 num = CountResidents(list);
112 sorted = TRUE;
114 for (i = 0; i < num - 1; i++)
116 if (RomTag[i]->rt_Pri < RomTag[i+1]->rt_Pri)
118 struct Resident *tmp;
120 tmp = RomTag[i+1];
121 RomTag[i+1] = RomTag[i];
122 RomTag[i] = tmp;
124 sorted = FALSE;
127 } while (!sorted);
131 * Residents in our list must always be sorted by priority.
132 * In order to maintain this, we can't just append new residents to the end of our list.
133 * We have to build a complete new list.
135 static void AddToResidentList(IPTR *list)
137 IPTR *newlist, *tmplist;
138 int oldcnt = CountResidents(SysBase->ResModules);
139 int addcnt = CountResidents(list);
141 /* Allocate space for the new list */
142 newlist = AllocMem((oldcnt + addcnt + 1) * sizeof(struct Resident*), MEMF_PUBLIC);
143 if (!newlist)
144 return;
146 /* Merge two lists and sort. */
147 tmplist = CopyResidents(SysBase->ResModules, newlist, NULL);
148 CopyResidents(list, tmplist, SysBase->ResModules);
149 SortResidents(newlist);
152 * Replace the list.
153 * We just drop the old list without deallocation because noone really knows if it's safe
154 * to deallocate it. With future page-based memory allocator it will certainly be not.
156 SysBase->ResModules = newlist;
158 #ifndef NO_RUNTIME_DEBUG
159 if (SysBase->ex_DebugFlags & EXECDEBUGF_INITCODE)
161 int i;
163 DINITCODE("Resident modules after KickTags merge:");
165 for (i = 0; i < addcnt + oldcnt; i++)
167 struct Resident *RomTag = (struct Resident*)newlist[i];
169 NewRawDoFmt("+ %p: %4ld %02x %3ld \"%s\"\n", (VOID_FUNC)RAWFMTFUNC_SERIAL, NULL,
170 RomTag, RomTag->rt_Pri, RomTag->rt_Flags, RomTag->rt_Version, RomTag->rt_Name);
173 #endif
176 void InitKickTags(struct ExecBase *SysBase)
178 ULONG chk = (ULONG)(IPTR)SysBase->KickCheckSum;
179 ULONG chkold = SumKickData();
180 struct MemList *ml = (struct MemList*)SysBase->KickMemPtr;
182 DINITCODE("kickmemptr=0x%p kicktagptr=0x%p kickchecksum=0x%08lx", SysBase->KickMemPtr, SysBase->KickTagPtr, chk);
184 if (chkold != chk)
186 DINITCODE("Kicktag checksum mismatch %08lx!=%08lx", chkold, chk);
188 SysBase->KickMemPtr = NULL;
189 SysBase->KickTagPtr = NULL;
190 SysBase->KickCheckSum = 0;
192 return;
196 * Before we do anything else, we need to lock down the entries in KickMemPtr
197 * If we get a single failure, don't run any of the KickTags.
199 while (ml) /* single linked! */
201 UWORD i;
203 DINITCODE("KickMemList 0x%p, NumEntries: %u", ml->ml_NumEntries);
204 for (i = 0; i < ml->ml_NumEntries; i++)
206 DINITCODE(" + Addr 0x%p, Len %u", ml->ml_ME[i].me_Addr, ml->ml_ME[i].me_Length);
209 * Use the non-Munwalling AllocAbs, since regions may be consecutive.
210 * Mungwall headers can trash them in this case.
212 if (!InternalAllocAbs(ml->ml_ME[i].me_Addr, ml->ml_ME[i].me_Length, SysBase))
214 DINITCODE("KickMem allocation failed");
215 /* Should we free already allocated KickMem lists? */
216 return;
219 ml = (struct MemList*)ml->ml_Node.ln_Succ;
222 if (SysBase->KickTagPtr)
224 AddToResidentList(SysBase->KickTagPtr);