2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
5 Desc: Amiga bootloader -- main file
10 * Note: This whole thing may seem a bit kludgy. It is. It was originally
11 * designed to load only one module. It has been extended to read a config
12 * file and to load multiple modules. It needs some polishing.
15 #include <exec/types.h>
16 #include <exec/execbase.h>
17 #include <exec/nodes.h>
18 #include <exec/resident.h>
19 #include <exec/memory.h>
21 #include <dos/rdargs.h>
23 #include <proto/dos.h>
24 #include <proto/exec.h>
25 #include <proto/alib.h>
32 #define D(x) if (debug) x
35 struct SpecialResident
43 #define SR_COOKIE 0x4afa4afb
45 struct Module
*LoadModule(char *);
46 void FreeModules(struct ModuleList
*);
47 BOOL
BuildTagPtrs(struct ModuleList
*);
48 ULONG
*AllocMoveCookie(ULONG
*, ULONG
);
49 struct MemList
*BuildMemList(struct ilsMemList
*, ULONG
*, ULONG
);
50 void StuffTags(struct MemList
*, ULONG
*, ULONG
);
51 void *FindResMod(struct ilsMemList
*);
52 void PrintTagPtrs(void);
53 void FreeRDArgsAll(struct RDArgs
*);
54 void PatchModule(struct Module
*, struct List
*);
56 char *version
= "$VER: " BANNER
" " VERSIONSTRING
" " DATE
;
62 struct ilsMemList ils_mem
;
64 char cmlargs
[] = "CONFIGFILE,CHIP/S,FAST/S,KICK/S,LOCAL/S,CLEAR/S,CO=CLEARONLY/S,RESET/S,DEBUG/S,SIM=SIMULATE/S,FORCE/S,QUIET/S";
67 "Configfile : config file to use, default is \"arosboot.config\"\n"
68 "Chip : force modules to chip mem\n"
69 "Fast : force modules to fast mem\n"
70 "Kick : force modules to kick mem\n"
71 "Local : force modules to local mem\n"
72 "Clear : clear reset vectors before installing new modules\n"
73 "Clearonly : only clear reset vectors and exit\n"
74 "Reset : reset after installing new modules\n"
75 "Debug : output debugging information\n"
76 "Simulate : Simulate loading, do not actually install modules\n"
77 "Force : Force loading if modules were already loaded\n"
78 "Quiet : Be quiet [debug mode will override this]\n"
80 "Order of precedence of memory: kick->local->fast->chip\n"
84 #define CML_CONFIGFILE 0
90 #define CML_CLEARONLY 6
93 #define CML_SIMULATE 9
112 name: dc.b 'arosboot.cookie',0
113 id: dc.b 'arosboot.cookie 41.1 (22.3.1997)',0
119 Relocate this by adding a field's contents to its address.
120 rt_MatchTag also contains a (negative) offset, but unsigned pointers
121 won't handle it correctly. Just set it to the base address.
123 ULONG rescookie
[] = {
124 0x4AFCFFFF, 0xFFFE0000, 0x004A0029, 0x00880000,
125 0x000C0000, 0x00180000, 0x00366172, 0x6F73626F,
126 0x6F742E63, 0x6F6F6B69, 0x65006172, 0x6F73626F,
127 0x6F742E63, 0x6F6F6B69, 0x65203431, 0x2E312028,
128 0x32322E33, 0x2E313939, 0x37290000, 0x70004E75
131 int main(int argc
, char **argv
)
133 struct BootConfig
*config
;
134 struct ModNode
*modnode
;
135 struct Module
*module
;
137 struct RDArgs
*rdargs
;
138 int returnvalue
= RETURN_OK
;
139 BPTR oldcurrentdir
, programdir
;
140 struct ModuleList ModuleList
;
141 BOOL reset
, simulate
, force
;
143 debug
= quiet
= reset
= simulate
= force
= FALSE
;
145 if(SysBase
->LibNode
.lib_Version
< 37)
147 PutStr("This program is for AmigaOS 2.04 (V37) and higher.\n\n");
151 if(!(SysBase
->AttnFlags
& AFF_68020
))
153 PutStr("The current AROS for 68k Amigas requires a 68020 or higher processor.\n\n");
158 * The memory type MEMF_KICK has been added in V39 exec. Fall back to
159 * MEMF_CHIP if we are on an earlier version.
161 if(SysBase
->LibNode
.lib_Version
< 39)
169 if( (rdargs
= AllocDosObject(DOS_RDARGS
, NULL
)))
171 /* set default config file name */
172 cmdvec
[CML_CONFIGFILE
] = (LONG
)"arosboot.config";
174 rdargs
->RDA_ExtHelp
= usage
; /* FIX: why doesn't this work? */
175 rdargs
->RDA_Buffer
= NULL
;
176 rdargs
->RDA_BufSiz
= 0;
178 if(!(ReadArgs(cmlargs
, cmdvec
, rdargs
)))
180 PrintFault(IoErr(), "arosboot");
181 FreeDosObject(DOS_RDARGS
, rdargs
);
188 PrintFault(ERROR_NO_FREE_STORE
, "arosboot");
192 if(SetSignal(0L,SIGBREAKF_CTRL_C
) & SIGBREAKF_CTRL_C
)
194 FreeRDArgsAll(rdargs
);
195 PutStr("***Break\n");
199 if(cmdvec
[CML_FORCE
]) force
= TRUE
;
200 if(cmdvec
[CML_RESET
]) reset
= TRUE
;
201 if(cmdvec
[CML_QUIET
]) quiet
= TRUE
;
202 if(cmdvec
[CML_DEBUG
])
207 if(cmdvec
[CML_SIMULATE
]) simulate
= TRUE
;
209 if(!quiet
) PutStr("\n" BANNER
" " VERSIONSTRING
"\n\n");
211 /* Order of precedence: kick->local->fast->chip */
212 if (cmdvec
[CML_KICK
]) memtype
= MEMF_KICK
;
213 else if(cmdvec
[CML_LOCAL
]) memtype
= MEMF_LOCAL
;
214 else if(cmdvec
[CML_FAST
]) memtype
= MEMF_FAST
;
215 else if(cmdvec
[CML_CHIP
]) memtype
= MEMF_CHIP
;
217 if(cmdvec
[CML_CLEARONLY
])
219 if(!quiet
) PutStr("Clearing reset vectors.\n");
220 SysBase
->KickMemPtr
= NULL
;
221 SysBase
->KickTagPtr
= NULL
;
222 SysBase
->KickCheckSum
= NULL
;
223 FreeRDArgsAll(rdargs
);
226 if(!quiet
) PutStr("Resetting this machine in about 5 seconds...\n");
228 ColdReboot(); /* never returns */
232 else if(cmdvec
[CML_CLEAR
]) /* no need to clear again if already done */
234 if(!quiet
) PutStr("Clearing reset vectors.\n");
235 SysBase
->KickMemPtr
= NULL
;
236 SysBase
->KickTagPtr
= NULL
;
237 SysBase
->KickCheckSum
= NULL
;
240 D(bug("Debug mode\n"));
242 if(!quiet
) PrintTagPtrs();
245 * InternalLoadSeg use.
247 ils_table
[0] = (ULONG
)&ils_read
;
248 ils_table
[1] = (ULONG
)&ils_alloc
;
249 ils_table
[2] = (ULONG
)&ils_free
;
251 NewList((struct List
*)&ils_mem
);
253 if(SetSignal(0L,SIGBREAKF_CTRL_C
) & SIGBREAKF_CTRL_C
)
255 FreeRDArgsAll(rdargs
);
256 PutStr("***Break\n");
260 if( (FindResident("arosboot.cookie")))
266 PutStr("AROS modules already loaded."); /* A smart compiler merges strings */
267 PutStr(" Exiting.\n");
269 FreeRDArgsAll(rdargs
);
276 PutStr("AROS modules already loaded.");
277 PutStr(" Overriding.\n");
283 * First check if we actually have a program dir (aka PROGDIR:). If we
284 * don't have one, we're in the resident list (hey, you shouldn't put
285 * us there!), and we stay right in the dir we were started from.
287 if( (programdir
= GetProgramDir()))
289 oldcurrentdir
= CurrentDir(programdir
);
293 * Construct a List of filenames to process.
295 if(!(config
= ReadConfig((char *)cmdvec
[CML_CONFIGFILE
])))
297 /* ReadConfig() prints it's own error string, just exit. */
298 FreeRDArgsAll(rdargs
);
300 /* If we switched dirs, switch back. */
301 if(oldcurrentdir
) CurrentDir(oldcurrentdir
);
305 /* We no longer need them */
306 FreeRDArgsAll(rdargs
);
308 if(SetSignal(0L,SIGBREAKF_CTRL_C
) & SIGBREAKF_CTRL_C
)
311 if(oldcurrentdir
) CurrentDir(oldcurrentdir
);
312 PutStr("***Break\n");
316 if(!quiet
) PutStr("Loading modules ...\n");
318 NewList((struct List
*)&ModuleList
);
319 ModuleList
.ml_Num
= 0;
322 * Traverse this list and load the modules into memory.
324 for(modnode
= (struct ModNode
*)config
->bc_Modules
.lh_Head
;
325 modnode
->mn_Node
.ln_Succ
;
326 modnode
= (struct ModNode
*)modnode
->mn_Node
.ln_Succ
)
328 modname
= modnode
->mn_Node
.ln_Name
;
329 if( (module
= LoadModule(modnode
->mn_Node
.ln_Name
)) )
331 PatchModule(module
, &modnode
->mn_FuncList
);
332 AddTail((struct List
*)&ModuleList
, (struct Node
*)module
);
334 if(!quiet
) Printf("\t%s\n", (ULONG
)module
->m_Resident
->rt_IdString
);
338 modnode
= NULL
; /* on normal exit, this points to the last module processed */
344 * I duplicated a CTRL-C handler a few times, instead of making it a
345 * subroutine. Else all local variables used here would have to be passed
346 * to that subroutine. I should put common cleanup code into an atexit()
347 * handler. Oh well, maybe next time.
349 if(SetSignal(0L,SIGBREAKF_CTRL_C
) & SIGBREAKF_CTRL_C
)
352 if(oldcurrentdir
) CurrentDir(oldcurrentdir
);
353 PutStr("***Break\n");
362 * If we're here, all modules we're loaded normally. Build all
363 * structures needed for the KickTag/Mem fields, and put them there.
365 if( (BuildTagPtrs(&ModuleList
)) )
367 if(!quiet
& !reset
) PutStr("\nAll modules loaded successfully, reset to activate.\n\n");
368 else if(!quiet
& reset
) PutStr("\nAll modules loaded successfully.\n\n");
372 if(!quiet
) PutStr("\nError building KickTagPtrs!\n");
373 FreeModules(&ModuleList
);
374 returnvalue
= RETURN_FAIL
;
379 if(!quiet
) PutStr("Simulation complete, unloading modules.\n");
380 FreeModules(&ModuleList
);
381 returnvalue
= RETURN_OK
;
386 if(!quiet
) Printf("Error loading \"%s\"\n", (ULONG
)modname
);
387 FreeModules(&ModuleList
);
388 returnvalue
= RETURN_FAIL
;
395 if(!quiet
) PutStr("Resetting this machine in about 5 seconds...\n");
397 ColdReboot(); /* never returns */
400 /* If we switched dirs, switch back. */
401 if(oldcurrentdir
) CurrentDir(oldcurrentdir
);
406 struct Module
*LoadModule(char *filename
)
411 D(bug("LoadModule(\"%s\")\n", (ULONG
)filename
));
412 if(!(fh
= Open(filename
, MODE_OLDFILE
)))
414 if(!quiet
) PrintFault(IoErr(), filename
);
418 if(!(mod
= AllocVec(sizeof(struct Module
), MEMF_CLEAR
)))
420 if(!quiet
) PutStr("Could not allocate memory for module.\n");
424 D(bug(" module = $%08lx (size %ld)\n", (ULONG
)mod
, sizeof(struct Module
)));
426 if( (seglist
= InternalLoadSeg(fh
, NULL
, &ils_table
[0], &stack
)) )
428 mod
->m_SegList
= seglist
;
429 mod
->m_Resident
= FindResMod(&ils_mem
);
432 if( ((struct SpecialResident
*)mod
->m_Resident
)->magiccookie
== SR_COOKIE
)
433 Printf(" Module is of patchable type\n");
437 D(bug(" SegList = $%08lx\n", BADDR(mod
->m_SegList
)));
438 D(bug(" Resident = $%08lx\n", (ULONG
)mod
->m_Resident
));
441 * If this module contains a Resident structure, return it.
443 if ( (mod
->m_Resident
))
451 void FreeModules(struct ModuleList
*modlist
)
453 struct Module
*mod
, *next
;
455 D(bug("FreeModules($%08lx)\n", (ULONG
)modlist
));
457 for(mod
= (struct Module
*)modlist
->ml_List
.mlh_Head
; mod
->m_Node
.mln_Succ
; mod
= next
)
459 /* get next node here, because after the Remove() it is undefined */
460 next
= (struct Module
*)mod
->m_Node
.mln_Succ
;
461 Remove((struct Node
*)mod
);
462 InternalUnLoadSeg(mod
->m_SegList
, &ils_free
);
467 BOOL
BuildTagPtrs(struct ModuleList
*modlist
)
469 struct MemList
*memlist
;
474 struct ilsMemNode
*cookienode
;
476 D(bug("BuildTagPtrs...\n"));
479 * Allocate memory for our KickTagPtr table:
480 * number of modules loaded +2 (cookie and table terminator)
482 D(bug("Allocating KickTagPtr memory (size %ld)\n", (modlist
->ml_Num
+2)*sizeof(ULONG
)));
483 if( (modarray
= AllocVec((modlist
->ml_Num
+2)*sizeof(ULONG
),
484 memtype
|MEMF_CLEAR
|MEMF_REVERSE
)) )
488 * Fill the KickTagPtr array with pointers to our Resident modules.
490 for(i
= 0, mod
= (struct Module
*)modlist
->ml_List
.mlh_Head
;
491 mod
->m_Node
.mln_Succ
;
492 mod
= (struct Module
*)mod
->m_Node
.mln_Succ
, i
++)
494 D(bug(" modarray[%ld] = $%lx (module)\n", i
, (ULONG
)mod
->m_Resident
));
495 modarray
[i
] = (ULONG
)mod
->m_Resident
;
497 /* i will be incremented one last time before exiting */
499 if( (cookieptr
= AllocMoveCookie(rescookie
, sizeof(rescookie
))))
502 * Add the cookie module.
504 D(bug(" modarray[%ld] = $%lx (cookie)\n", i
, (ULONG
)cookieptr
));
505 modarray
[i
] = (ULONG
)cookieptr
;
508 * Terminate the module array.
510 D(bug(" modarray[%ld] = $%lx (termination)\n", i
+1, (ULONG
)NULL
));
511 modarray
[i
+1] = NULL
;
514 * Add the cookie's memory address + size on the memlist.
516 if( (cookienode
= AllocMem(sizeof(struct ilsMemNode
), MEMF_CLEAR
)) )
518 cookienode
->imn_Addr
= cookieptr
;
519 cookienode
->imn_Size
= sizeof(rescookie
);
520 AddHead((struct List
*)&ils_mem
, (struct Node
*)cookienode
);
522 ils_mem
.iml_NewNum
++;
525 * Cache number of modules, since it will be modified in
526 * BuildMemList. +1 because of the cookie.
528 nummods
= modlist
->ml_Num
+ 1;
531 * build a memlist to be put in KickMemPtr
533 if( (memlist
= BuildMemList(&ils_mem
, modarray
,
534 (modlist
->ml_Num
+2)*sizeof(ULONG
) )) )
536 StuffTags(memlist
, modarray
, nummods
);
541 /* If we get here, something went wrong. Free stuff. */
542 FreeMem(cookieptr
, sizeof(rescookie
));
549 ULONG
*AllocMoveCookie(ULONG
*cookie
, ULONG size
)
551 struct Resident
*res
;
553 D(bug("AllocMoveCookie()\n"));
555 if( (res
= AllocMem(size
, memtype
|MEMF_REVERSE
)))
557 D(bug(" Moving cookie\n"));
558 /* Relocate the cookie. */
559 CopyMem(cookie
, (APTR
)res
, size
);
561 D(bug(" Relocating cookie pointers\n"));
562 /* Relocate pointers in cookie. */
563 res
->rt_MatchTag
= res
;
564 res
->rt_EndSkip
+= (ULONG
)&res
->rt_EndSkip
;
565 res
->rt_Name
+= (ULONG
)&res
->rt_Name
;
566 res
->rt_IdString
+= (ULONG
)&res
->rt_IdString
;
567 res
->rt_Init
+= (ULONG
)&res
->rt_Init
;
569 D(bug(" cookie @ $%lx, name @ $%lx, idstring @ $%lx\n",
570 (ULONG
)res
, (ULONG
)res
->rt_Name
, (ULONG
)res
->rt_IdString
));
572 if(!quiet
) Printf("\t%s\n", (ULONG
)res
->rt_IdString
);
580 struct MemList
*BuildMemList(struct ilsMemList
*prelist
,
584 struct MemList
*memlist
;
586 struct ilsMemNode
*node
;
590 D(bug("BuildMemList()\n"));
592 * Calculate needed number of extra MemEntry fields that need to be
593 * appended to the end of our MemList structure. This number+1 (there
594 * already is one MemEntry in the MemList) is what we'll be putting in
595 * memlist->ml_NumEntries later.
597 numentries
= prelist
->iml_Num
+ 1;
598 D(bug(" number of mem areas = %ld\n", numentries
+1));
600 size
= ( sizeof(struct MemList
) + (sizeof(struct MemEntry
) * numentries
) );
603 * Allocate memory from the top of the memory list, to keep fragmentation
604 * down, and hopefully to keep all our applications in one place.
606 if(!(memlist
= AllocVec(size
, memtype
|MEMF_CLEAR
|MEMF_REVERSE
))) return(NULL
);
609 * We have the memory. Assure that this MemList is allocated during a
610 * reset, and put it in the first MemEntry field.
612 memlist
->ml_ME
[0].me_Addr
= memlist
;
613 memlist
->ml_ME
[0].me_Length
= size
;
616 * Indicate that this node is part of a KickMem MemList, and indicate how
617 * many MemEntries there are.
619 memlist
->ml_Node
.ln_Type
= NT_KICKMEM
;
620 memlist
->ml_NumEntries
= numentries
+1;
623 * Put the modlist in the next MemEntry.
625 me
= (struct MemEntry
*)( ((ULONG
)memlist
) + sizeof(struct MemList
) );
626 me
->me_Addr
= modlist
;
627 me
->me_Length
= modlistsize
;
630 * Increase to the next MemEntry.
632 me
= (struct MemEntry
*)( ((ULONG
)me
) + sizeof(struct MemEntry
) );
635 * Now put the data from our prelist in the remaining MemEntry fields,
636 * removing the nodes in our prelist and freeing them in the process.
638 while(prelist
->iml_Num
)
641 * pop a node off the list
643 node
= (struct ilsMemNode
*)RemHead((struct List
*)prelist
);
645 me
->me_Addr
= node
->imn_Addr
;
646 me
->me_Length
= node
->imn_Size
;
648 FreeMem(node
, sizeof(struct ilsMemNode
));
651 * Point to the next MemEntry, decrease our counter.
653 me
= (struct MemEntry
*)(((ULONG
)me
) + sizeof(struct MemEntry
));
660 void StuffTags(struct MemList
*memlist
, ULONG
*modlist
, ULONG nummods
)
662 D(bug("StuffTags(memlist $%08lx modlist $%08lx nummods %ld)\n",
663 (ULONG
)memlist
, (ULONG
)modlist
, nummods
));
667 if(SysBase
->KickCheckSum
!= (APTR
)SumKickData())
669 /* Vectors had incorrect checksum. Just clear them now. */
670 D(bug("Vectors had incorrect checksum. Clearing before loading.\n"));
671 SysBase
->KickTagPtr
= SysBase
->KickMemPtr
= SysBase
->KickCheckSum
= NULL
;
674 if(SysBase
->KickMemPtr
)
677 * Prepend to an existing chain of MemLists.
679 D(bug("Prepending to existing memlist (old ptr = $%lx)\n", (ULONG
)SysBase
->KickMemPtr
));
680 memlist
->ml_Node
.ln_Succ
= SysBase
->KickMemPtr
;
682 SysBase
->KickMemPtr
= memlist
;
684 if(SysBase
->KickTagPtr
)
687 * Prepend to an existing chain of module lists.
689 D(bug("Prepending to existing tagptr (old ptr = $%lx)\n", (ULONG
)SysBase
->KickTagPtr
));
690 modlist
[nummods
] = (ULONG
)SysBase
->KickTagPtr
| 0x80000000;
692 SysBase
->KickTagPtr
= modlist
;
695 * And checksum the KickPtrs. KickCheckSum is defined wrong in the include
696 * file exec/execbase.h. It is defined as APTR, but really is a ULONG.
698 SysBase
->KickCheckSum
= (APTR
)SumKickData();
708 void *FindResMod(struct ilsMemList
*list
)
710 struct ilsMemNode
*node
;
714 D(bug("Finding Resident Module..."));
717 * Search all memory blocks for the Resident struct. Only new nodes
720 for(node
= (struct ilsMemNode
*)ils_mem
.iml_List
.mlh_Head
, num
= ils_mem
.iml_NewNum
;
721 node
->imn_Node
.mln_Succ
|| num
;
722 node
= (struct ilsMemNode
*)node
->imn_Node
.mln_Succ
, num
--)
725 * In each block: skip to the magic word, if present.
726 * Searching by word: divide by 2
728 counter
= node
->imn_Size
/2;
730 for(ptr
= node
->imn_Addr
; counter
; ptr
++, counter
--)
732 if(RTC_MATCHWORD
== *ptr
)
735 * Reset the counter, so that next time only new nodes will
738 ils_mem
.iml_NewNum
= 0;
740 D(bug(" at $%08lx\n", (ULONG
)ptr
));
746 D(bug(" not found\n"));
750 void PrintTagPtrs(void)
752 if(SumKickData() == (ULONG
)SysBase
->KickCheckSum
)
754 if(SysBase
->KickTagPtr
)
758 PutStr("Modules already in use:\n");
760 list
= SysBase
->KickTagPtr
;
764 Printf("\t$%08lx", *list
);
765 Printf("\t%s\n", (ULONG
)((struct Resident
*)*list
)->rt_IdString
);
768 if(*list
& 0x80000000) list
= (ULONG
*)(*list
& 0x7fffffff);
774 /* Don't print message if all vectors are NULL */
775 if(SysBase
->KickMemPtr
|| SysBase
->KickTagPtr
|| SysBase
->KickCheckSum
)
776 Printf("Vectors have incorrect checksum.\n");
780 void FreeRDArgsAll(struct RDArgs
*rdargs
)
783 FreeDosObject(DOS_RDARGS
, rdargs
);
786 /* Turn functions on/off in module according to the function slots in funclist */
787 void PatchModule(struct Module
*module
, struct List
*funclist
)
789 struct FuncNode
*funcnode
;
793 if( ((struct SpecialResident
*)module
->m_Resident
)->magiccookie
== SR_COOKIE
)
795 /* ok, cookie found, let's patch this module */
797 array
= ((struct SpecialResident
*)module
->m_Resident
)->statusarray
;
798 maxslot
= ((struct SpecialResident
*)module
->m_Resident
)->maxslot
;
800 for(funcnode
= (struct FuncNode
*)funclist
->lh_Head
;
801 funcnode
->fn_Node
.ln_Succ
;
802 funcnode
= (struct FuncNode
*)funcnode
->fn_Node
.ln_Succ
)
804 /* walk function list, (un)setting entries in array */
806 /* Check if in range of library, do not touch first 4 vectors */
807 if(funcnode
->fn_Slot
<= maxslot
&& funcnode
->fn_Slot
> 4)
809 D(bug("Setting function %ld (slot %ld) %s\n",
810 funcnode
->fn_Slot
* -6,
812 funcnode
->fn_Status
? (ULONG
)"on" : (ULONG
)"off"
815 array
[funcnode
->fn_Slot
] = funcnode
->fn_Status
? 1 : 0;
820 Printf("Function %ld (slot %ld) outside scope of module (max %ld, %ld). Ignored.\n",
821 funcnode
->fn_Slot
* -6,