NetBSD/sys/arch/amiga/stand/loadbsd/loadbsd.c

560 lines
14 KiB
C

/*
* $Id: loadbsd.c,v 1.10 1994/05/12 05:57:33 chopps Exp $
*/
#include <sys/types.h>
#include <a.out.h>
#include <stdio.h>
#include <unistd.h>
#include <exec/types.h>
#include <exec/execbase.h>
#include <exec/memory.h>
#include <exec/resident.h>
#include <libraries/configregs.h>
#include <libraries/expansionbase.h>
#include <graphics/gfxbase.h>
#include <inline/exec.h>
#include <inline/expansion.h>
#include <inline/graphics.h>
/* Get definitions for boothowto */
#include "reboot.h"
static char usage[] =
"
NAME
\t%s - loads NetBSD from amiga dos.
SYNOPSIS
\t%s some-vmunix [-a] [-b] [-k] [-m memory] [-p] [-t] [-V]
OPTIONS
\t-a Boot up to multiuser mode.
\t-b Ask for which root device.
\t Its possible to have multiple roots and choose between them.
\t-k Reserve the first 4M of fast mem [Some one else
\t is going to have to answer what that it is used for].
\t-m Tweak amount of available memory, for finding minimum amount
\t of memory required to run. Sets fastmem size to specified
\t size in Kbytes.
\t-p Use highest priority fastmem segement instead of the largest
\t segment. The higher priority segment is usually faster
\t (i.e. 32 bit memory), but some people have smaller amounts
\t of 32 bit memory.
\t-t This is a *test* option. It prints out the memory
\t list information being passed to the kernel and also
\t exits without actually starting NetBSD.
\t-S Include kernel symbol table.
\t-D Enter debugger
\t-V Version of loadbsd program.
HISTORY
This version supports Kernel version 720 +
";
struct ExpansionBase *ExpansionBase;
struct GfxBase *GfxBase;
#undef __LDPGSZ
#define __LDPGSZ 8192
#define MAX_MEM_SEG 16
/*
* Kernel parameter passing version
* 1: first version of loadbsd
* 2: needs esym location passed in a4
*/
#define KERNEL_PARAMETER_VERSION 2
/*
* Version history:
* 1.x Kernel parameter passing version check.
* 2.0 Added symbol table end address and symbol table support.
* 2.1 03/23/94 - Round up end of fastram segment.
* Check fastram segment size for minimum of 2M.
* Use largest segment of highest priority if -p option.
* Print out fastram size in KB if not a multiple of MB.
* 2.2 03/24/94 - Zero out all unused registers.
* Started version history comment.
* 2.3 04/26/94 - Added -D option to enter debugger on boot.
* 2.4 04/30/94 - Cpuid includes base machine type.
* Also check if CPU is capable of running NetBSD.
*/
struct MEM_LIST {
u_long num_mem;
struct MEM_SEG {
u_long mem_start;
u_long mem_size;
u_short mem_attrib;
short mem_prio;
} mem_seg[MAX_MEM_SEG];
} mem_list, *kmem_list;
int k_opt;
int a_opt;
int b_opt;
int p_opt;
int t_opt;
int m_opt;
int S_opt;
int D_opt;
u_long cpuid;
extern char *optarg;
extern int optind;
void get_mem_config (void **fastmem_start, u_long *fastmem_size, u_long *chipmem_size);
void get_cpuid (void);
void Usage (char *program_name);
void Version (void);
static const char _version[] = "$VER: LoadBSD 2.4 (30.4.94)";
int
main (int argc, char *argv[])
{
struct exec e;
int fd;
int boothowto = RB_SINGLE;
if (argc >= 2)
{
if ((fd = open (argv[1], 0)) >= 0)
{
if (read (fd, &e, sizeof (e)) == sizeof (e))
{
if (e.a_magic == NMAGIC)
{
u_char *kernel;
int kernel_size;
int text_size;
struct ConfigDev *cd;
int num_cd;
void *fastmem_start;
u_long fastmem_size, chipmem_size;
int i;
u_short *kern_vers;
char *esym;
int string_size;
GfxBase = (struct GfxBase *) OpenLibrary ("graphics.library", 0);
if (! GfxBase) /* not supposed to fail... */
abort();
ExpansionBase= (struct ExpansionBase *) OpenLibrary ("expansion.library", 0);
if (! ExpansionBase) /* not supposed to fail... */
abort();
optind = 2;
while ((i = getopt (argc, argv, "kabptVm:SD")) != EOF)
switch (i) {
case 'k':
k_opt = 1;
break;
case 'a':
a_opt = 1;
break;
case 'b':
b_opt = 1;
break;
case 'p':
p_opt = 1;
break;
case 't':
t_opt = 1;
break;
case 'm':
m_opt = atoi (optarg) * 1024;
break;
case 'V':
Version();
break;
case 'S':
S_opt = 1;
break;
case 'D':
D_opt = 1;
break;
default:
Usage(argv[0]);
fprintf(stderr,"Unrecognized option \n");
exit(-1);
}
for (cd = 0, num_cd = 0; cd = FindConfigDev (cd, -1, -1); num_cd++) ;
get_mem_config (&fastmem_start, &fastmem_size, &chipmem_size);
get_cpuid ();
text_size = (e.a_text + __LDPGSZ - 1) & (-__LDPGSZ);
esym = NULL;
kernel_size = text_size + e.a_data + e.a_bss
+ num_cd*sizeof(*cd) + 4
+ mem_list.num_mem*sizeof(struct MEM_SEG) + 4;
/*
* get symbol table size & string size
* (should check kernel version to see if it will handle it)
*/
if (S_opt && e.a_syms) {
S_opt = 0; /* prepare for failure */
if (lseek(fd, e.a_text + e.a_data + e.a_syms, SEEK_CUR) > 0) {
if (read (fd, &string_size, 4) == 4) {
if (lseek(fd, sizeof(e), SEEK_SET) < 0) {
printf ("Error repositioning to text\n");
exit(0); /* Give up! */
}
kernel_size += e.a_syms + 4 + string_size;
S_opt = 1; /* sucess! Keep -S option */
}
}
}
kernel = (u_char *) malloc (kernel_size);
if (t_opt)
for (i = 0; i < mem_list.num_mem; ++i) {
printf ("mem segment %d: start=%08lx size=%08lx attribute=%04lx pri=%d\n",
i + 1, mem_list.mem_seg[i].mem_start,
mem_list.mem_seg[i].mem_size,
mem_list.mem_seg[i].mem_attrib,
mem_list.mem_seg[i].mem_prio);
}
if (kernel)
{
if (read (fd, kernel, e.a_text) == e.a_text
&& read (fd, kernel + text_size, e.a_data) == e.a_data)
{
int *knum_cd;
struct ConfigDev *kcd;
int mem_ix;
if (k_opt)
{
fastmem_start += 4*1024*1024;
fastmem_size -= 4*1024*1024;
}
if (m_opt && m_opt <= fastmem_size)
{
fastmem_size = m_opt;
}
if (a_opt)
{
printf("Autobooting...");
boothowto = RB_AUTOBOOT;
}
if (b_opt)
{
printf("Askboot...");
boothowto |= RB_ASKNAME;
}
if (D_opt)
{
boothowto |= RB_KDB;
}
printf ("Using %d%c FASTMEM at 0x%x, %dM CHIPMEM\n",
(fastmem_size & 0xfffff) ? fastmem_size>>10 :
fastmem_size>>20,
(fastmem_size & 0xfffff) ? 'K' : 'M',
fastmem_start, chipmem_size>>20);
kern_vers = (u_short *) (kernel + e.a_entry - 2);
if (*kern_vers > KERNEL_PARAMETER_VERSION &&
*kern_vers != 0x4e73)
{
printf ("This kernel requires a newer version of loadbsd: %d\n", *kern_vers);
exit (0);
}
if ((cpuid & AFB_68020) == 0)
{
printf ("Hmmm... You don't seem to have a CPU capable\n");
printf (" of running NetBSD. You need a 68020\n");
printf (" or better\n");
exit (0);
}
/* give them a chance to read the information... */
sleep(2);
bzero (kernel + text_size + e.a_data, e.a_bss);
/*
* If symbols wanted (and kernel can handle them),
* load symbol table & strings and set esym to end.
*/
knum_cd = (int *) (kernel + text_size + e.a_data + e.a_bss);
if (*kern_vers != 0x4e73 && *kern_vers > 1 && S_opt && e.a_syms) {
*knum_cd++ = e.a_syms;
read(fd, (char *)knum_cd, e.a_syms);
knum_cd = (int *)((char *)knum_cd + e.a_syms);
read(fd, (char *)knum_cd, string_size);
knum_cd = (int*)((char *)knum_cd + string_size);
esym = (char *) (text_size + e.a_data + e.a_bss
+ e.a_syms + 4 + string_size);
}
*knum_cd = num_cd;
for (kcd = (struct ConfigDev *) (knum_cd+1);
cd = FindConfigDev (cd, -1, -1);
*kcd++ = *cd)
;
kmem_list = (struct MEM_LIST *)kcd;
kmem_list->num_mem = mem_list.num_mem;
for (mem_ix = 0; mem_ix < mem_list.num_mem; mem_ix++)
kmem_list->mem_seg[mem_ix] = mem_list.mem_seg[mem_ix];
if (t_opt) /* if test option */
exit (0); /* don't start kernel */
/* AGA startup - may need more */
LoadView (NULL);
startit (kernel, kernel_size,
e.a_entry, fastmem_start,
fastmem_size, chipmem_size,
boothowto, esym, cpuid );
}
else
fprintf (stderr, "Executable corrupt!\n");
}
else
fprintf (stderr, "Out of memory! (%d)\n", text_size + e.a_data + e.a_bss
+ num_cd*sizeof(*cd) + 4
+ mem_list.num_mem*sizeof(struct MEM_SEG) + 4);
}
else
fprintf (stderr, "Unsupported executable: %o\n", e.a_magic);
}
else
fprintf (stderr, "Can't read header of %s\n", argv[1]);
close (fd);
}
else
perror ("open");
}
else
Usage(argv[0]);
Version();
}/* main() */
void
get_mem_config (void **fastmem_start, u_long *fastmem_size, u_long *chipmem_size)
{
extern struct ExecBase *SysBase;
struct MemHeader *mh, *nmh;
int num_mem = 0;
u_int seg_size;
u_int seg_start;
u_int seg_end;
char mem_pri = -128;
*fastmem_size = 0;
*chipmem_size = 0;
/* walk thru the exec memory list */
Forbid ();
for (mh = (struct MemHeader *) SysBase->MemList.lh_Head;
nmh = (struct MemHeader *) mh->mh_Node.ln_Succ;
mh = nmh, num_mem++)
{
mem_list.mem_seg[num_mem].mem_attrib = mh->mh_Attributes;
mem_list.mem_seg[num_mem].mem_prio = mh->mh_Node.ln_Pri;
seg_start = (u_int)mh->mh_Lower;
seg_end = (u_int)mh->mh_Upper;
seg_size = seg_end - seg_start;
mem_list.mem_seg[num_mem].mem_size = seg_size;
mem_list.mem_seg[num_mem].mem_start = seg_start;
if (mh->mh_Attributes & MEMF_CHIP)
{
/* there should hardly be more than one entry for chip mem, but
handle it the same nevertheless */
/* chipmem always starts at 0, so include vector area */
mem_list.mem_seg[num_mem].mem_start = seg_start = 0;
/* round to multiple of 512K */
seg_size = (seg_size + 512*1024 - 1) & -(512*1024);
mem_list.mem_seg[num_mem].mem_size = seg_size;
if (seg_size > *chipmem_size)
{
*chipmem_size = seg_size;
}
}
else
{
/* some heuristics.. */
seg_start &= -__LDPGSZ;
seg_end = (seg_end + __LDPGSZ - 1) & -__LDPGSZ;
/* get the mem back stolen by incore kickstart on A3000 with
V36 bootrom. */
if (seg_end == 0x07f80000)
seg_end = 0x08000000;
/* or by zkick on a A2000. */
if (seg_start == 0x280000
&& strcmp (mh->mh_Node.ln_Name, "zkick memory") == 0)
seg_start = 0x200000;
seg_size = seg_end - seg_start;
mem_list.mem_seg[num_mem].mem_start = seg_start;
mem_list.mem_seg[num_mem].mem_size = seg_size;
/*
* If this segment is smaller than 2M,
* don't use it to load the kernel
*/
if (seg_size < 2 * 1024 * 1024)
continue;
/* if p_opt is set, select memory by priority instead of size */
if ((!p_opt && seg_size > *fastmem_size) ||
(p_opt && mem_pri <= mh->mh_Node.ln_Pri && seg_size > *fastmem_size))
{
*fastmem_size = seg_size;
*fastmem_start = (void *)seg_start;
mem_pri = mh->mh_Node.ln_Pri;
}
}
}
mem_list.num_mem = num_mem;
Permit();
}
/*
* Try to determine the machine ID by searching the resident module list
* for modules only present on specific machines. (Thanks, Bill!)
*/
void
get_cpuid ()
{
extern struct ExecBase *SysBase;
u_long *rl;
struct Resident *rm;
cpuid = SysBase->AttnFlags; /* get FPU and CPU flags */
rl = (u_long *) SysBase->ResModules;
if (rl == NULL)
return;
while (*rl) {
rm = (struct Resident *) *rl;
if (strcmp (rm->rt_Name, "A4000 Bonus") == 0 ||
strcmp (rm->rt_Name, "A1000 Bonus") == 0) {
cpuid |= 4000 << 16;
break;
}
if (strcmp (rm->rt_Name, "A3000 Bonus") == 0) {
cpuid |= 3000 << 16;
break;
}
if (strcmp (rm->rt_Name, "card.resource") == 0) {
cpuid |= 1200 << 16; /* or A600 :-) */
break;
}
++rl;
}
if (*rl == 0) /* Nothing found, it's probably an A2000 or A500 */
cpuid |= 2000 << 16;
}
asm ("
.set ABSEXECBASE,4
.text
.globl _startit
_startit:
movel sp,a3
movel 4:w,a6
lea pc@(start_super-.+2),a5
jmp a6@(-0x1e) | supervisor-call
start_super:
movew #0x2700,sr
| the BSD kernel wants values into the following registers:
| a0: fastmem-start
| d0: fastmem-size
| d1: chipmem-size
| d5: AttnFlags (cpuid)
| d7: boothowto
| a4: esym location
| All other registers zeroed for possible future requirements.
movel a3@(4),a1 | loaded kernel
movel a3@(8),d2 | length of loaded kernel
movel a3@(12),sp@- | entry point [save on stack for rts]
movel a3@(16),a0 | fastmem-start
movel a3@(20),d0 | fastmem-size
movel a3@(24),d1 | chipmem-size
movel a3@(28),d7 | boothowto
movel a3@(32),a4 | esym
movel a3@(36),d5 | cpuid
subl a5,a5 | target, load to 0
btst #3,(ABSEXECBASE)@(0x129) | AFB_68040,SysBase->AttnFlags
beq not040
| Turn off 68040 MMU
.word 0x4e7b,0xd003 | movec a5,tc
.word 0x4e7b,0xd806 | movec a5,urp
.word 0x4e7b,0xd807 | movec a5,srp
.word 0x4e7b,0xd004 | movec a5,itt0
.word 0x4e7b,0xd005 | movec a5,itt1
.word 0x4e7b,0xd006 | movec a5,dtt0
.word 0x4e7b,0xd007 | movec a5,dtt1
bra nott
not040:
lea pc@(zero-.+2),a3
pmove a3@,tc | Turn off MMU
lea pc@(nullrp-.+2),a3
pmove a3@,crp | Turn off MMU some more
pmove a3@,srp | Really, really, turn off MMU
| Turn off 68030 TT registers
btst #2,(ABSEXECBASE)@(0x129) | AFB_68030,SysBase->AttnFlags
beq nott | Skip TT registers if not 68030
lea pc@(zero-.+2),a3
.word 0xf013,0x0800 | pmove a3@,tt0 (gas only knows about 68851 ops..)
.word 0xf013,0x0c00 | pmove a3@,tt1 (gas only knows about 68851 ops..)
nott:
movew #(1<<9),0xdff096 | disable DMA
L0:
moveb a1@+,a5@+
subl #1,d2
bcc L0
moveq #0,d2 | zero out unused registers
moveq #0,d3 | (might make future compatibility
moveq #0,d4 | a little easier, since all registers
moveq #0,d6 | would have known contents)
movel d6,a1
movel d6,a2
movel d6,a3
movel d6,a5
movel d6,a6
rts | return to kernel entry point
| A do-nothing MMU root pointer (includes the following long as well)
nullrp: .long 0x7fff0001
zero: .long 0
");
void Usage(char *program_name)
{
fprintf(stderr,usage,program_name,program_name);
}
void Version()
{
fprintf(stderr,"%s\n",_version + 6);
}