2 * Copyright (C) 2011, 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) + sizeof(struct MemList))
31 #define ALLOCPADDING (sizeof(struct MemChunk) + 2 * sizeof(BPTR))
33 #define SS_STACK_SIZE 0x2000
34 #define MAGIC_FAST_SIZE 65536
35 /* This must match with start.c! */
36 #define ABS_BOOT_MAGIC 0x4d363802
40 struct TagItem
*kerneltags
;
44 LONG magicfastmemsize
;
47 #include <stddef.h> /* offsetof */
48 #include <string.h> /* memcpy, memset */
51 #if defined(DEBUG) && DEBUG > 1
52 #define DEFAULT_KERNEL_CMDLINE "sysdebug=InitCode mungwall"
54 #define DEFAULT_KERNEL_CMDLINE "sysdebug=InitCode"
57 #define PROTO_KERNEL_H /* Don't pick up AROS kernel hooks */
63 static inline void bug(const char *fmt
, ...)
65 static char buff
[256];
69 vsnprintf(buff
, sizeof(buff
), fmt
, args
);
72 Write(Output(), buff
, strlen(buff
));
81 struct ExecBase
*SysBase
;
82 struct DosLibrary
*DOSBase
;
83 struct Library
*ExpansionBase
;
85 static BOOL ROM_Loaded
= FALSE
;
86 static BOOL forceAROS
= FALSE
;
87 static BOOL forceCHIP
= FALSE
;
88 static BOOL forceFAST
= FALSE
;
89 static BOOL debug_enabled
= FALSE
;
90 static struct List mlist
;
92 /* KS 1.3 (and earlier) don't have a dos.library with
93 * niceties such as VFPrintf nor ReadArgs.
95 * We need to use the BCPL routines to be able
96 * to do these types of operations.
98 #define BCPL_WriteS 73
99 #define BCPL_WriteF 74
100 #define BCPL_RdArgs 78
103 #define Printf __Printf_NOT_AVAILABLE_UNDER_KS1_3
105 #define ReadArgs __ReadArgs_NOT_AVAILABLE_UNDER_KS1_3
107 /* BCPL can trash D5-D7 and A3, evidently.
109 static void bcplWrapper(void)
112 "movem.l %d5-%d7/%a3,%sp@-\n"
114 "movem.l %sp@+,%d5-%d7/%a3\n"
118 static ULONG
doBCPL(int index
, ULONG d1
, ULONG d2
, ULONG d3
, ULONG d4
, const IPTR
*arg
, int args
)
120 struct Process
*pr
= (APTR
)FindTask(NULL
);
122 ULONG
*gv
= pr
->pr_GlobVec
;
124 ULONG
*BCPL_frame
= AllocMem(1500, MEMF_ANY
);
125 if (BCPL_frame
== NULL
)
128 func
= (APTR
)gv
[index
];
131 CopyMem(arg
, &BCPL_frame
[3 + 4], args
* sizeof(ULONG
));
133 ret
= AROS_UFC11(ULONG
, bcplWrapper
,
134 AROS_UFCA(ULONG
, 0, D0
), /* BCPL frame usage (args-3)*/
135 AROS_UFCA(ULONG
, d1
, D1
),
136 AROS_UFCA(ULONG
, d2
, D2
),
137 AROS_UFCA(ULONG
, d3
, D3
),
138 AROS_UFCA(ULONG
, d4
, D4
),
139 AROS_UFCA(ULONG
, 0, A0
), /* System memory base */
140 AROS_UFCA(ULONG
*, &BCPL_frame
[3], A1
),
141 AROS_UFCA(APTR
, gv
, A2
),
142 AROS_UFCA(APTR
, func
, A4
),
143 AROS_UFCA(APTR
, DOSBase
->dl_A5
, A5
),
144 AROS_UFCA(APTR
, DOSBase
->dl_A6
, A6
));
146 FreeMem(BCPL_frame
, 1500);
152 static BSTR
ConvertCSTR(const UBYTE
*name
)
154 UBYTE
*bname
= AllocMem(256 + 1, MEMF_CLEAR
);
155 UWORD len
= strlen(name
), i
;
160 strcpy(bname
+ 1, name
);
161 for (i
= 0; i
< len
; i
++) {
162 if (bname
[1 + i
] == 13 || bname
[1 + i
] == 10)
165 return MKBADDR(bname
);
167 static void FreeBSTR(BSTR bstr
)
169 FreeMem(BADDR(bstr
), 256 + 1);
173 static UBYTE
*ConvertBSTR(BSTR bname
)
175 UBYTE
*name
= BADDR(bname
);
176 UBYTE
*s
= AllocMem(256 + 1, MEMF_CLEAR
);
179 CopyMem(name
+ 1, s
, name
[0]);
183 static void FreeString(UBYTE
*cstr
)
185 FreeMem(cstr
, 256+1);
188 static void _WriteF(BPTR bfmt
, ...)
190 IPTR
*args
= (IPTR
*)&bfmt
;
192 doBCPL(BCPL_WriteF
, bfmt
, args
[1], args
[2], args
[3], &args
[4], 26-3);
196 static void _DWriteF(BPTR bfmt
, ...)
198 if (debug_enabled
|| DEBUG
> 1) {
199 IPTR
*args
= (IPTR
*)&bfmt
;
201 doBCPL(BCPL_WriteF
, bfmt
, args
[1], args
[2], args
[3], &args
[4], 26-3);
204 #define DWriteF(fmt, args...) _DWriteF(AROS_CONST_BSTR(fmt) ,##args )
207 #define WriteF(fmt, args...) _WriteF(AROS_CONST_BSTR(fmt) ,##args )
209 /* For KS < 2.0, we need to call the BCPL ReadArgs,
210 * since DOS/ReadArgs doesn't exist.
212 static ULONG
RdArgs(BSTR format
, BPTR args
, ULONG max_arg
)
214 return doBCPL(BCPL_RdArgs
, format
, args
, max_arg
, 0, NULL
, 0);
219 struct MemHeader
*mh
;
220 ForeachNode(&SysBase
->MemList
, mh
) {
222 bstr
[0] = strlen(mh
->mh_Node
.ln_Name
) & 0xff;
223 strncpy(&bstr
[1], mh
->mh_Node
.ln_Name
, bstr
[0]);
224 WriteF("@$%X8-$%X8 ATTR $%X4 FREE $%X8 (%S)\n",
225 mh
->mh_Lower
, mh
->mh_Upper
, mh
->mh_Attributes
,
226 mh
->mh_Free
, MKBADDR(bstr
));
230 /* Allocate MMU page aligned memory chunks */
232 static APTR
AllocPageAligned(ULONG
*psize
, ULONG flags
)
238 size
+= ALLOCPADDING
;
239 ret
= AllocMem(size
+ 2 * PAGE_SIZE
, flags
);
240 D(DWriteF("AllocPageAligned: $%X8, %X4 => %X8\n", size
+ 2 * PAGE_SIZE
, flags
, ret
));
244 FreeMem(ret
, size
+ 2 * PAGE_SIZE
);
245 size
= (size
+ PAGE_SIZE
- 1) & PAGE_MASK
;
246 ret
= AllocAbs(size
, (APTR
)(((((ULONG
)ret
) + PAGE_SIZE
- 1) & PAGE_MASK
)));
253 static void FreePageAligned(APTR addr
, ULONG size
)
255 FreeMem(addr
, (size
+ PAGE_SIZE
- 1) & PAGE_MASK
);
258 /* Define these here for zlib so that we don't
259 * pull in arosc.library.
261 * We can't use AllocVec, since it's only
262 * been around since KS v36
264 void *malloc(int size
)
268 size
+= sizeof(ULONG
);
270 vec
= AllocMem(size
, MEMF_ANY
);
272 WriteF("libz: Failed to allocate %N bytes of type %X8\n", size
, MEMF_ANY
);
276 vec
[0] = (ULONG
)size
;
282 ULONG
*vec
= ptr
- sizeof(ULONG
);
283 FreeMem(vec
, vec
[0]);
286 int open(const char *name
, int mode
)
288 return (int)Open(name
, MODE_OLDFILE
);
297 ssize_t
read(int fd
, void *buff
, size_t len
)
299 return Read((BPTR
)fd
, buff
, (LONG
)len
);
302 off_t
lseek(int fd
, off_t offset
, int whence
)
304 LONG mode
= SEEK_SET
;
308 case SEEK_CUR
: mode
= OFFSET_CURRENT
; break;
309 case SEEK_SET
: mode
= OFFSET_BEGINNING
; break;
310 case SEEK_END
: mode
= OFFSET_END
; break;
314 err
= Seek((BPTR
)fd
, (LONG
)offset
, mode
);
318 return Seek((BPTR
)fd
, 0, OFFSET_CURRENT
);
321 static AROS_UFH4(LONG
, aosRead
,
322 AROS_UFHA(BPTR
, file
, D1
),
323 AROS_UFHA(void *, buf
, D2
),
324 AROS_UFHA(LONG
, size
, D3
),
325 AROS_UFHA(struct DosLibrary
*, DOSBase
, A6
))
329 return Read(file
, buf
, (unsigned)size
);
333 static AROS_UFH4(LONG
, aosSeek
,
334 AROS_UFHA(BPTR
, file
, D1
),
335 AROS_UFHA(LONG
, pos
, D2
),
336 AROS_UFHA(LONG
, mode
, D3
),
337 AROS_UFHA(struct DosLibrary
*, DOSBase
, A6
))
345 case OFFSET_CURRENT
: whence
= SEEK_CUR
; break;
346 case OFFSET_END
: whence
= SEEK_END
; break;
347 case OFFSET_BEGINNING
: whence
= SEEK_SET
; break;
351 oldpos
= (LONG
)Seek(file
, 0, SEEK_CUR
);
353 ret
= (LONG
)Seek(file
, (z_off_t
)pos
, whence
);
362 static APTR
aosAllocMem(ULONG size
, ULONG flags
, struct ExecBase
*SysBase
)
367 /* Clear bits 15-0, we're setting memory class explicitly */
370 if (SysBase
->LibNode
.lib_Version
>= 36) {
371 flags
|= MEMF_LOCAL
| MEMF_REVERSE
;
376 size
+= ALLOCATION_EXTRA
;
377 mem
= AllocMem(size
, flags
| MEMF_CLEAR
);
379 WriteF("AOS: Failed to allocate %N bytes of type %X8\n", size
, flags
);
384 ml
= (struct MemList
*)(mem
+ sizeof(struct MemChunk
));
385 ml
->ml_NumEntries
= 1;
386 ml
->ml_ME
[0].me_Addr
= (APTR
)mem
;
387 ml
->ml_ME
[0].me_Length
= size
;
388 AddTail(&mlist
, (struct Node
*)ml
);
393 static AROS_UFH3(APTR
, aosAlloc
,
394 AROS_UFHA(ULONG
, size
, D0
),
395 AROS_UFHA(ULONG
, flags
, D1
),
396 AROS_UFHA(struct ExecBase
*, SysBase
, A6
))
400 return aosAllocMem(size
, flags
, SysBase
);
404 static AROS_UFH3(void, aosFree
,
405 AROS_UFHA(APTR
, addr
, A1
),
406 AROS_UFHA(ULONG
, size
, D0
),
407 AROS_UFHA(struct ExecBase
*, SysBase
, A6
))
411 addr
-= sizeof(struct MemList
);
412 Remove((struct Node
*)addr
);
413 addr
-= sizeof(struct MemChunk
);
414 size
+= ALLOCATION_EXTRA
;
420 /* Backcalls for LoadSegment
421 * using the gzip backend.
423 static AROS_UFH4(LONG
, elfRead
,
424 AROS_UFHA(BPTR
, file
, D1
),
425 AROS_UFHA(void *, buf
, D2
),
426 AROS_UFHA(LONG
, size
, D3
),
427 AROS_UFHA(struct DosLibrary
*, DOSBase
, A6
))
431 return gzread((gzFile
)file
, buf
, (unsigned)size
);
435 static AROS_UFH4(LONG
, elfSeek
,
436 AROS_UFHA(BPTR
, file
, D1
),
437 AROS_UFHA(LONG
, pos
, D2
),
438 AROS_UFHA(LONG
, mode
, D3
),
439 AROS_UFHA(struct DosLibrary
*, DOSBase
, A6
))
447 case OFFSET_CURRENT
: whence
= SEEK_CUR
; break;
448 case OFFSET_END
: whence
= SEEK_END
; break;
449 case OFFSET_BEGINNING
: whence
= SEEK_SET
; break;
453 oldpos
= (LONG
)gzseek((gzFile
)file
, 0, SEEK_CUR
);
455 ret
= (LONG
)gzseek((gzFile
)file
, (z_off_t
)pos
, whence
);
464 static APTR
specialAlloc(ULONG size
, ULONG flags
, struct ExecBase
*SysBase
)
469 D(DWriteF("ELF: Attempt to allocate %N bytes of type %X8\n", size
, flags
));
470 /* Since we don't know if we need to wrap the memory
471 * with the KickMem wrapper until after allocation,
472 * we always adjust the size as if we have to.
474 size
+= ALLOCATION_EXTRA
;
476 if (flags
& MEMF_KICK
) {
477 D(DWriteF("MEMF_KICK %N\n", size
));
481 /* Prefer MEMF_KICK | MEMF_FAST if available */
486 /* Hmm. MEMF_LOCAL is only available on v36 and later.
487 * Use MEMF_CHIP if we have to.
489 if (flags
& MEMF_LOCAL
) {
490 D(DWriteF("MEMF_LOCAL %N\n", size
));
492 flags
&= ~MEMF_LOCAL
;
493 } else if (SysBase
->LibNode
.lib_Version
< 36 || forceCHIP
) {
494 flags
&= ~MEMF_LOCAL
;
499 /* MEMF_31BIT is not available on AOS */
500 if ((flags
& MEMF_31BIT
)) {
501 flags
&= ~MEMF_31BIT
;
504 /* If ROM allocation, always allocate from top of memory if possible */
505 if ((flags
& MEMF_PUBLIC
) && SysBase
->LibNode
.lib_Version
>= 36) {
506 flags
|= MEMF_REVERSE
;
509 D(DWriteF("ELF: Attempt to allocate %N bytes of type %X8\n", size
, flags
));
510 mem
= AllocPageAligned(&size
, flags
| MEMF_CLEAR
);
512 if ((flags
& (MEMF_KICK
| MEMF_FAST
)) == (MEMF_KICK
| MEMF_FAST
)) {
513 /* Couldn't allocate MEMF_KICK | MEMF_FAST, fall back to any memory */
514 mem
= AllocPageAligned(&size
, (flags
& MEMF_REVERSE
) | MEMF_CLEAR
);
517 D(DWriteF("ELF: Failed to allocate %N bytes of type %X8\n", size
, flags
));
522 D(DWriteF("ELF: Got memory at %X8, size %N\n", (IPTR
)mem
, size
));
524 ml
= (struct MemList
*)(mem
+ sizeof(struct MemChunk
));
525 ml
->ml_NumEntries
= 1;
526 ml
->ml_ME
[0].me_Addr
= (APTR
)mem
;
527 ml
->ml_ME
[0].me_Length
= size
;
529 /* Add to the KickMem list */
530 AddTail(&mlist
, (struct Node
*)ml
);
536 static AROS_UFH3(APTR
, elfAlloc
,
537 AROS_UFHA(ULONG
, size
, D0
),
538 AROS_UFHA(ULONG
, flags
, D1
),
539 AROS_UFHA(struct ExecBase
*, SysBase
, A6
))
543 return specialAlloc(size
, flags
, SysBase
);
548 static AROS_UFH3(void, elfFree
,
549 AROS_UFHA(APTR
, addr
, A1
),
550 AROS_UFHA(ULONG
, size
, D0
),
551 AROS_UFHA(struct ExecBase
*, SysBase
, A6
))
555 /* If not page aligned, and the offset from the page boundary
556 * is the sizeof(MemChunk) + sizeof(MemList) then we can assume
557 * that it was a KickTag protected allocation
559 D(DWriteF("ELF: Free memory at %X8, size %N\n", (IPTR
)addr
, size
));
560 addr
-= sizeof(struct MemList
);
561 Remove((struct Node
*)addr
);
562 addr
-= sizeof(struct MemChunk
);
563 size
+= ALLOCATION_EXTRA
;
564 D(DWriteF("ELF: FREE memory at %X8, size %N\n", (IPTR
)addr
, size
));
565 FreePageAligned(addr
, size
);
571 * This routine is called from within libloadseg.a's ELF loader.
572 * In dos.library it's responsible for collecting debug information from the loaded file.
573 * Here it does nothing (FIXME ???)
575 void register_elf(BPTR file
, BPTR hunks
, struct elfheader
*eh
, struct sheader
*sh
, struct DosLibrary
*DOSBase
)
580 static BPTR
ROMLoad(BSTR bfilename
)
585 SIPTR funcarray
[] = {
591 filename
= ConvertBSTR(bfilename
);
595 WriteF("Loading '%S' into RAM...\n", bfilename
);
596 if ((gzf
= gzopen(filename
, "rb"))) {
597 gzbuffer(gzf
, 65536);
599 rom
= LoadSegment((BPTR
)gzf
, BNULL
, funcarray
, NULL
);
601 WriteF("'%S': Can't parse, error %N\n", bfilename
, IoErr());
606 WriteF("'%S': Can't open\n", bfilename
);
608 FreeString(filename
);
612 /* Patch "picasso96/<driver>.chip" -> "<driver>.chip" so that OpenLibrary() finds it */
613 static void RTGPatch(struct Resident
*r
, BPTR seg
)
615 BOOL patched
= FALSE
;
616 WORD len
= strlen(r
->rt_Name
);
617 const UBYTE
*name
= r
->rt_Name
+ len
- 5;
618 if (len
> 5 && (!stricmp(name
, ".card") || !stricmp(name
, ".chip"))) {
621 ULONG
*ptr
= BADDR(seglist
);
622 LONG len
= ptr
[-1] - sizeof(BPTR
);
623 UBYTE
*p
= (UBYTE
*)(ptr
+ 1);
625 if (len
> 16 && !strnicmp(p
, "libs:picasso96/", 15)) {
626 memmove(p
, p
+ 15, strlen(p
+ 15) + 1);
628 } else if (len
> 10 && !strnicmp(p
, "picasso96/", 10)) {
629 memmove(p
, p
+ 10, strlen(p
+ 10) + 1);
635 seglist
= *((BPTR
*)BADDR(seglist
));
639 WriteF("Library path patched\n");
642 static BOOL
PatchResidents(BPTR seg
)
644 const LONG ressize
= offsetof(struct Resident
, rt_Init
) + sizeof(APTR
);
646 ULONG
*ptr
= BADDR(seg
);
648 UWORD
*end
= (UWORD
*)((ULONG
)ptr
+ ptr
[-1] - ressize
);
650 res
= (UWORD
*)(ptr
+ 1);
652 if (*res
== RTC_MATCHWORD
&& ((ULONG
*)(res
+ 1))[0] == (ULONG
)res
) {
653 struct Resident
*r
= (struct Resident
*)res
;
654 r
->rt_Flags
|= 1 << 5;
655 if (r
->rt_EndSkip
<= (APTR
)res
) {
657 WriteF("Invalid rt_EndSkip: %X8, Resident: %X8\n", r
->rt_EndSkip
, r
);
659 res
+= ressize
/ sizeof(WORD
) - 1;
661 res
= (UWORD
*)r
->rt_EndSkip
- 1;
671 #define RESLIST_CHUNK 100
672 #define LRF_NOPATCH (1 << 0) /* If set, don't patch the struct Resident */
674 static struct Resident
**LoadResident(BPTR seg
, struct Resident
**reslist
, ULONG
*resleft
, ULONG flags
)
676 const LONG ressize
= offsetof(struct Resident
, rt_Init
) + sizeof(APTR
);
677 ULONG
*ptr
= BADDR(seg
);
679 UWORD
*end
= (UWORD
*)((ULONG
)ptr
+ ptr
[-1] - ressize
);
681 res
= (UWORD
*)(ptr
+ 1);
683 if (*res
== RTC_MATCHWORD
&& ((ULONG
*)(res
+ 1))[0] == (ULONG
)res
) {
684 struct Resident
*r
= (struct Resident
*)res
;
685 if (!(flags
& LRF_NOPATCH
)) {
686 /* Set RTF_COLDSTART if no initialization flags set */
687 if (!(r
->rt_Flags
& (RTF_COLDSTART
| RTF_SINGLETASK
| RTF_AFTERDOS
)))
688 r
->rt_Flags
|= RTF_COLDSTART
;
695 struct Resident
**resnew
;
696 resnew
= aosAllocMem(RESLIST_CHUNK
* sizeof(struct Resident
*), MEMF_CLEAR
, SysBase
);
700 *reslist
= (APTR
)((IPTR
)resnew
| RESLIST_NEXT
);
702 *resleft
= RESLIST_CHUNK
- 1;
704 D(DWriteF("Resident structure found @%X8\n", r
));
708 if (r
->rt_EndSkip
<= (APTR
)res
)
709 res
+= ressize
/ sizeof(WORD
) - 1;
711 res
= (UWORD
*)r
->rt_EndSkip
- 1;
719 static struct Resident
**LoadResidents(BPTR
*namearray
, struct Resident
**resnext
, ULONG
*resleft
)
722 SIPTR funcarray
[] = {
729 for (i
= 0; namearray
[i
]; i
++) {
732 BPTR seglist
= BNULL
;
736 bname
= namearray
[i
];
737 name
= ConvertBSTR(bname
);
739 handle
= Open(name
, MODE_OLDFILE
);
741 seglist
= LoadSegment(handle
, BNULL
, funcarray
, &stack
);
746 WriteF("Loaded '%S'\n", bname
);
747 for (seg
= seglist
; seg
!= BNULL
; seg
= *((BPTR
*)BADDR(seg
)))
748 resnext
= LoadResident(seg
, resnext
, resleft
, 0);
750 WriteF("Failed to load '%S', error %N\n", bname
, IoErr());
765 #define SERDATR_TBE (1 << 13) /* Tx Buffer Empty */
766 #define SERDAT_STP8 (1 << 8)
767 #define SERDAT_DB8(x) ((x) & 0xff)
768 #define SERPER_BASE_PAL 3546895
770 #define SERPER_BAUD(base, x) ((((base + (x)/2))/(x)-1) & 0x7fff) /* Baud rate */
771 #define INTF_TBE 0x0001
773 static inline void reg_w(ULONG reg
, UWORD val
)
775 volatile UWORD
*r
= (void *)(0xdff000 + reg
);
779 static inline UWORD
reg_r(ULONG reg
)
781 volatile UWORD
*r
= (void *)(0xdff000 + reg
);
785 static void DebugInit(void)
787 /* Set DTR, RTS, etc */
788 volatile UBYTE
*ciab_pra
= (APTR
)0xBFD000;
789 volatile UBYTE
*ciab_ddra
= (APTR
)0xBFD200;
792 *ciab_ddra
= 0xc0; /* Only DTR and RTS are driven as outputs */
793 *ciab_pra
= 0; /* Turn on DTR and RTS */
795 /* Set the debug UART to 115200 */
796 reg_w(SERPER
, SERPER_BAUD(SERPER_BASE_PAL
, 115200));
797 /* Disable serial transmit interrupt */
798 reg_w(INTENA
, INTF_TBE
);
800 static void DebugPutChar(register int chr
)
806 while ((reg_r(SERDATR
) & SERDATR_TBE
) == 0);
807 reg_w(INTREQ
, INTF_TBE
);
808 /* Output a char to the debug UART */
809 reg_w(SERDAT
, SERDAT_STP8
| SERDAT_DB8(chr
));
811 static void DebugPutStr(register const char *buff
)
815 for (; *buff
!= 0; buff
++)
819 static void DebugPutDec(const char *what
, ULONG val
)
832 for (i
= 1000000000; i
> 0; i
/= 10) {
842 DebugPutChar("0123456789"[num
]);
847 static void DebugPutHex(const char *what
, ULONG val
)
854 for (i
= 0; i
< 8; i
++) {
855 DebugPutChar("0123456789abcdef"[(val
>> (28 - (i
* 4))) & 0xf]);
859 static void DebugPutHexVal(ULONG val
)
864 for (i
= 0; i
< 8; i
++) {
865 DebugPutChar("0123456789abcdef"[(val
>> (28 - (i
* 4))) & 0xf]);
873 #define FAKEBASE 0x200
874 #define FAKEBASESIZE 558
875 #define COLDCAPTURE (FAKEBASE + FAKEBASESIZE + 16)
877 /* Theory of operation:
879 - create fake sysbase in low chip memory (We can't use original because it is not binary compatible with AROS one)
880 - set correct checksum and point ColdCapture to our routine (also in low chip)
881 - reset the system (autoconfig devices disappear, including most expansion RAM and ROM overlay disables chip RAM)
882 - original ROM code now disables ROM overlay and checks KS checksum and jumps to our ColdCapture routine
883 - above step is needed because in worst case ALL RAM disappear at reset and there
884 are also accelerators that reset the CPU completely when reset instruction is executed.
885 - now we have control again, autoconfig devices are still unconfigured but at least we have chip ram.
886 - jump to AROS ROM code entry point which detects romloader mode and automatically reserves RAM used by "ROM" code
887 - AROS ROM creates new proper execbase and copies ColdCapture
892 static UWORD
GetSysBaseChkSum(struct ExecBase
*sysbase
)
895 UWORD
*p
= (UWORD
*)&sysbase
->SoftVer
;
896 while (p
<= &sysbase
->ChkSum
)
901 static ULONG
mySumKickData(struct ExecBase
*sysbase
, BOOL output
)
906 if (sysbase
->KickTagPtr
) {
907 IPTR
*list
= sysbase
->KickTagPtr
;
910 chksum
+= (ULONG
)*list
;
913 WriteF("%X8 %X8\n", list
, *list
);
914 WriteF("CHK %X8\n", chksum
);
918 /* on amiga, if bit 31 is set then this points to another list of
919 * modules rather than pointing to a single module. bit 31 is
920 * inconvenient on architectures where code may be loaded above
921 * 2GB. on these platforms we assume aligned pointers and use bit
924 if(*list
& 0x80000000) { list
= (IPTR
*)(*list
& 0x7fffffff); continue; }
926 if(*list
& 0x1) { list
= (IPTR
*)(*list
& ~(IPTR
)0x1); continue; }
933 if (sysbase
->KickMemPtr
) {
934 struct MemList
*ml
= (struct MemList
*)sysbase
->KickMemPtr
;
937 ULONG
*p
= (ULONG
*)ml
;
938 for (i
= 0; i
< sizeof(struct MemList
) / sizeof(ULONG
); i
++)
943 WriteF("ML %X8 %X8\n", ml
, chksum
);
944 WriteF("NODE0 %X8 %X8\n", p
[0], p
[1]);
945 WriteF("NODE2 %X8 %X8\n", p
[2], p
[3]);
946 WriteF("ADDR %X8 %X8\n", ml
->ml_ME
[0].me_Un
.meu_Addr
, ml
->ml_ME
[0].me_Length
);
947 WriteF("DATA0 %X8 %X8\n", p
[6], p
[7]);
951 ml
= (struct MemList
*)ml
->ml_Node
.ln_Succ
;
955 if (isdata
&& !chksum
)
961 /* reset VBR and switch off MMU */
962 static void setcpu(void)
967 "move.w 296(%a0),%d1\n"
987 "not040: btst #2,%d1\n"
990 "lea zero(%pc),%a0\n"
1000 /* This is needed because KS clears ColdCapture before calling it
1001 * causing checksum mismatch in AROS exec check
1003 void coldcapturecode(void)
1006 ".long end - start\n"
1009 "nop\n" /* Align to start + 4 */
1010 ".long 0x46414b45\n" /* AROS_MAKE_ID('F','A','K','E') */
1012 "move.w #0x440,0xdff180\n"
1016 // set early exceptions
1018 "lea exception(%pc),%a0\n"
1019 "moveq #64-2-1,%d0\n"
1021 "move.l %a0,(%a1)+\n"
1025 "move.l (%a0),0x7c.w\n" // restore NMI
1028 "lea start(%pc),%a1\n"
1029 "move.l %a1,42(%a0)\n" // ColdCapture
1032 "move.l %d0,38(%a0)\n" // ChkBase
1036 "chk1: add.w (%a0)+,%d1\n"
1039 "move.w %d1,(%a0)\n" // ChkSum
1040 "move.l start-4(%pc),%a0\n"
1043 "cmp.w #0x4ef9,(%a0)\n"
1045 // skip elf loader injected header
1047 "move.l (%a0),%a0\n"
1049 "move.l 0(%a0,%d0.w),%a0\n"
1052 "move.w #0xff0,0xdff180\n"
1053 "move.w #0x000,0xdff180\n"
1059 /* Official reboot code from HRM
1060 * All CPUs have at least 1 word prefetch,
1061 * jmp (a0) has been prefetched even if
1062 * reset disables all memory
1064 static void doreboot(void)
1067 "lea 0x01000000,%a0\n"
1068 "sub.l %a0@(-0x14),%a0\n"
1069 "move.l %a0@(4),%a0\n"
1071 ".balign 8\n" /* Workaround for E-UAE emulation bug */
1077 APTR entry
, kicktags
;
1078 struct BootStruct
*bootstruct
;
1080 static void supercode(void)
1082 ULONG
*fakesys
, *coldcapture
, *coldcapturep
;
1083 struct ExecBase
*sysbase
;
1088 DebugPutStr("Entered Supervisor mode.\n");
1091 if ((SysBase
->AttnFlags
& 0xff) != 0)
1095 DebugPutStr("CPU setup done.\n");
1098 fakesys
= (ULONG
*)FAKEBASE
;
1099 coldcapture
= (ULONG
*)COLDCAPTURE
;
1100 coldcapture
[-1] = (ULONG
)entry
;
1101 coldcapturep
= (ULONG
*)coldcapturecode
;
1102 len
= *coldcapturep
++;
1103 memcpy (coldcapture
, coldcapturep
, len
);
1105 *fakesys
++ = traps
[31]; // Level 7
1106 *fakesys
++ = 0x4ef9 | (COLDCAPTURE
>> 16);
1107 *fakesys
++ = (COLDCAPTURE
<< 16) | 0x4e75;
1108 sysbase
= (struct ExecBase
*)fakesys
;
1110 memset(sysbase
, 0, FAKEBASESIZE
);
1111 /* Misuse DebugData as a kernel tag pointer,
1114 sysbase
->DebugData
= bootstruct
;
1117 sysbase
->LibNode
.lib_Node
.ln_Pred
= &sysbase
->LibNode
.lib_Node
;
1118 sysbase
->LibNode
.lib_Node
.ln_Succ
= &sysbase
->LibNode
.lib_Node
;
1120 /* Set up cold capture */
1121 sysbase
->ColdCapture
= coldcapture
;
1122 sysbase
->MaxLocMem
= 512 * 1024;
1123 sysbase
->ChkBase
=~(IPTR
)sysbase
;
1124 sysbase
->ChkSum
= GetSysBaseChkSum(sysbase
) ^ 0xffff;
1126 /* Propogate the existing OS's Kick Data */
1127 if (mlist
.lh_Head
->ln_Succ
) {
1128 sysbase
->KickMemPtr
= (APTR
)mlist
.lh_Head
;
1129 mlist
.lh_TailPred
->ln_Succ
= SysBase
->KickMemPtr
;
1131 sysbase
->KickMemPtr
= (APTR
)SysBase
->KickMemPtr
;
1134 sysbase
->KickTagPtr
= kicktags
;
1135 if (SysBase
->KickTagPtr
) {
1136 ULONG
*p
= kicktags
;
1139 *p
= 0x80000000 | (ULONG
)SysBase
->KickTagPtr
;
1142 sysbase
->KickTagPtr
= SysBase
->KickTagPtr
;
1144 sysbase
->KickCheckSum
= (APTR
)mySumKickData(sysbase
, FALSE
);
1146 traps
[1] = (IPTR
)sysbase
;
1149 DebugPutStr("Rebooting.\n");
1152 // TODO: add custom cacheclear, can't call CacheClearU() because it may not work
1153 // anymore and KS 1.x does not even have it
1157 void BootROM(BPTR romlist
, struct Resident
**reslist
, struct BootStruct
*BootS
)
1161 entry
= BADDR(romlist
)+sizeof(ULONG
);
1166 DebugPutStr("Booting..\n");
1170 /* Debug testing code */
1171 if (mlist
.lh_Head
->ln_Succ
) {
1172 SysBase
->KickMemPtr
= (APTR
)mlist
.lh_Head
;
1173 mlist
.lh_TailPred
->ln_Succ
= NULL
;
1176 SysBase
->KickTagPtr
= kicktags
;
1178 mySumKickData(SysBase
, TRUE
);
1179 SysBase
->KickTagPtr
= 0;
1180 SysBase
->KickMemPtr
= 0;
1184 if ((GfxBase
= OpenLibrary("graphics.library", 0))) {
1188 CloseLibrary(GfxBase
);
1191 /* We're off in the weeds now. */
1194 Supervisor((ULONG_FUNC
)supercode
);
1198 static void DumpKickMems(ULONG num
, struct MemList
*ml
)
1201 DWriteF("Original KickMemList:\n");
1203 DWriteF("AROS KickMemList:\n");
1204 /* List is single-linked but last link gets cleared later, so test ln_Succ too */
1205 while (ml
&& ml
->ml_Node
.ln_Succ
) {
1207 DWriteF("%X8:%N\n", ml
, ml
->ml_NumEntries
);
1208 for (i
= 0; i
< ml
->ml_NumEntries
; i
++) {
1209 DWriteF(" %N: %X8, %N\n", i
, ml
->ml_ME
[i
].me_Un
.meu_Addr
, ml
->ml_ME
[i
].me_Length
);
1211 ml
= (struct MemList
*)ml
->ml_Node
.ln_Succ
;
1213 DWriteF("End of List\n");
1216 static void DumpKickTags(ULONG num
, struct Resident
**list
)
1219 DWriteF("Original KickTagList:\n");
1221 DWriteF("AROS KickTagList:\n");
1224 if ((ULONG
)list
& 0x80000000) {
1225 DWriteF("Redirected to %X8\n", (ULONG
)list
& ~0x80000000);
1226 list
= (struct Resident
**)((ULONG
)list
& ~0x80000000);
1229 bname
= ConvertCSTR((*list
)->rt_IdString
);
1230 DWriteF("%X8: %X8 %S\n", list
, *list
, bname
);
1234 DWriteF("End of List\n");
1238 #define HC_FORCEFAST 1
1239 struct HardwareConfig
1247 static const struct HardwareConfig hc
[] =
1249 { 8512, 17, "Blizzard A1200 Accelerator", HC_FORCEFAST
}, // Blizzard 1230 IV, 1240 or 1260.
1253 static void DetectHardware(void)
1255 struct ConfigDev
*cd
= NULL
;
1258 ExpansionBase
= (APTR
)OpenLibrary("expansion.library", 0);
1261 while((cd
= FindConfigDev(cd
, -1, -1))) {
1262 for (i
= 0; hc
[i
].manufacturer
; i
++) {
1263 if (cd
->cd_Rom
.er_Manufacturer
== hc
[i
].manufacturer
&& cd
->cd_Rom
.er_Product
== hc
[i
].product
) {
1265 bname
= ConvertCSTR(hc
[i
].name
);
1266 WriteF("%S: ", bname
);
1267 if (hc
[i
].flags
& HC_FORCEFAST
) {
1269 WriteF("ForceFast enabled");
1276 CloseLibrary(ExpansionBase
);
1279 static struct Resident
**ScanROMSegment(BPTR ROMSegList
, struct Resident
**resnext
, ULONG
*resleft
)
1282 /* Only scan 2nd ROM section */
1283 seg
= *((BPTR
*)BADDR(ROMSegList
));
1284 return LoadResident(seg
, resnext
, resleft
, LRF_NOPATCH
);
1287 #define KERNELTAGS_SIZE 10
1288 #define CMDLINE_SIZE 512
1290 static struct BootStruct
*AllocBootStruct(UBYTE
*cmdline
)
1292 struct TagItem
*tags
;
1293 struct BootStruct
*boots
;
1296 boots
= aosAllocMem(sizeof(struct BootStruct
) + sizeof(struct TagItem
) * KERNELTAGS_SIZE
+ CMDLINE_SIZE
, MEMF_CLEAR
, SysBase
);
1299 tags
= (struct TagItem
*)(boots
+ 1);
1300 cmd
= (UBYTE
*)(tags
+ KERNELTAGS_SIZE
);
1301 /* cmdline is a BCPL string! */
1302 if (cmdline
&& cmdline
[0])
1303 CopyMem(cmdline
+ 1, cmd
, cmdline
[0]);
1305 strcpy(cmd
, DEFAULT_KERNEL_CMDLINE
);
1306 tags
[0].ti_Tag
= KRN_CmdLine
;
1307 tags
[0].ti_Data
= (IPTR
)cmd
;
1308 tags
[1].ti_Tag
= TAG_DONE
;
1310 boots
->magic
= ABS_BOOT_MAGIC
;
1311 boots
->kerneltags
= tags
;
1313 UBYTE
*addr
= specialAlloc(SS_STACK_SIZE
+ MAGIC_FAST_SIZE
+ 1, MEMF_FAST
| MEMF_REVERSE
, SysBase
); /* +1 = guaranteed extra page at the end */
1315 addr
= (UBYTE
*)(((ULONG
)(addr
+ PAGE_SIZE
- 1)) & ~(PAGE_SIZE
- 1));
1316 boots
->ss_address
= addr
;
1317 boots
->ss_size
= SS_STACK_SIZE
;
1318 /* magic fast mem pool for early allocations that normally can't be allocated from fast memory */
1319 boots
->magicfastmem
= boots
->ss_address
+ SS_STACK_SIZE
;
1320 boots
->magicfastmemsize
= MAGIC_FAST_SIZE
;
1326 __startup
static AROS_PROCH(startup
, argstr
, argsize
, sysBase
)
1333 /* Allocate some low MEMF_CHIP ram, as a buffer
1334 * against overlapping allocations with the initial
1337 lowmem
= AllocMem(PAGE_SIZE
, MEMF_CHIP
);
1340 DOSBase
= (APTR
)OpenLibrary("dos.library", 0);
1341 if (DOSBase
!= NULL
) {
1343 BSTR name
= AROS_CONST_BSTR("aros.elf");
1344 enum { ARG_ROM
= 16, ARG_CMD
= 17, ARG_FORCECHIP
= 18, ARG_FORCEFAST
= 19, ARG_DEBUG
= 20, ARG_FORCEAROS
= 21, ARG_MODULES
= 0 };
1345 /* It would be nice to use the '/M' switch, but that
1346 * is not supported under the AOS BCPL RdArgs routine.
1348 * So only 16 modules are supported
1350 BSTR format
= AROS_CONST_BSTR(",,,,,,,,,,,,,,,,ROM/K,CMD/K,FORCECHIP/S,FORCEFAST/S,DEBUG/S,FORCEAROS/S");
1351 /* Make sure the args are in .bss, not stack */
1352 static ULONG args
[16 + 6 + 256] __attribute__((aligned(4))) = { };
1356 RdArgs(format
, MKBADDR(args
), sizeof(args
)/sizeof(args
[0]));
1358 DWriteF("ROM: %S\n", args
[ARG_ROM
]);
1359 DWriteF("CMD: %S\n", args
[ARG_CMD
]);
1360 DWriteF("FORCECHIP: %N\n", args
[ARG_FORCECHIP
]);
1361 DWriteF("FORCEFAST: %N\n", args
[ARG_FORCEFAST
]);
1362 DWriteF("MOD: %S\n", args
[0]);
1363 DWriteF(" : %S\n", args
[1]);
1364 DWriteF(" : %S\n", args
[2]);
1365 DWriteF(" : %S\n", args
[3]);
1368 forceAROS
= args
[ARG_FORCEAROS
] ? TRUE
: FALSE
;
1369 forceCHIP
= args
[ARG_FORCECHIP
] ? TRUE
: FALSE
;
1370 forceFAST
= args
[ARG_FORCEFAST
] ? TRUE
: FALSE
;
1371 debug_enabled
= args
[ARG_DEBUG
] ? TRUE
: FALSE
;
1373 /* See if we're already running on AROS.
1375 if (OpenResource("kernel.resource") != NULL
) {
1377 CloseLibrary(DOSBase
);
1378 FreeMem(lowmem
, PAGE_SIZE
);
1385 WriteF("AROSBootstrap " ADATE
"\n");
1387 WriteF("Forcing load of AROS on existing AROS\n");
1389 /* Blizzard A1200 accelerator boards have strange MAP ROM
1390 * feature, even when it is disabled, ROM is copied to
1391 * last 512K of RAM, so we have to make sure all our
1392 * allocations ignore this region.
1393 * Blizzard Fast RAM memory type is plain MEMF_FAST.
1395 if (SysBase
->LibNode
.lib_Version
>= 37 && !AvailMem(MEMF_KICK
| MEMF_FAST
)) {
1396 if (AvailMem(MEMF_FAST
)) {
1397 WriteF("Reserving non-MEMF_KICK Fast RAM\n");
1399 /* Allocate in PAGE_SIZE byte chunks, it is smallest allocated size */
1400 for (i
= 0; i
< 524288 / PAGE_SIZE
; i
++)
1401 AllocMem(PAGE_SIZE
, MEMF_FAST
| MEMF_REVERSE
);
1413 /* Load ROM image */
1414 if (args
[ARG_ROM
] == BNULL
)
1415 args
[ARG_ROM
] = name
;
1417 ROMSegList
= ROMLoad(args
[ARG_ROM
]);
1418 if (ROMSegList
!= BNULL
) {
1420 struct Resident
**ResidentList
;
1421 struct BootStruct
*BootS
;
1422 WriteF("Successfully loaded ROM\n");
1424 struct Resident
**resnext
, *reshead
= NULL
;
1426 PatchResidents(ROMSegList
);
1428 resnext
= ScanROMSegment(ROMSegList
, resnext
, &resleft
);
1429 resnext
= LoadResidents(&args
[ARG_MODULES
], resnext
, &resleft
);
1430 BootS
= AllocBootStruct(BADDR(args
[ARG_CMD
]));
1431 ResidentList
= (APTR
)((IPTR
)reshead
& ~RESLIST_NEXT
);
1434 DumpKickMems(0, SysBase
->KickMemPtr
);
1435 DumpKickMems(1, (struct MemList
*)mlist
.lh_Head
);
1436 DumpKickTags(0, SysBase
->KickTagPtr
);
1437 DumpKickTags(1, ResidentList
);
1439 WriteF("Booting...\n");
1442 BootROM(ROMSegList
, ResidentList
, BootS
);
1444 UnLoadSeg(ROMSegList
);
1446 WriteF("Can't load ROM ELF file %S\n", args
[ARG_ROM
]);
1449 WriteF("Can't parse arguments, error %N\n", IoErr());
1452 CloseLibrary((APTR
)DOSBase
);
1455 FreeMem(lowmem
, PAGE_SIZE
);