2 * Copyright (C) 2011-2018, The AROS Development Team. All rights reserved.
4 * Licensed under the AROS PUBLIC LICENSE (APL) Version 1.1
7 /* This loads relocatable AROS ROM ELF images, and gzipped
8 * image. Use either the aros-amiga-m68k-reloc.elf or
9 * aros.elf.gz images. The fully linked aros-amiga-m68k.elf
10 * image cannot be loaded by this application.
12 * As you can probably guess, you will need at least 1MB of
13 * extra free RAM to get this to work.
15 * Also - no AROS specific code can go in here! We have to run
20 #include <proto/exec.h>
21 #include <proto/graphics.h>
22 #include <proto/dos.h>
23 #include <proto/expansion.h>
24 #include <exec/resident.h>
25 #include <aros/kernel.h>
26 #include <hardware/cpu/memory.h>
27 #include <libraries/configvars.h>
29 /* This much memory is wasted in single reset proof allocation */
30 #define ALLOCATION_EXTRA (sizeof(struct MemChunk))
31 #define ALLOCPADDING (sizeof(struct MemChunk) + 2 * sizeof(BPTR))
33 #define KERNELTAGS_TOTAL 16
34 #define CMDLINE_SIZE 512
36 #define SS_STACK_SIZE 0x2000
37 #define MAGIC_FAST_SIZE 65536
39 /* This structure must match with start.c! */
40 #define ABS_BOOT_MAGIC 0x4d363802
44 struct ExecBase
*RealBase
;
45 struct ExecBase
*RealBase2
;
47 struct TagItem
*kerneltags
;
48 struct Resident
**reslist
;
49 struct ExecBase
*FakeBase
;
54 LONG magicfastmemsize
;
57 #define BMC_NAME_SIZE 14
60 /* MemList must be first */
63 UBYTE name
[BMC_NAME_SIZE
];
71 struct BootStruct boots
;
73 struct Resident
*res
[RES_MAX
];
74 struct ExecBase FakeBase
;
75 UBYTE bootcode
[BOOTCODE
];
77 struct TagItem ktags
[KERNELTAGS_TOTAL
];
78 UBYTE kcmd
[CMDLINE_SIZE
];
80 struct BootMemChunk bmc
[BMC_MAX
];
83 #include <stddef.h> /* offsetof */
84 #include <string.h> /* memcpy, memset */
87 #if defined(DEBUG) && DEBUG > 1
88 #define DEFAULT_KERNEL_CMDLINE "sysdebug=InitCode mungwall"
90 #define DEFAULT_KERNEL_CMDLINE "sysdebug=InitCode"
93 #define PROTO_KERNEL_H /* Don't pick up AROS kernel hooks */
99 static inline void bug(const char *fmt
, ...)
101 static char buff
[256];
105 vsnprintf(buff
, sizeof(buff
), fmt
, args
);
108 Write(Output(), buff
, strlen(buff
));
117 struct ExecBase
*SysBase
;
118 struct DosLibrary
*DOSBase
;
119 struct Library
*ExpansionBase
;
121 static BOOL ROM_Loaded
= FALSE
;
122 static BOOL forceAROS
= FALSE
;
123 static BOOL forceCHIP
= FALSE
;
124 static BOOL forceFAST
= FALSE
;
125 static BOOL debug_enabled
= FALSE
;
127 static struct BootMemHeader
*bmh
;
129 /* KS 1.3 (and earlier) don't have a dos.library with
130 * niceties such as VFPrintf nor ReadArgs.
132 * We need to use the BCPL routines to be able
133 * to do these types of operations.
135 #define BCPL_WriteS 73
136 #define BCPL_WriteF 74
137 #define BCPL_RdArgs 78
140 #define Printf __Printf_NOT_AVAILABLE_UNDER_KS1_3
142 #define ReadArgs __ReadArgs_NOT_AVAILABLE_UNDER_KS1_3
144 /* BCPL can trash D5-D7 and A3, evidently.
146 static void bcplWrapper(void)
149 "movem.l %d5-%d7/%a3,%sp@-\n"
151 "movem.l %sp@+,%d5-%d7/%a3\n"
155 static ULONG
doBCPL(int index
, ULONG d1
, ULONG d2
, ULONG d3
, ULONG d4
, const IPTR
*arg
, int args
)
157 struct Process
*pr
= (APTR
)FindTask(NULL
);
159 ULONG
*gv
= pr
->pr_GlobVec
;
161 ULONG
*BCPL_frame
= AllocMem(1500, MEMF_ANY
);
162 if (BCPL_frame
== NULL
)
165 func
= (APTR
)gv
[index
];
168 CopyMem(arg
, &BCPL_frame
[3 + 4], args
* sizeof(ULONG
));
170 ret
= AROS_UFC11(ULONG
, bcplWrapper
,
171 AROS_UFCA(ULONG
, 0, D0
), /* BCPL frame usage (args-3)*/
172 AROS_UFCA(ULONG
, d1
, D1
),
173 AROS_UFCA(ULONG
, d2
, D2
),
174 AROS_UFCA(ULONG
, d3
, D3
),
175 AROS_UFCA(ULONG
, d4
, D4
),
176 AROS_UFCA(ULONG
, 0, A0
), /* System memory base */
177 AROS_UFCA(ULONG
*, &BCPL_frame
[3], A1
),
178 AROS_UFCA(APTR
, gv
, A2
),
179 AROS_UFCA(APTR
, func
, A4
),
180 AROS_UFCA(APTR
, DOSBase
->dl_A5
, A5
),
181 AROS_UFCA(APTR
, DOSBase
->dl_A6
, A6
));
183 FreeMem(BCPL_frame
, 1500);
189 static BSTR
ConvertCSTR(const UBYTE
*name
)
191 UBYTE
*bname
= AllocMem(256 + 1, MEMF_CLEAR
);
192 UWORD len
= strlen(name
), i
;
197 strcpy(bname
+ 1, name
);
198 for (i
= 0; i
< len
; i
++) {
199 if (bname
[1 + i
] == 13 || bname
[1 + i
] == 10)
202 return MKBADDR(bname
);
204 static void FreeBSTR(BSTR bstr
)
206 FreeMem(BADDR(bstr
), 256 + 1);
210 static UBYTE
*ConvertBSTR(BSTR bname
)
212 UBYTE
*name
= BADDR(bname
);
213 UBYTE
*s
= AllocMem(256 + 1, MEMF_CLEAR
);
216 CopyMem(name
+ 1, s
, name
[0]);
220 static void FreeString(UBYTE
*cstr
)
222 FreeMem(cstr
, 256+1);
225 static void _WriteF(BPTR bfmt
, ...)
227 IPTR
*args
= (IPTR
*)&bfmt
;
229 doBCPL(BCPL_WriteF
, bfmt
, args
[1], args
[2], args
[3], &args
[4], 26-3);
233 static void _DWriteF(BPTR bfmt
, ...)
235 if (debug_enabled
|| DEBUG
> 1) {
236 IPTR
*args
= (IPTR
*)&bfmt
;
238 doBCPL(BCPL_WriteF
, bfmt
, args
[1], args
[2], args
[3], &args
[4], 26-3);
241 #define DWriteF(fmt, args...) _DWriteF(AROS_CONST_BSTR(fmt) ,##args )
244 #define WriteF(fmt, args...) _WriteF(AROS_CONST_BSTR(fmt) ,##args )
246 /* For KS < 2.0, we need to call the BCPL ReadArgs,
247 * since DOS/ReadArgs doesn't exist.
249 static ULONG
RdArgs(BSTR format
, BPTR args
, ULONG max_arg
)
251 return doBCPL(BCPL_RdArgs
, format
, args
, max_arg
, 0, NULL
, 0);
256 struct MemHeader
*mh
;
257 ForeachNode(&SysBase
->MemList
, mh
) {
259 bstr
[0] = strlen(mh
->mh_Node
.ln_Name
) & 0xff;
260 strncpy(&bstr
[1], mh
->mh_Node
.ln_Name
, bstr
[0]);
261 WriteF("@$%X8-$%X8 ATTR $%X4 FREE $%X8 (%S)\n",
262 mh
->mh_Lower
, mh
->mh_Upper
, mh
->mh_Attributes
,
263 mh
->mh_Free
, MKBADDR(bstr
));
267 /* Allocate MMU page aligned memory chunks */
269 static APTR
AllocPageAligned(ULONG
*psize
, ULONG flags
)
275 size
+= ALLOCPADDING
;
276 ret
= AllocMem(size
+ 2 * PAGE_SIZE
, flags
);
277 D(DWriteF("AllocPageAligned: $%X8, %X4 => %X8\n", size
+ 2 * PAGE_SIZE
, flags
, ret
));
281 FreeMem(ret
, size
+ 2 * PAGE_SIZE
);
282 size
= (size
+ PAGE_SIZE
- 1) & PAGE_MASK
;
283 ret
= AllocAbs(size
, (APTR
)(((((ULONG
)ret
) + PAGE_SIZE
- 1) & PAGE_MASK
)));
290 static void FreePageAligned(APTR addr
, ULONG size
)
292 FreeMem(addr
, (size
+ PAGE_SIZE
- 1) & PAGE_MASK
);
295 static BYTE
getNodePri(APTR mem
, ULONG flags
)
298 if (flags
== 0xffffffff)
300 if (flags
& MEMF_CHIP
)
302 if (flags
& MEMF_KICK
)
304 /* Check also addresses, some boards may lie */
306 if ((ULONG
)mem
>= 0x00200000 && (ULONG
)mem
< 0x00a00000)
309 if ((ULONG
)mem
>= 0x10000000)
314 static BOOL
addMemList(UBYTE
*mem
, ULONG size
, ULONG flags
, const char *name
, BOOL resscan
)
317 struct BootMemChunk
*bmc
= NULL
;
320 D(WriteF("AddMemList %X8 %N\n", mem
, size
));
321 for (i
= 0; i
< BMC_MAX
; i
++) {
327 D(WriteF("All MemList slots in use!\n"));
332 ml
->ml_Node
.ln_Type
= resscan
? NT_KICKMEM
: NT_MEMORY
;
333 ml
->ml_Node
.ln_Pri
= getNodePri(mem
, flags
);
335 ml
->ml_Node
.ln_Name
= bmc
->name
;
336 if (strlen(name
) >= BMC_NAME_SIZE
)
337 memcpy(ml
->ml_Node
.ln_Name
, name
, BMC_NAME_SIZE
- 1);
339 strcpy(ml
->ml_Node
.ln_Name
, name
);
341 ml
->ml_NumEntries
= 1;
342 ml
->ml_ME
[0].me_Addr
= (APTR
)mem
;
343 ml
->ml_ME
[0].me_Length
= size
;
344 Enqueue(&bmh
->mlist
, &ml
->ml_Node
);
348 static void remMemList(UBYTE
*mem
)
352 D(DWriteF("RemMemList %X8\n", mem
));
353 for (i
= 0; i
< BMC_MAX
; i
++) {
354 struct BootMemChunk
*bmc
= &bmh
->bmc
[i
];
355 if (bmc
->inuse
&& bmc
->ml
.ml_ME
[0].me_Addr
== mem
) {
357 Remove(&bmc
->ml
.ml_Node
);
361 D(DWriteF("MemList slot not found!\n"));
364 static struct Resident
*scanResidents(UBYTE
*mem
, ULONG size
, BOOL loadseg
)
366 struct Resident
**resptr
= NULL
;
367 struct Resident
*firstres
= NULL
;
369 UBYTE
*end
= mem
+ size
;
373 D(WriteF("ScanResident %X8 %N\n", mem
, size
));
374 for (i
= 0; i
< RES_MAX
- 1; i
++) {
375 if (bmh
->res
[i
] == NULL
) {
376 resptr
= &bmh
->res
[i
];
381 D(WriteF("All Resident slots in use!\n"));
384 while (ptr
<= end
- 26) {
385 struct Resident
*r
= (struct Resident
*)ptr
;
386 if (r
->rt_MatchWord
== RTC_MATCHWORD
&& r
->rt_MatchTag
== r
) {
387 resptr
[rescnt
++] = r
;
391 /* Set RTF_COLDSTART if no initialization flags set */
392 if (!(r
->rt_Flags
& (RTF_COLDSTART
| RTF_SINGLETASK
| RTF_AFTERDOS
)))
393 r
->rt_Flags
|= RTF_COLDSTART
;
398 if ((IPTR
)r
->rt_EndSkip
> (IPTR
)ptr
)
399 ptr
= (UBYTE
*)r
->rt_EndSkip
- sizeof(UWORD
);
401 ptr
+= sizeof(UWORD
);
403 D(WriteF("%N residents found, start address %X8\n", rescnt
, resptr
));
407 static void scanMemLists(void)
410 struct BootMemChunk
*bmc
;
412 D(WriteF("Scanning for residents..\n"));
413 bmc
= (struct BootMemChunk
*)bmh
->mlist
.lh_Head
;
414 while (bmc
->ml
.ml_Node
.ln_Succ
) {
415 struct MemList
*ml
= &bmc
->ml
;
416 if (ml
->ml_Node
.ln_Type
== NT_KICKMEM
) {
417 ml
->ml_Node
.ln_Type
= NT_MEMORY
;
418 for (i
= 0; i
< ml
->ml_NumEntries
; i
++) {
419 if (scanResidents(ml
->ml_ME
[i
].me_Addr
, ml
->ml_ME
[i
].me_Length
, FALSE
)) {
420 // Can be MMU write protected
421 ml
->ml_Node
.ln_Type
= NT_KICKMEM
;
425 bmc
= (struct BootMemChunk
*)bmc
->ml
.ml_Node
.ln_Succ
;
429 static BOOL
initDataPool(void)
437 size
= 2 * PAGE_SIZE
+ ((sizeof(struct BootMemHeader
) + PAGE_SIZE
- 1) & ~PAGE_SIZE
);
438 /* Always in Chip RAM */
439 flags
= MEMF_CHIP
| (SysBase
->LibNode
.lib_Version
>= 36 ? MEMF_REVERSE
: 0) | MEMF_CLEAR
;
440 start
= AllocPageAligned (&size
, flags
);
443 D(DWriteF("BootMemHeader allocated at %X8\n", start
));
444 /* Fill with identifier strings. */
446 for (i
= 0; i
< PAGE_SIZE
/ 4; i
++)
448 p
= (ULONG
*)(start
+ size
- PAGE_SIZE
);
449 for (i
= 0; i
< PAGE_SIZE
/ 4; i
++)
451 bmh
= (struct BootMemHeader
*)(start
+ PAGE_SIZE
);
452 /* Initialize Memory List */
453 NEWLIST(&bmh
->mlist
);
454 /* Add our memory to list, highest priority */
455 addMemList(start
, size
, 0xffffffff, "pool", FALSE
);
459 /* Define these here for zlib so that we don't
460 * pull in stdc.library.
462 * We can't use AllocVec, since it's only
463 * been around since KS v36
465 void *malloc(int size
)
469 size
+= sizeof(ULONG
);
471 vec
= AllocMem(size
, MEMF_ANY
);
473 WriteF("libz: Failed to allocate %N bytes of type %X8\n", size
, MEMF_ANY
);
477 vec
[0] = (ULONG
)size
;
483 ULONG
*vec
= ptr
- sizeof(ULONG
);
484 FreeMem(vec
, vec
[0]);
487 int open(const char *name
, int mode
)
489 return (int)Open(name
, MODE_OLDFILE
);
498 ssize_t
read(int fd
, void *buff
, size_t len
)
500 return Read((BPTR
)fd
, buff
, (LONG
)len
);
503 off_t
lseek(int fd
, off_t offset
, int whence
)
505 LONG mode
= SEEK_SET
;
509 case SEEK_CUR
: mode
= OFFSET_CURRENT
; break;
510 case SEEK_SET
: mode
= OFFSET_BEGINNING
; break;
511 case SEEK_END
: mode
= OFFSET_END
; break;
515 err
= Seek((BPTR
)fd
, (LONG
)offset
, mode
);
519 return Seek((BPTR
)fd
, 0, OFFSET_CURRENT
);
522 static AROS_UFH4(LONG
, aosRead
,
523 AROS_UFHA(BPTR
, file
, D1
),
524 AROS_UFHA(void *, buf
, D2
),
525 AROS_UFHA(LONG
, size
, D3
),
526 AROS_UFHA(struct DosLibrary
*, DOSBase
, A6
))
530 return Read(file
, buf
, (unsigned)size
);
534 static AROS_UFH4(LONG
, aosSeek
,
535 AROS_UFHA(BPTR
, file
, D1
),
536 AROS_UFHA(LONG
, pos
, D2
),
537 AROS_UFHA(LONG
, mode
, D3
),
538 AROS_UFHA(struct DosLibrary
*, DOSBase
, A6
))
546 case OFFSET_CURRENT
: whence
= SEEK_CUR
; break;
547 case OFFSET_END
: whence
= SEEK_END
; break;
548 case OFFSET_BEGINNING
: whence
= SEEK_SET
; break;
552 oldpos
= (LONG
)Seek(file
, 0, SEEK_CUR
);
554 ret
= (LONG
)Seek(file
, (z_off_t
)pos
, whence
);
563 static APTR
aosAllocMem(ULONG size
, ULONG flags
, const char *name
, BOOL resscan
, struct ExecBase
*SysBase
)
567 /* Clear bits 15-0, we're setting memory class explicitly */
570 if (SysBase
->LibNode
.lib_Version
>= 36) {
571 flags
|= MEMF_LOCAL
| MEMF_REVERSE
;
576 size
+= 2 * ALLOCATION_EXTRA
;
577 mem
= AllocMem(size
, flags
| MEMF_CLEAR
);
579 WriteF("AOS: Failed to allocate %N bytes of type %X8\n", size
, flags
);
583 addMemList(mem
, size
, flags
, name
, resscan
);
584 return mem
+ ALLOCATION_EXTRA
;
587 static AROS_UFH3(APTR
, aosAlloc
,
588 AROS_UFHA(ULONG
, size
, D0
),
589 AROS_UFHA(ULONG
, flags
, D1
),
590 AROS_UFHA(struct ExecBase
*, SysBase
, A6
))
594 return aosAllocMem(size
, flags
, NULL
, FALSE
, SysBase
);
598 static AROS_UFH3(void, aosFree
,
599 AROS_UFHA(APTR
, addr
, A1
),
600 AROS_UFHA(ULONG
, size
, D0
),
601 AROS_UFHA(struct ExecBase
*, SysBase
, A6
))
605 addr
-= ALLOCATION_EXTRA
;
606 size
+= 2 * ALLOCATION_EXTRA
;
612 /* Backcalls for LoadSegment
613 * using the gzip backend.
615 static AROS_UFH4(LONG
, elfRead
,
616 AROS_UFHA(BPTR
, file
, D1
),
617 AROS_UFHA(void *, buf
, D2
),
618 AROS_UFHA(LONG
, size
, D3
),
619 AROS_UFHA(struct DosLibrary
*, DOSBase
, A6
))
623 return gzread((gzFile
)file
, buf
, (unsigned)size
);
627 static AROS_UFH4(LONG
, elfSeek
,
628 AROS_UFHA(BPTR
, file
, D1
),
629 AROS_UFHA(LONG
, pos
, D2
),
630 AROS_UFHA(LONG
, mode
, D3
),
631 AROS_UFHA(struct DosLibrary
*, DOSBase
, A6
))
639 case OFFSET_CURRENT
: whence
= SEEK_CUR
; break;
640 case OFFSET_END
: whence
= SEEK_END
; break;
641 case OFFSET_BEGINNING
: whence
= SEEK_SET
; break;
645 oldpos
= (LONG
)gzseek((gzFile
)file
, 0, SEEK_CUR
);
647 ret
= (LONG
)gzseek((gzFile
)file
, (z_off_t
)pos
, whence
);
656 static APTR
specialAlloc(ULONG size
, ULONG flags
, const char *name
, BOOL resscan
, struct ExecBase
*SysBase
)
660 D(DWriteF("ELF: Attempt to allocate %N bytes of type %X8\n", size
, flags
));
661 /* Since we don't know if we need to wrap the memory
662 * with the KickMem wrapper until after allocation,
663 * we always adjust the size as if we have to.
665 size
+= 2 * ALLOCATION_EXTRA
;
667 if (flags
& MEMF_KICK
) {
668 D(DWriteF("MEMF_KICK %N\n", size
));
672 /* Prefer MEMF_KICK | MEMF_FAST if available */
677 /* Hmm. MEMF_LOCAL is only available on v36 and later.
678 * Use MEMF_CHIP if we have to.
680 if (flags
& MEMF_LOCAL
) {
681 D(DWriteF("MEMF_LOCAL %N\n", size
));
683 flags
&= ~MEMF_LOCAL
;
684 } else if (SysBase
->LibNode
.lib_Version
< 36 || forceCHIP
) {
685 flags
&= ~MEMF_LOCAL
;
690 /* MEMF_31BIT is not available on AOS */
691 if ((flags
& MEMF_31BIT
)) {
692 flags
&= ~MEMF_31BIT
;
695 /* If ROM allocation, always allocate from top of memory if possible */
696 if ((flags
& MEMF_PUBLIC
) && SysBase
->LibNode
.lib_Version
>= 36) {
697 flags
|= MEMF_REVERSE
;
700 D(DWriteF("ELF: Attempt to allocate %N bytes of type %X8\n", size
, flags
));
701 mem
= AllocPageAligned(&size
, flags
| MEMF_CLEAR
);
703 if ((flags
& (MEMF_KICK
| MEMF_FAST
)) == (MEMF_KICK
| MEMF_FAST
)) {
704 /* Couldn't allocate MEMF_KICK | MEMF_FAST, fall back to any memory */
705 mem
= AllocPageAligned(&size
, (flags
& MEMF_REVERSE
) | MEMF_CLEAR
);
708 D(DWriteF("ELF: Failed to allocate %N bytes of type %X8\n", size
, flags
));
713 D(DWriteF("ELF: Got memory at %X8, size %N\n", (IPTR
)mem
, size
));
715 addMemList(mem
, size
, flags
, name
, resscan
);
716 return mem
+ ALLOCATION_EXTRA
;
719 static AROS_UFH3(APTR
, elfAlloc
,
720 AROS_UFHA(ULONG
, size
, D0
),
721 AROS_UFHA(ULONG
, flags
, D1
),
722 AROS_UFHA(struct ExecBase
*, SysBase
, A6
))
726 return specialAlloc(size
, flags
, NULL
, TRUE
, SysBase
);
731 static AROS_UFH3(void, elfFree
,
732 AROS_UFHA(APTR
, addr
, A1
),
733 AROS_UFHA(ULONG
, size
, D0
),
734 AROS_UFHA(struct ExecBase
*, SysBase
, A6
))
738 /* If not page aligned, and the offset from the page boundary
739 * is the sizeof(MemChunk) + sizeof(MemList) then we can assume
740 * that it was a KickTag protected allocation
742 D(DWriteF("ELF: Free memory at %X8, size %N\n", (IPTR
)addr
, size
));
743 addr
-= ALLOCATION_EXTRA
;
744 size
+= 2 * ALLOCATION_EXTRA
;
746 FreePageAligned(addr
, size
);
752 * This routine is called from within libloadseg.a's ELF loader.
753 * In dos.library it's responsible for collecting debug information from the loaded file.
754 * Here it does nothing (FIXME ???)
756 void register_elf(BPTR file
, BPTR hunks
, struct elfheader
*eh
, struct sheader
*sh
, struct DosLibrary
*DOSBase
)
760 void register_hunk(BPTR file
, BPTR hunks
, APTR header
, struct DosLibrary
*DOSBase
)
765 static BPTR
ROMLoad(BSTR bfilename
)
770 SIPTR funcarray
[] = {
776 filename
= ConvertBSTR(bfilename
);
780 WriteF("Loading '%S' into RAM...\n", bfilename
);
781 if ((gzf
= gzopen(filename
, "rb"))) {
782 gzbuffer(gzf
, 65536);
784 rom
= LoadSegment((BPTR
)gzf
, BNULL
, funcarray
, NULL
);
786 WriteF("'%S': Can't parse, error %N\n", bfilename
, IoErr());
791 WriteF("'%S': Can't open\n", bfilename
);
793 FreeString(filename
);
797 /* Patch "picasso96/<driver>.chip" -> "<driver>.chip" so that OpenLibrary() finds it */
798 static void RTGPatch(struct Resident
*r
, BPTR seg
)
800 BOOL patched
= FALSE
;
801 WORD len
= strlen(r
->rt_Name
);
802 const UBYTE
*name
= r
->rt_Name
+ len
- 5;
803 if (len
> 5 && (!stricmp(name
, ".card") || !stricmp(name
, ".chip"))) {
806 ULONG
*ptr
= BADDR(seglist
);
807 LONG len
= ptr
[-1] - sizeof(BPTR
);
808 UBYTE
*p
= (UBYTE
*)(ptr
+ 1);
810 if (len
> 16 && !strnicmp(p
, "libs:picasso96/", 15)) {
811 memmove(p
, p
+ 15, strlen(p
+ 15) + 1);
813 } else if (len
> 10 && !strnicmp(p
, "picasso96/", 10)) {
814 memmove(p
, p
+ 10, strlen(p
+ 10) + 1);
820 seglist
= *((BPTR
*)BADDR(seglist
));
824 WriteF("Library path patched\n");
827 static void LoadResidents(BPTR
*namearray
)
830 SIPTR funcarray
[] = {
837 for (i
= 0; namearray
[i
]; i
++) {
840 BPTR seglist
= BNULL
;
844 bname
= namearray
[i
];
845 name
= ConvertBSTR(bname
);
847 handle
= Open(name
, MODE_OLDFILE
);
849 seglist
= LoadSegment(handle
, BNULL
, funcarray
, &stack
);
853 struct Resident
*res
= NULL
;
855 WriteF("Loaded '%S'\n", bname
);
856 for (seg
= seglist
; seg
!= BNULL
; seg
= *((BPTR
*)BADDR(seg
))) {
857 ULONG
*ptr
= BADDR(seg
);
859 res
= scanResidents((UBYTE
*)ptr
, len
, TRUE
);
867 WriteF("Failed to load '%S', error %N\n", bname
, IoErr());
880 #define SERDATR_TBE (1 << 13) /* Tx Buffer Empty */
881 #define SERDAT_STP8 (1 << 8)
882 #define SERDAT_DB8(x) ((x) & 0xff)
883 #define SERPER_BASE_PAL 3546895
885 #define SERPER_BAUD(base, x) ((((base + (x)/2))/(x)-1) & 0x7fff) /* Baud rate */
886 #define INTF_TBE 0x0001
888 static inline void reg_w(ULONG reg
, UWORD val
)
890 volatile UWORD
*r
= (void *)(0xdff000 + reg
);
894 static inline UWORD
reg_r(ULONG reg
)
896 volatile UWORD
*r
= (void *)(0xdff000 + reg
);
900 static void DebugInit(void)
902 /* Set DTR, RTS, etc */
903 volatile UBYTE
*ciab_pra
= (APTR
)0xBFD000;
904 volatile UBYTE
*ciab_ddra
= (APTR
)0xBFD200;
907 *ciab_ddra
= 0xc0; /* Only DTR and RTS are driven as outputs */
908 *ciab_pra
= 0; /* Turn on DTR and RTS */
910 /* Set the debug UART to 115200 */
911 reg_w(SERPER
, SERPER_BAUD(SERPER_BASE_PAL
, 115200));
912 /* Disable serial transmit interrupt */
913 reg_w(INTENA
, INTF_TBE
);
915 static void DebugPutChar(register int chr
)
921 while ((reg_r(SERDATR
) & SERDATR_TBE
) == 0);
922 reg_w(INTREQ
, INTF_TBE
);
923 /* Output a char to the debug UART */
924 reg_w(SERDAT
, SERDAT_STP8
| SERDAT_DB8(chr
));
926 static void DebugPutStr(register const char *buff
)
930 for (; *buff
!= 0; buff
++)
934 static void DebugPutDec(const char *what
, ULONG val
)
947 for (i
= 1000000000; i
> 0; i
/= 10) {
957 DebugPutChar("0123456789"[num
]);
962 static void DebugPutHexVal(ULONG val
)
967 for (i
= 0; i
< 8; i
++) {
968 DebugPutChar("0123456789abcdef"[(val
>> (28 - (i
* 4))) & 0xf]);
972 static void DebugPutHex(const char *what
, ULONG val
)
979 for (i
= 0; i
< 8; i
++) {
980 DebugPutChar("0123456789abcdef"[(val
>> (28 - (i
* 4))) & 0xf]);
987 /* Theory of operation:
989 - create fake sysbase in chip memory (We can't use original because it is not binary compatible with AROS one)
990 - set correct checksum and point ColdCapture to our routine (also in low chip)
991 - reset the system (autoconfig devices disappear, including most expansion RAM and ROM overlay disables chip RAM)
992 - original ROM code runs, disables ROM overlay and checks KS checksum and jumps to our ColdCapture routine
993 - above step is needed because in worst case ALL RAM disappear at reset and there
994 are also accelerators that reset the CPU completely when reset instruction is executed.
995 - now we have control again, autoconfig devices are still unconfigured but at least we have chip ram.
996 - extra step if AROS build final SysBase in autoconfig RAM:
997 - AOS detects invalid SysBase (not accessible)
998 - builds temporary SysBase in Chip RAM
1000 - checks if original SysBase is now valid. If it is, checks ColdCapture and jumps to it.
1001 - we have control now but autoconfig devices have been configured and we don't want it.
1002 - we store original SysBase, set fake sysbase back, reset system again
1003 - now we finally have control without autoconfig
1004 - jump to AROS ROM code entry point which detects romloader mode and automatically reserves RAM used by "ROM" code
1005 - AROS ROM creates new proper execbase and copies ColdCapture and other reset proof vectors from original SysBase
1006 - normal boot starts
1010 static UWORD
GetSysBaseChkSum(struct ExecBase
*sysbase
)
1013 UWORD
*p
= (UWORD
*)&sysbase
->SoftVer
;
1014 while (p
<= &sysbase
->ChkSum
)
1019 /* reset VBR and switch off MMU */
1020 static void setcpu(void)
1025 "move.w 296(%a0),%d1\n"
1033 /* disable caches */
1045 "not040: btst #2,%d1\n"
1048 "lea zero(%pc),%a0\n"
1049 ".long 0xf0104000\n"
1050 ".long 0xf0100c00\n"
1051 ".long 0xf0100800\n"
1058 /* This is needed because KS clears ColdCapture before calling it
1059 * causing checksum mismatch in AROS exec check
1061 void coldcapturecode(void)
1065 ".long end - start\n"
1068 "nop\n" /* Align to start + 4 */
1069 ".long 0x46414b45\n" /* AROS_MAKE_ID('F','A','K','E') */
1070 ".long 0\n" // 0 BootStruct
1071 ".long 0\n" // 4 FakeBase
1072 ".long 0\n" // 8 Stored NMI
1073 ".long 0\n" // 12 ROM EntryPoint
1075 "move.w #0x440,0xdff180\n"
1076 "lea vbrexp(%pc),%a0\n"
1077 "move.l %a0,0x10.w\n" // illegal opcode exception
1078 "move.l #0x400,%sp\n"
1080 "movec %d0,%vbr\n" // reset VBR
1081 "vbrexp:\n" // we get here if 68000 (no VBR)
1082 "lea start+8(%pc),%a4\n"
1088 // We need to check if autoconfig has already been done by
1089 // AOS expansion.library. It happens if SysBase is in autoconfig RAM
1090 // We need to get back to non-autoconfig state.
1091 "tst.l 10(%a0)\n" // ln_Name == NULL?
1093 // It was AOS temp SysBase. Switch back to FakeBase.
1094 // Interestingly ChkBase contains original SysBase pointer in this situation!
1095 "move.l (%a4),%a1\n"
1096 "move.l 38(%a0),8(%a1)\n" // Original SysBase -> BootStruct->RealBase2
1099 // and reset and try again.
1100 "lea 0x01000000,%a0\n"
1101 "sub.l %a0@(-0x14),%a0\n"
1102 "move.l %a0@(4),%a0\n"
1104 /* Force ULONG alignment of 'reset' */
1113 "cmp.l 38(%a0),%d0\n" // ChkBase
1116 "move.l (%a4),%a1\n"
1117 "move.l %a0,4(%a1)\n" // Original SysBase -> BootStruct->RealBase
1119 // set early exceptions
1121 "lea exception(%pc),%a0\n"
1122 "moveq #64-2-1,%d0\n"
1124 "move.l %a0,(%a1)+\n"
1129 "move.l 12(%a4),%a0\n" // Entrypoint
1132 "cmp.w #0x4ef9,(%a0)\n"
1134 // skip elf loader injected header
1136 "move.l (%a0),%a0\n"
1138 "move.l 0(%a0,%d0.w),%a0\n"
1141 // Setup our temporary fake SysBase
1143 "move.l 8(%a4),0x7c.w\n" // restore NMI
1144 "move.l 4(%a4),%a0\n" // FakeBase
1146 "move.w #50,34(%a0)\n" // SoftVer
1147 "lea start(%pc),%a1\n"
1148 "move.l %a1,42(%a0)\n" // ColdCapture
1151 "move.l %d0,38(%a0)\n" // ChkBase
1155 "chk1: add.w (%a0)+,%d1\n"
1158 "move.w %d1,(%a0)\n" // ChkSum
1162 "move.w #0xff0,0xdff180\n"
1163 "move.w #0x000,0xdff180\n"
1169 /* Official reboot code from HRM
1170 * All CPUs have at least 1 word prefetch,
1171 * jmp (a0) has been prefetched even if
1172 * reset disables all memory
1174 static void doreboot(void)
1177 "lea 0x01000000,%a0\n"
1178 "sub.l %a0@(-0x14),%a0\n"
1179 "move.l %a0@(4),%a0\n"
1181 /* Force ULONG alignment of 'reset' */
1190 struct BootStruct
*bs
;
1192 /* AROSBootstrap's ClearCacheE implementations */
1193 void ClearCacheAmigaOS(APTR address
, IPTR length
, ULONG caches
)
1195 CacheClearE(address
, length
, caches
);
1198 void ClearCacheNOP(APTR address
, IPTR length
, ULONG caches
)
1203 void (*ils_ClearCache
)(APTR address
, IPTR length
, ULONG caches
) = ClearCacheNOP
;
1205 static void supercode(void)
1210 DebugPutStr("Entered Supervisor mode.\n");
1213 if ((SysBase
->AttnFlags
& 0xff) != 0)
1216 DebugPutStr("CPU setup done.\n");
1220 traps
[1] = (ULONG
)bs
->FakeBase
;
1222 // TODO: add custom cacheclear, can't call CacheClearU() because it may not work
1223 // anymore and KS 1.x does not even have it
1227 static void BootROM(struct BootStruct
*BootS
)
1230 struct ExecBase
*sysbase
= BootS
->FakeBase
;
1235 WriteF("BootStruct %X8\n", BootS
);
1236 WriteF("FakeBase %X8\n", sysbase
);
1237 WriteF("Bootcode %X8\n", BootS
->bootcode
);
1240 strcpy(bmh
->fakename
, "fakebase");
1241 sysbase
->LibNode
.lib_Node
.ln_Name
= bmh
->fakename
;
1242 sysbase
->ColdCapture
= BootS
->bootcode
;
1243 sysbase
->MaxLocMem
= 512 * 1024;
1244 sysbase
->ChkBase
=~(IPTR
)sysbase
;
1245 sysbase
->ChkSum
= GetSysBaseChkSum(sysbase
) ^ 0xffff;
1246 memcpy(BootS
->bootcode
, coldcapturecode
+ 4, ((ULONG
*)coldcapturecode
)[0]);
1247 colddata
= (ULONG
*)(BootS
->bootcode
+ 8);
1248 colddata
[0] = (ULONG
)BootS
;
1249 colddata
[1] = (ULONG
)sysbase
;
1250 colddata
[2] = traps
[31]; // NMI
1251 colddata
[3] = (ULONG
)bmh
->entrypoint
;
1257 if ((GfxBase
= OpenLibrary("graphics.library", 0))) {
1261 CloseLibrary(GfxBase
);
1264 /* We're off in the weeds now. */
1267 Supervisor((ULONG_FUNC
)supercode
);
1271 static void DumpKickMems(ULONG num
, struct MemList
*ml
)
1274 DWriteF("Original KickMemList:\n");
1276 DWriteF("AROS KickMemList:\n");
1277 /* List is single-linked but last link gets cleared later, so test ln_Succ too */
1278 while (ml
&& ml
->ml_Node
.ln_Succ
) {
1280 DWriteF("%X8:%N\n", ml
, ml
->ml_NumEntries
);
1281 for (i
= 0; i
< ml
->ml_NumEntries
; i
++) {
1282 DWriteF(" %N: %X8, %N\n", i
, ml
->ml_ME
[i
].me_Un
.meu_Addr
, ml
->ml_ME
[i
].me_Length
);
1284 ml
= (struct MemList
*)ml
->ml_Node
.ln_Succ
;
1286 DWriteF("End of List\n");
1289 static void DumpKickTags(ULONG num
, struct Resident
**list
)
1292 DWriteF("Original KickTagList:\n");
1294 DWriteF("AROS KickTagList:\n");
1297 if ((ULONG
)list
& RESLIST_NEXT
) {
1298 DWriteF("Redirected to %X8\n", (ULONG
)list
& ~RESLIST_NEXT
);
1299 list
= (struct Resident
**)((ULONG
)list
& ~RESLIST_NEXT
);
1302 bname
= ConvertCSTR((*list
)->rt_IdString
);
1303 DWriteF("%X8: %X8 %S\n", list
, *list
, bname
);
1307 DWriteF("End of List\n");
1311 #define HC_FORCEFAST 1
1312 struct HardwareConfig
1320 static const struct HardwareConfig hc
[] =
1322 { 8512, 17, "Blizzard A1200 Accelerator", HC_FORCEFAST
}, // Blizzard 1230 IV, 1240 or 1260.
1326 static void DetectHardware(void)
1328 struct ConfigDev
*cd
= NULL
;
1331 ExpansionBase
= (APTR
)OpenLibrary("expansion.library", 0);
1334 while((cd
= FindConfigDev(cd
, -1, -1))) {
1335 for (i
= 0; hc
[i
].manufacturer
; i
++) {
1336 if (cd
->cd_Rom
.er_Manufacturer
== hc
[i
].manufacturer
&& cd
->cd_Rom
.er_Product
== hc
[i
].product
) {
1338 bname
= ConvertCSTR(hc
[i
].name
);
1339 WriteF("%S: ", bname
);
1340 if (hc
[i
].flags
& HC_FORCEFAST
) {
1342 WriteF("ForceFast enabled");
1349 CloseLibrary(ExpansionBase
);
1352 static struct BootStruct
*CreateBootStruct(BPTR ROMSeg
, UBYTE
*cmdline
)
1354 struct TagItem
*tags
;
1355 struct BootStruct
*boots
;
1357 boots
= &bmh
->boots
;
1358 boots
->mlist
= &bmh
->mlist
;
1359 boots
->reslist
= bmh
->res
;
1360 boots
->FakeBase
= &bmh
->FakeBase
;
1361 boots
->bootcode
= &bmh
->bootcode
;
1362 bmh
->entrypoint
= BADDR(ROMSeg
) + sizeof(ULONG
);
1364 /* cmdline is a BCPL string! */
1365 if (cmdline
&& cmdline
[0])
1366 CopyMem(cmdline
+ 1, bmh
->kcmd
, cmdline
[0]);
1368 strcpy(bmh
->kcmd
, DEFAULT_KERNEL_CMDLINE
);
1369 tags
[0].ti_Tag
= KRN_CmdLine
;
1370 tags
[0].ti_Data
= (IPTR
)bmh
->kcmd
;
1371 tags
[1].ti_Tag
= TAG_DONE
;
1373 boots
->magic
= ABS_BOOT_MAGIC
;
1374 boots
->kerneltags
= tags
;
1376 UBYTE
*addr
= specialAlloc(SS_STACK_SIZE
+ MAGIC_FAST_SIZE
+ 1, MEMF_FAST
| MEMF_REVERSE
, "magicfast", FALSE
, SysBase
); /* +1 = guaranteed extra page at the end */
1378 addr
= (UBYTE
*)(((ULONG
)(addr
+ PAGE_SIZE
- 1)) & ~(PAGE_SIZE
- 1));
1379 boots
->ss_address
= addr
;
1380 boots
->ss_size
= SS_STACK_SIZE
;
1381 /* magic fast mem pool for early allocations that normally can't be allocated from fast memory */
1382 boots
->magicfastmem
= boots
->ss_address
+ SS_STACK_SIZE
;
1383 boots
->magicfastmemsize
= MAGIC_FAST_SIZE
;
1389 __startup
static AROS_PROCH(startup
, argstr
, argsize
, sysBase
)
1396 /* Allocate some low MEMF_CHIP ram, as a buffer
1397 * against overlapping allocations with the initial
1400 lowmem
= AllocMem(PAGE_SIZE
, MEMF_CHIP
);
1403 * Determine the version of CacheClearE to use.
1404 * This is called from the loadseg support so we check for SysBase's
1405 * lib_Version, since this code can be running on AOS 1.4 or lower.
1407 if (SysBase
->LibNode
.lib_Version
>= 37)
1409 ils_ClearCache
= ClearCacheAmigaOS
;
1413 ULONG cpuflags
= SysBase
->AttnFlags
;
1415 The current used AmigaOS version doesnt implement
1416 a usable CacheClearE, so we have to do it ourselves
1418 if ((cpuflags
& AFF_68060
|AFF_68040
|AFF_68020
) == 0)
1421 AmigaOS may not have detected the CPU type
1422 so we may need to detect it ourselves ...
1426 if (cpuflags
& AFF_68060
) {
1429 } else if (cpuflags
& AFF_68040
) {
1432 } else if (cpuflags
& AFF_68020
) {
1436 /* Everybody else (68000, 68010) */
1441 DOSBase
= (APTR
)OpenLibrary("dos.library", 0);
1442 if (DOSBase
!= NULL
) {
1444 BSTR name
= AROS_CONST_BSTR("aros.elf");
1445 enum { ARG_ROM
= 16, ARG_CMD
= 17, ARG_FORCECHIP
= 18, ARG_FORCEFAST
= 19, ARG_DEBUG
= 20, ARG_FORCEAROS
= 21, ARG_MODULES
= 0 };
1446 /* It would be nice to use the '/M' switch, but that
1447 * is not supported under the AOS BCPL RdArgs routine.
1449 * So only 16 modules are supported
1451 BSTR format
= AROS_CONST_BSTR(",,,,,,,,,,,,,,,,ROM/K,CMD/K,FORCECHIP/S,FORCEFAST/S,DEBUG/S,FORCEAROS/S");
1452 /* Make sure the args are in .bss, not stack */
1453 static ULONG args
[16 + 6 + 256] __attribute__((aligned(4))) = { };
1457 RdArgs(format
, MKBADDR(args
), sizeof(args
)/sizeof(args
[0]));
1459 DWriteF("ROM : %S\n", args
[ARG_ROM
]);
1460 DWriteF("CMD : %S\n", args
[ARG_CMD
]);
1461 DWriteF("FORCECHIP: %N\n", args
[ARG_FORCECHIP
]);
1462 DWriteF("FORCEFAST: %N\n", args
[ARG_FORCEFAST
]);
1463 DWriteF("MOD 0 : %S\n", args
[0]);
1464 DWriteF(" 1 : %S\n", args
[1]);
1465 DWriteF(" 2 : %S\n", args
[2]);
1466 DWriteF(" 3 : %S\n", args
[3]);
1469 forceAROS
= args
[ARG_FORCEAROS
] ? TRUE
: FALSE
;
1470 forceCHIP
= args
[ARG_FORCECHIP
] ? TRUE
: FALSE
;
1471 forceFAST
= args
[ARG_FORCEFAST
] ? TRUE
: FALSE
;
1472 debug_enabled
= args
[ARG_DEBUG
] ? TRUE
: FALSE
;
1474 /* See if we're already running on AROS.
1476 if (OpenResource("kernel.resource") != NULL
) {
1478 CloseLibrary((APTR
)DOSBase
);
1479 FreeMem(lowmem
, PAGE_SIZE
);
1486 WriteF("AROSBootstrap " ADATE
"\n");
1488 WriteF("Forcing load of AROS on existing AROS\n");
1490 /* Blizzard A1200 accelerator boards have strange MAP ROM
1491 * feature, even when it is disabled, ROM is copied to
1492 * last 512K of RAM, so we have to make sure all our
1493 * allocations ignore this region.
1494 * Blizzard Fast RAM memory type is plain MEMF_FAST.
1496 if (SysBase
->LibNode
.lib_Version
>= 37 && !AvailMem(MEMF_KICK
| MEMF_FAST
)) {
1497 if (AvailMem(MEMF_FAST
)) {
1498 WriteF("Reserving non-MEMF_KICK Fast RAM\n");
1500 /* Allocate in PAGE_SIZE byte chunks, it is smallest allocated size */
1501 for (i
= 0; i
< 524288 / PAGE_SIZE
; i
++)
1502 AllocMem(PAGE_SIZE
, MEMF_FAST
| MEMF_REVERSE
);
1515 /* Load ROM image */
1516 if (args
[ARG_ROM
] == BNULL
)
1517 args
[ARG_ROM
] = name
;
1519 ROMSegList
= ROMLoad(args
[ARG_ROM
]);
1520 if (ROMSegList
!= BNULL
) {
1521 struct BootStruct
*BootS
;
1522 WriteF("Successfully loaded ROM\n");
1526 LoadResidents((BPTR
*)&args
[ARG_MODULES
]);
1527 BootS
= CreateBootStruct(ROMSegList
, BADDR(args
[ARG_CMD
]));
1530 WriteF("Debug info:\n");
1531 DumpKickTags(0, SysBase
->KickTagPtr
);
1532 DumpKickTags(1, BootS
->reslist
);
1533 DumpKickMems(0, SysBase
->KickMemPtr
);
1534 DumpKickMems(1, (struct MemList
*)bmh
->mlist
.lh_Head
);
1536 WriteF("Booting...\n");
1540 UnLoadSeg(ROMSegList
);
1542 WriteF("Can't load ROM ELF file %S\n", args
[ARG_ROM
]);
1545 WriteF("Can't parse arguments, error %N\n", IoErr());
1548 CloseLibrary((APTR
)DOSBase
);
1551 FreeMem(lowmem
, PAGE_SIZE
);
1558 /* Provide dummy implementation of strerror for gzip code */
1559 char *strerror(int errnum
)