summaryrefslogtreecommitdiffstats
path: root/arch/m68k/boot
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-01-07 02:33:00 +0000
committer <ralf@linux-mips.org>1997-01-07 02:33:00 +0000
commitbeb116954b9b7f3bb56412b2494b562f02b864b1 (patch)
tree120e997879884e1b9d93b265221b939d2ef1ade1 /arch/m68k/boot
parent908d4681a1dc3792ecafbe64265783a86c4cccb6 (diff)
Import of Linux/MIPS 2.1.14
Diffstat (limited to 'arch/m68k/boot')
-rw-r--r--arch/m68k/boot/Makefile62
-rw-r--r--arch/m68k/boot/amiga/bootstrap.c333
-rw-r--r--arch/m68k/boot/amiga/bootstrap.h175
-rw-r--r--arch/m68k/boot/amiga/linuxboot.c1128
-rw-r--r--arch/m68k/boot/amiga/linuxboot.h427
-rw-r--r--arch/m68k/boot/atari/bootp.c793
-rw-r--r--arch/m68k/boot/atari/bootp.h44
-rw-r--r--arch/m68k/boot/atari/bootstrap.c1083
-rw-r--r--arch/m68k/boot/atari/bootstrap.h147
-rw-r--r--arch/m68k/boot/atari/ethlance.c435
-rw-r--r--arch/m68k/boot/atari/ethlance.h7
-rw-r--r--arch/m68k/boot/atari/sysvars.h22
12 files changed, 4656 insertions, 0 deletions
diff --git a/arch/m68k/boot/Makefile b/arch/m68k/boot/Makefile
new file mode 100644
index 000000000..e67a9c4d1
--- /dev/null
+++ b/arch/m68k/boot/Makefile
@@ -0,0 +1,62 @@
+#
+# linux/arch/m68k/boot/Makefile
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+
+ifdef CONFIG_AMIGA
+AMIGA_BOOTSTRAP = amiga_bootstrap
+AMIGA_BOOTOBJS := amiga/bootstrap.o amiga/linuxboot.o
+AMIGA_HOSTCC = m68k-cbm-amigados-gcc -I$(TOPDIR)/include
+AMIGA_HOSTFLAGS=-m68030 -O2 -Wall -Dlinux
+endif
+
+ifdef CONFIG_ATARI
+ATARI_BOOTSTRAP = atari_bootstrap
+ATARI_BOOTOBJS := atari/bootstrap.o
+ATARI_HOSTCC = m68k-mint-gcc -I$(TOPDIR)/include
+ATARI_HOSTFLAGS = -m68030 -m68881 -Dlinux -O2 -Wall
+
+# BOOTP/TFTP support in bootstrap?
+# USE_BOOTP = y
+
+ifdef USE_BOOTP
+ATARI_BOOTOBJS += atari/bootp.o
+ATARI_HOSTFLAGS += -DUSE_BOOTP
+
+# low-level Ethernet drivers:
+
+# Lance (RieblCard, PAM-VME)
+ATARI_BOOTOBJS += atari/ethlance.o
+ATARI_HOSTFLAGS += -DETHLL_LANCE
+
+endif
+endif
+
+ifdef CONFIG_ATARI
+atari_bootstrap: $(ATARI_BOOTOBJS)
+ $(ATARI_HOSTCC) $(ATARI_HOSTFLAGS) -o $@ $(ATARI_BOOTOBJS)
+ rm -f ../../../bootstrap
+ ln $@ ../../../bootstrap
+endif
+
+ifdef CONFIG_AMIGA
+amiga_bootstrap: $(AMIGA_BOOTOBJS)
+ $(AMIGA_HOSTCC) $(AMIGA_HOSTFLAGS) -o $@ -s -noixemul $(AMIGA_BOOTOBJS)
+ rm -f ../../../bootstrap
+ ln $@ ../../../bootstrap
+endif
+
+$(AMIGA_BOOTOBJS): %.o: %.c
+ $(AMIGA_HOSTCC) $(AMIGA_HOSTFLAGS) -c $< -o $@
+
+$(ATARI_BOOTOBJS): %.o: %.c
+ $(ATARI_HOSTCC) $(ATARI_HOSTFLAGS) -c $< -o $@
+
+bootstrap: $(AMIGA_BOOTSTRAP) $(ATARI_BOOTSTRAP)
+
+clean:
+ rm -f *.o amiga/*.o atari/*.o amiga_bootstrap atari_bootstrap
+
+dep:
diff --git a/arch/m68k/boot/amiga/bootstrap.c b/arch/m68k/boot/amiga/bootstrap.c
new file mode 100644
index 000000000..20ca0621f
--- /dev/null
+++ b/arch/m68k/boot/amiga/bootstrap.c
@@ -0,0 +1,333 @@
+/*
+** linux/arch/m68k/boot/amiga/bootstrap.c -- This program loads the Linux/m68k
+** kernel into an Amiga and launches
+** it.
+**
+** Copyright 1993,1994 by Hamish Macdonald, Greg Harp
+**
+** Modified 11-May-94 by Geert Uytterhoeven
+** (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+** - A3640 MapROM check
+** Modified 31-May-94 by Geert Uytterhoeven
+** - Memory thrash problem solved
+** Modified 07-March-95 by Geert Uytterhoeven
+** - Memory block sizes are rounded to a multiple of 256K instead of 1M
+** This _requires_ >0.9pl5 to work!
+** (unless all block sizes are multiples of 1M :-)
+** Modified 11-July-95 by Andreas Schwab
+** - Support for ELF kernel (untested!)
+** Modified 10-Jan-96 by Geert Uytterhoeven
+** - The real Linux/m68k boot code moved to linuxboot.[ch]
+** Modified 9-Sep-96 by Geert Uytterhoeven
+** - Rewritten option parsing
+** - New parameter passing to linuxboot() (linuxboot_args)
+**
+** This file is subject to the terms and conditions of the GNU General Public
+** License. See the file COPYING in the main directory of this archive
+** for more details.
+**
+*/
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/file.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+/* required Linux/m68k include files */
+#include <linux/a.out.h>
+#include <linux/elf.h>
+#include <asm/setup.h>
+#include <asm/page.h>
+
+/* Amiga bootstrap include files */
+#include "linuxboot.h"
+#include "bootstrap.h"
+
+
+/* Library Bases */
+extern const struct ExecBase *SysBase;
+const struct ExpansionBase *ExpansionBase;
+const struct GfxBase *GfxBase;
+
+static const char *memfile_name = NULL;
+
+static int model = AMI_UNKNOWN;
+
+static const char *ProgramName;
+
+struct linuxboot_args args;
+
+
+ /*
+ * Function Prototypes
+ */
+
+static void Usage(void) __attribute__ ((noreturn));
+int main(int argc, char *argv[]);
+static void Puts(const char *str);
+static long GetChar(void);
+static void PutChar(char c);
+static void Printf(const char *fmt, ...);
+static int Open(const char *path);
+static int Seek(int fd, int offset);
+static int Read(int fd, char *buf, int count);
+static void Close(int fd);
+static int FileSize(const char *path);
+static void Sleep(u_long micros);
+static int ModifyBootinfo(struct bootinfo *bi);
+
+
+static void Usage(void)
+{
+ fprintf(stderr,
+ "Linux/m68k Amiga Bootstrap version " AMIBOOT_VERSION "\n\n"
+ "Usage: %s [options] [kernel command line]\n\n"
+ "Valid options are:\n"
+ " -h, --help Display this usage information\n"
+ " -k, --kernel file Use kernel image `file' (default is `vmlinux')\n"
+ " -r, --ramdisk file Use ramdisk image `file'\n"
+ " -d, --debug Enable debug mode\n"
+ " -m, --memfile file Use memory file `file'\n"
+ " -v, --keep-video Don't reset the video mode\n"
+ " -t, --model id Set the Amiga model to `id'\n\n",
+ ProgramName);
+ exit(EXIT_FAILURE);
+}
+
+
+int main(int argc, char *argv[])
+{
+ int i;
+ int debugflag = 0, keep_video = 0;
+ const char *kernel_name = NULL;
+ const char *ramdisk_name = NULL;
+ char commandline[CL_SIZE] = "";
+
+ ProgramName = argv[0];
+ while (--argc) {
+ argv++;
+ if (!strcmp(argv[0], "-h") || !strcmp(argv[0], "--help"))
+ Usage();
+ else if (!strcmp(argv[0], "-k") || !strcmp(argv[0], "--kernel"))
+ if (--argc && !kernel_name) {
+ kernel_name = argv[1];
+ argv++;
+ } else
+ Usage();
+ else if (!strcmp(argv[0], "-r") || !strcmp(argv[0], "--ramdisk"))
+ if (--argc && !ramdisk_name) {
+ ramdisk_name = argv[1];
+ argv++;
+ } else
+ Usage();
+ else if (!strcmp(argv[0], "-d") || !strcmp(argv[0], "--debug"))
+ debugflag = 1;
+ else if (!strcmp(argv[0], "-m") || !strcmp(argv[0], "--memfile"))
+ if (--argc && !memfile_name) {
+ memfile_name = argv[1];
+ argv++;
+ } else
+ Usage();
+ else if (!strcmp(argv[0], "-v") || !strcmp(argv[0], "--keep-video"))
+ keep_video = 1;
+ else if (!strcmp(argv[0], "-t") || !strcmp(argv[0], "--model"))
+ if (--argc && !model) {
+ model = atoi(argv[1]);
+ argv++;
+ } else
+ Usage();
+ else
+ break;
+ }
+ if (!kernel_name)
+ kernel_name = "vmlinux";
+
+ SysBase = *(struct ExecBase **)4;
+
+ /* open Expansion Library */
+ ExpansionBase = (struct ExpansionBase *)OpenLibrary("expansion.library",
+ 36);
+ if (!ExpansionBase) {
+ fputs("Unable to open expansion.library V36 or greater! Aborting...\n",
+ stderr);
+ exit(EXIT_FAILURE);
+ }
+
+ /* open Graphics Library */
+ GfxBase = (struct GfxBase *)OpenLibrary ("graphics.library", 0);
+ if (!GfxBase) {
+ fputs("Unable to open graphics.library! Aborting...\n", stderr);
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * Join command line options
+ */
+ i = 0;
+ while (argc--) {
+ if ((i+strlen(*argv)+1) < CL_SIZE) {
+ i += strlen(*argv) + 1;
+ if (commandline[0])
+ strcat(commandline, " ");
+ strcat(commandline, *argv++);
+ }
+ }
+
+ args.kernelname = kernel_name;
+ args.ramdiskname = ramdisk_name;
+ args.commandline = commandline;
+ args.debugflag = debugflag;
+ args.keep_video = keep_video;
+ args.reset_boards = 1;
+ args.puts = Puts;
+ args.getchar = GetChar;
+ args.putchar = PutChar;
+ args.printf = Printf;
+ args.open = Open;
+ args.seek = Seek;
+ args.read = Read;
+ args.close = Close;
+ args.filesize = FileSize;
+ args.sleep = Sleep;
+ args.modify_bootinfo = ModifyBootinfo;
+
+ /* Do The Right Stuff */
+ linuxboot(&args);
+
+ CloseLibrary((struct Library *)GfxBase);
+ CloseLibrary((struct Library *)ExpansionBase);
+
+ /* if we ever get here, something went wrong */
+ exit(EXIT_FAILURE);
+}
+
+
+ /*
+ * Routines needed by linuxboot
+ */
+
+static void Puts(const char *str)
+{
+ fputs(str, stderr);
+}
+
+static long GetChar(void)
+{
+ return(getchar());
+}
+
+static void PutChar(char c)
+{
+ fputc(c, stderr);
+}
+
+static void Printf(const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+}
+
+static int Open(const char *path)
+{
+ return(open(path, O_RDONLY));
+}
+
+static int Seek(int fd, int offset)
+{
+ return(lseek(fd, offset, SEEK_SET));
+}
+
+
+static int Read(int fd, char *buf, int count)
+{
+ return(read(fd, buf, count));
+}
+
+static void Close(int fd)
+{
+ close(fd);
+}
+
+static int FileSize(const char *path)
+{
+ int fd, size = -1;
+
+ if ((fd = open(path, O_RDONLY)) != -1) {
+ size = lseek(fd, 0, SEEK_END);
+ close(fd);
+ }
+ return(size);
+}
+
+static void Sleep(u_long micros)
+{
+ struct MsgPort *TimerPort;
+ struct timerequest *TimerRequest;
+
+ if ((TimerPort = CreateMsgPort())) {
+ if ((TimerRequest = CreateIORequest(TimerPort,
+ sizeof(struct timerequest)))) {
+ if (!OpenDevice("timer.device", UNIT_VBLANK,
+ (struct IORequest *)TimerRequest, 0)) {
+ TimerRequest->io_Command = TR_ADDREQUEST;
+ TimerRequest->io_Flags = IOF_QUICK;
+ TimerRequest->tv_secs = micros/1000000;
+ TimerRequest->tv_micro = micros%1000000;
+ DoIO((struct IORequest *)TimerRequest);
+ CloseDevice((struct IORequest *)TimerRequest);
+ }
+ DeleteIORequest(TimerRequest);
+ }
+ DeleteMsgPort(TimerPort);
+ }
+}
+
+
+static int ModifyBootinfo(struct bootinfo *bi)
+{
+ /*
+ * if we have a memory file, read the memory information from it
+ */
+ if (memfile_name) {
+ FILE *fp;
+ int i;
+
+ if ((fp = fopen(memfile_name, "r")) == NULL) {
+ perror("open memory file");
+ fprintf(stderr, "Cannot open memory file %s\n", memfile_name);
+ return(FALSE);
+ }
+
+ if (fscanf(fp, "%lu", &bi->bi_amiga.chip_size) != 1) {
+ fprintf(stderr, "memory file does not contain chip memory size\n");
+ fclose(fp);
+ return(FALSE);
+ }
+
+ for (i = 0; i < NUM_MEMINFO; i++) {
+ if (fscanf(fp, "%lx %lu", &bi->memory[i].addr, &bi->memory[i].size)
+ != 2)
+ break;
+ }
+
+ fclose(fp);
+
+ if (i != bi->num_memory && i > 0)
+ bi->num_memory = i;
+ }
+
+ /*
+ * change the Amiga model, if necessary
+ */
+ if (model != AMI_UNKNOWN)
+ bi->bi_amiga.model = model;
+
+ return(TRUE);
+}
diff --git a/arch/m68k/boot/amiga/bootstrap.h b/arch/m68k/boot/amiga/bootstrap.h
new file mode 100644
index 000000000..d7a5c44fd
--- /dev/null
+++ b/arch/m68k/boot/amiga/bootstrap.h
@@ -0,0 +1,175 @@
+/*
+** linux/arch/m68k/boot/amiga/bootstrap.h -- This file is part of the Amiga
+** bootloader.
+**
+** Copyright 1993, 1994 by Hamish Macdonald
+**
+** Some minor additions by Michael Rausch 1-11-94
+** Modified 11-May-94 by Geert Uytterhoeven
+** (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+** - inline Supervisor() call
+** Modified 10-Jan-96 by Geert Uytterhoeven
+** - The real Linux/m68k boot code moved to linuxboot.[ch]
+** Modified 9-Sep-96 by Geert Uytterhoeven
+** - const library bases
+** - fixed register naming for m68k-cbm-amigados-gcc
+**
+** This file is subject to the terms and conditions of the GNU General Public
+** License. See the file COPYING in the main directory of this archive
+** for more details.
+**
+*/
+
+#include <asm/amigatypes.h>
+
+
+struct MsgPort {
+ u_char fill1[15];
+ u_char mp_SigBit;
+ u_char fill2[18];
+};
+
+struct IOStdReq {
+ u_char fill1[20];
+ struct Device *io_Device;
+ u_char fill2[4];
+ u_short io_Command;
+ u_char io_Flags;
+ char io_Error;
+ u_long io_Actual;
+ u_long io_Length;
+ void *io_Data;
+ u_char fill4[4];
+};
+
+#define IOF_QUICK (1<<0)
+
+struct timerequest {
+ u_char fill1[28];
+ u_short io_Command;
+ u_char io_Flags;
+ u_char fill2[1];
+ u_long tv_secs;
+ u_long tv_micro;
+};
+
+#define UNIT_VBLANK 1
+#define TR_ADDREQUEST 9
+
+
+struct Library;
+struct IORequest;
+
+
+static __inline void CloseLibrary(struct Library *library)
+{
+ register const struct ExecBase *a6 __asm("a6") = SysBase;
+ register struct Library *a1 __asm("a1") = library;
+ __asm __volatile ("jsr a6@(-0x19e)"
+ : /* no output */
+ : "r" (a6), "r" (a1)
+ : "a0","a1","d0","d1", "memory");
+}
+
+static __inline struct Library *OpenLibrary(char *libName,
+ unsigned long version)
+{
+ register struct Library * _res __asm("d0");
+ register const struct ExecBase *a6 __asm("a6") = SysBase;
+ register u_char *a1 __asm("a1") = libName;
+ register unsigned long d0 __asm("d0") = version;
+ __asm __volatile ("jsr a6@(-0x228)"
+ : "=r" (_res)
+ : "r" (a6), "r" (a1), "r" (d0)
+ : "a0","a1","d0","d1", "memory");
+ return _res;
+}
+
+static __inline char OpenDevice(u_char *devName, u_long unit,
+ struct IORequest *ioRequest, u_long flags)
+{
+ register char _res __asm("d0");
+ register const struct ExecBase *a6 __asm("a6") = SysBase;
+ register u_char *a0 __asm("a0") = devName;
+ register u_long d0 __asm("d0") = unit;
+ register struct IORequest *a1 __asm("a1") = ioRequest;
+ register u_long d1 __asm("d1") = flags;
+
+ __asm __volatile ("jsr a6@(-0x1bc)"
+ : "=r" (_res)
+ : "r" (a6), "r" (a0), "r" (a1), "r" (d0), "r" (d1)
+ : "a0","a1","d0","d1", "memory");
+ return(_res);
+}
+
+static __inline void CloseDevice(struct IORequest *ioRequest)
+{
+ register const struct ExecBase *a6 __asm("a6") = SysBase;
+ register struct IORequest *a1 __asm("a1") = ioRequest;
+
+ __asm __volatile ("jsr a6@(-0x1c2)"
+ : /* no output */
+ : "r" (a6), "r" (a1)
+ : "a0","a1","d0","d1", "memory");
+}
+
+static __inline char DoIO(struct IORequest *ioRequest)
+{
+ register char _res __asm("d0");
+ register const struct ExecBase *a6 __asm("a6") = SysBase;
+ register struct IORequest *a1 __asm("a1") = ioRequest;
+
+ __asm __volatile ("jsr a6@(-0x1c8)"
+ : "=r" (_res)
+ : "r" (a6), "r" (a1)
+ : "a0","a1","d0","d1", "memory");
+ return(_res);
+}
+
+static __inline void *CreateIORequest(struct MsgPort *port, u_long size)
+{
+ register struct Library *_res __asm("d0");
+ register const struct ExecBase *a6 __asm("a6") = SysBase;
+ register struct MsgPort *a0 __asm("a0") = port;
+ register u_long d0 __asm("d0") = size;
+
+ __asm __volatile ("jsr a6@(-0x28e)"
+ : "=r" (_res)
+ : "r" (a6), "r" (a0), "r" (d0)
+ : "a0","a1","d0","d1", "memory");
+ return(_res);
+}
+
+static __inline void DeleteIORequest(void *ioRequest)
+{
+ register const struct ExecBase *a6 __asm("a6") = SysBase;
+ register void *a0 __asm("a0") = ioRequest;
+
+ __asm __volatile ("jsr a6@(-0x294)"
+ : /* no output */
+ : "r" (a6), "r" (a0)
+ : "a0","a1","d0","d1", "memory");
+}
+
+static __inline struct MsgPort *CreateMsgPort(void)
+{
+ register struct MsgPort *_res __asm("d0");
+ register const struct ExecBase *a6 __asm("a6") = SysBase;
+
+ __asm __volatile ("jsr a6@(-0x29a)"
+ : "=r" (_res)
+ : "r" (a6)
+ : "a0","a1","d0","d1", "memory");
+ return(_res);
+}
+
+static __inline void DeleteMsgPort(struct MsgPort *port)
+{
+ register const struct ExecBase *a6 __asm("a6") = SysBase;
+ register struct MsgPort *a0 __asm("a0") = port;
+
+ __asm __volatile ("jsr a6@(-0x2a0)"
+ : /* no output */
+ : "r" (a6), "r" (a0)
+ : "a0","a1","d0","d1", "memory");
+}
diff --git a/arch/m68k/boot/amiga/linuxboot.c b/arch/m68k/boot/amiga/linuxboot.c
new file mode 100644
index 000000000..975868c45
--- /dev/null
+++ b/arch/m68k/boot/amiga/linuxboot.c
@@ -0,0 +1,1128 @@
+/*
+ * linux/arch/m68k/boot/amiga/linuxboot.c -- Generic routine to boot Linux/m68k
+ * on Amiga, used by both Amiboot and
+ * Amiga-Lilo.
+ *
+ * Created 1996 by Geert Uytterhoeven
+ *
+ *
+ * This file is based on the original bootstrap code (bootstrap.c):
+ *
+ * Copyright (C) 1993, 1994 Hamish Macdonald
+ * Greg Harp
+ *
+ * with work by Michael Rausch
+ * Geert Uytterhoeven
+ * Frank Neumann
+ * Andreas Schwab
+ *
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+
+#ifndef __GNUC__
+#error GNU CC is required to compile this program
+#endif /* __GNUC__ */
+
+
+#include <stddef.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include <linux/a.out.h>
+#include <linux/elf.h>
+#include <linux/linkage.h>
+#include <asm/setup.h>
+#include <asm/amigatypes.h>
+#include <asm/amigahw.h>
+#include <asm/page.h>
+
+#include "linuxboot.h"
+
+
+#undef custom
+#define custom ((*(volatile struct CUSTOM *)(CUSTOM_PHYSADDR)))
+
+/* temporary stack size */
+#define TEMP_STACKSIZE (256)
+
+extern char copyall, copyallend;
+
+static struct exec kexec;
+static Elf32_Ehdr kexec_elf;
+static struct bootinfo bi;
+
+static const struct linuxboot_args *linuxboot_args;
+
+#define kernelname linuxboot_args->kernelname
+#define ramdiskname linuxboot_args->ramdiskname
+#define commandline linuxboot_args->commandline
+#define debugflag linuxboot_args->debugflag
+#define keep_video linuxboot_args->keep_video
+#define reset_boards linuxboot_args->reset_boards
+
+#define Puts linuxboot_args->puts
+#define GetChar linuxboot_args->getchar
+#define PutChar linuxboot_args->putchar
+#define Printf linuxboot_args->printf
+#define Open linuxboot_args->open
+#define Seek linuxboot_args->seek
+#define Read linuxboot_args->read
+#define Close linuxboot_args->close
+#define FileSize linuxboot_args->filesize
+#define Sleep linuxboot_args->sleep
+#define ModifyBootinfo linuxboot_args->modify_bootinfo
+
+
+ /*
+ * Function Prototypes
+ */
+
+static u_long get_chipset(void);
+static u_long get_cpu(void);
+static u_long get_model(u_long chipset);
+static int probe_resident(const char *name);
+static int probe_resource(const char *name);
+static int check_bootinfo_version(const char *memptr);
+static void start_kernel(void (*startfunc)(), char *stackp, char *memptr,
+ u_long start_mem, u_long mem_size, u_long rd_size,
+ u_long kernel_size) __attribute__ ((noreturn));
+asmlinkage u_long maprommed(void);
+
+
+ /*
+ * Reset functions for nasty Zorro boards
+ */
+
+static void reset_rb3(const struct ConfigDev *cd);
+static void reset_piccolo(const struct ConfigDev *cd);
+static void reset_sd64(const struct ConfigDev *cd);
+static void reset_ariadne(const struct ConfigDev *cd);
+static void reset_hydra(const struct ConfigDev *cd);
+#if 0
+static void reset_a2060(const struct ConfigDev *cd);
+#endif
+
+struct boardreset {
+ u_short manuf;
+ u_short prod;
+ const char *name;
+ void (*reset)(const struct ConfigDev *cd);
+};
+
+static struct boardreset boardresetdb[] = {
+ { MANUF_HELFRICH1, PROD_RAINBOW3, "Rainbow 3", reset_rb3 },
+ { MANUF_HELFRICH2, PROD_PICCOLO_REG, "Piccolo", reset_piccolo },
+ { MANUF_HELFRICH2, PROD_SD64_REG, "SD64", reset_sd64 },
+ { MANUF_VILLAGE_TRONIC, PROD_ARIADNE, "Ariadne", reset_ariadne },
+ { MANUF_HYDRA_SYSTEMS, PROD_AMIGANET, "Hydra", reset_hydra },
+#if 0
+ { MANUF_COMMODORE, PROD_A2060, "A2060", reset_a2060 },
+#endif
+};
+#define NUM_BOARDRESET sizeof(boardresetdb)/sizeof(*boardresetdb)
+
+static void (*boardresetfuncs[NUM_AUTO])(const struct ConfigDev *cd);
+
+
+const char *amiga_models[] = {
+ "Amiga 500", "Amiga 500+", "Amiga 600", "Amiga 1000", "Amiga 1200",
+ "Amiga 2000", "Amiga 2500", "Amiga 3000", "Amiga 3000T", "Amiga 3000+",
+ "Amiga 4000", "Amiga 4000T", "CDTV", "CD32", "Draco"
+};
+const u_long first_amiga_model = AMI_500;
+const u_long last_amiga_model = AMI_DRACO;
+
+
+#define MASK(model) (1<<AMI_##model)
+
+#define CLASS_A3000 (MASK(3000) | MASK(3000T))
+#define CLASS_A4000 (MASK(4000) | MASK(4000T))
+#define CLASS_ZKICK (MASK(500) | MASK(1000) | MASK(2000) | MASK(2500))
+
+
+ /*
+ * Boot the Linux/m68k Operating System
+ */
+
+u_long linuxboot(const struct linuxboot_args *args)
+{
+ int kfd = -1, rfd = -1, elf_kernel = 0;
+ int i, j;
+ const struct MemHeader *mnp;
+ struct ConfigDev *cdp = NULL;
+ char *memptr = NULL;
+ u_long *stack = NULL;
+ u_long fast_total, model_mask, startcodesize, start_mem, mem_size, rd_size;
+ u_long kernel_size;
+ u_long memreq = 0, text_offset = 0;
+ Elf32_Phdr *kernel_phdrs = NULL;
+ void (*startfunc)(void);
+ u_short manuf;
+ u_char prod;
+
+ linuxboot_args = args;
+
+ /* print the greet message */
+ Puts("\nLinux/m68k Amiga Bootstrap version " AMIBOOT_VERSION "\n");
+ Puts("Copyright 1993,1994 by Hamish Macdonald and Greg Harp\n\n");
+
+ /* machine is Amiga */
+ bi.machtype = MACH_AMIGA;
+
+ /* determine chipset */
+ bi.bi_amiga.chipset = get_chipset();
+
+ /* determine CPU type */
+ bi.cputype = get_cpu();
+
+ /* determine Amiga model */
+ bi.bi_amiga.model = get_model(bi.bi_amiga.chipset);
+ model_mask = (bi.bi_amiga.model != AMI_UNKNOWN) ? 1<<bi.bi_amiga.model : 0;
+
+ /* Memory & AutoConfig based on 'unix_boot.c' by C= */
+
+ /* find all of the autoconfig boards in the system */
+ bi.bi_amiga.num_autocon = 0;
+ for (i = 0; (cdp = (struct ConfigDev *)FindConfigDev(cdp, -1, -1)); i++) {
+ if (bi.bi_amiga.num_autocon < NUM_AUTO) {
+ /* copy the contents of each structure into our boot info */
+ memcpy(&bi.bi_amiga.autocon[bi.bi_amiga.num_autocon], cdp,
+ sizeof(struct ConfigDev));
+ /* count this device */
+ bi.bi_amiga.num_autocon++;
+ } else
+ Printf("Warning: too many AutoConfig devices. Ignoring device at "
+ "0x%08lx\n", cdp->cd_BoardAddr);
+ }
+
+ /* find out the memory in the system */
+ bi.num_memory = 0;
+ for (mnp = (struct MemHeader *)SysBase->MemList.lh_Head;
+ mnp->mh_Node.ln_Succ;
+ mnp = (struct MemHeader *)mnp->mh_Node.ln_Succ) {
+ struct MemHeader mh;
+
+ /* copy the information */
+ mh = *mnp;
+
+ /* skip virtual memory */
+ if (!(mh.mh_Attributes & MEMF_PUBLIC))
+ continue;
+
+ /* if we suspect that Kickstart is shadowed in an A3000,
+ modify the entry to show 512K more at the top of RAM
+ Check first for a MapROMmed A3640 board: overwriting the
+ Kickstart image causes an infinite lock-up on reboot! */
+ if ((mh.mh_Upper == (void *)0x07f80000) &&
+ (model_mask & (CLASS_A3000 | CLASS_A4000)))
+ if ((bi.cputype & CPU_68040) && Supervisor(maprommed))
+ Puts("A3640 MapROM detected.\n");
+ else if (model_mask & CLASS_A3000) {
+ mh.mh_Upper = (void *)0x08000000;
+ Puts("A3000 shadowed Kickstart detected.\n");
+ }
+
+ /* if we suspect that Kickstart is zkicked,
+ modify the entry to show 512K more at the botton of RAM */
+ if ((mh.mh_Lower == (void *)0x00280020) &&
+ (model_mask & CLASS_ZKICK)) {
+ mh.mh_Lower = (void *)0x00200000;
+ Puts("ZKick detected.\n");
+ }
+
+ /* mask the memory limit values */
+ mh.mh_Upper = (void *)((u_long)mh.mh_Upper & 0xfffff000);
+ mh.mh_Lower = (void *)((u_long)mh.mh_Lower & 0xfffff000);
+
+ /* if fast memory */
+ if (mh.mh_Attributes & MEMF_FAST) {
+ /* set the size value to the size of this block and mask off to a
+ 256K increment */
+ u_long size = ((u_long)mh.mh_Upper-(u_long)mh.mh_Lower)&0xfffc0000;
+ if (size > 0)
+ if (bi.num_memory < NUM_MEMINFO) {
+ /* record the start and size */
+ bi.memory[bi.num_memory].addr = (u_long)mh.mh_Lower;
+ bi.memory[bi.num_memory].size = size;
+ /* count this block */
+ bi.num_memory++;
+ } else
+ Printf("Warning: too many memory blocks. Ignoring block "
+ "of %ldK at 0x%08x\n", size>>10,
+ (u_long)mh.mh_Lower);
+ } else if (mh.mh_Attributes & MEMF_CHIP)
+ /* if CHIP memory, record the size */
+ bi.bi_amiga.chip_size = (u_long)mh.mh_Upper;
+ }
+
+ /* get info from ExecBase */
+ bi.bi_amiga.vblank = SysBase->VBlankFrequency;
+ bi.bi_amiga.psfreq = SysBase->PowerSupplyFrequency;
+ bi.bi_amiga.eclock = SysBase->ex_EClockFrequency;
+
+ /* copy command line options into the kernel command line */
+ strncpy(bi.command_line, commandline, CL_SIZE);
+ bi.command_line[CL_SIZE-1] = '\0';
+
+
+ /* modify the bootinfo, e.g. to change the memory configuration */
+ if (ModifyBootinfo && !ModifyBootinfo(&bi))
+ goto Fail;
+
+
+ /* display Amiga model */
+ if (bi.bi_amiga.model >= first_amiga_model &&
+ bi.bi_amiga.model <= last_amiga_model)
+ Printf("%s ", amiga_models[bi.bi_amiga.model-first_amiga_model]);
+ else
+ Puts("Amiga ");
+
+ /* display the CPU type */
+ Puts("CPU: ");
+ switch (bi.cputype & CPU_MASK) {
+ case CPU_68020:
+ Puts("68020 (Do you have an MMU?)");
+ break;
+ case CPU_68030:
+ Puts("68030");
+ break;
+ case CPU_68040:
+ Puts("68040");
+ break;
+ case CPU_68060:
+ Puts("68060");
+ break;
+ default:
+ Puts("Insufficient for Linux. Aborting...\n");
+ Printf("SysBase->AttnFlags = 0x%08lx\n", SysBase->AttnFlags);
+ goto Fail;
+ }
+ switch (bi.cputype & ~CPU_MASK) {
+ case FPU_68881:
+ Puts(" with 68881 FPU");
+ break;
+ case FPU_68882:
+ Puts(" with 68882 FPU");
+ break;
+ case FPU_68040:
+ case FPU_68060:
+ Puts(" with internal FPU");
+ break;
+ default:
+ Puts(" without FPU");
+ break;
+ }
+
+ /* display the chipset */
+ switch(bi.bi_amiga.chipset) {
+ case CS_STONEAGE:
+ Puts(", old or unknown chipset");
+ break;
+ case CS_OCS:
+ Puts(", OCS");
+ break;
+ case CS_ECS:
+ Puts(", ECS");
+ break;
+ case CS_AGA:
+ Puts(", AGA chipset");
+ break;
+ }
+
+ Puts("\n\n");
+
+ /* display the command line */
+ Printf("Command line is '%s'\n", bi.command_line);
+
+ /* display the clock statistics */
+ Printf("Vertical Blank Frequency: %ldHz\n", bi.bi_amiga.vblank);
+ Printf("Power Supply Frequency: %ldHz\n", bi.bi_amiga.psfreq);
+ Printf("EClock Frequency: %ldHz\n\n", bi.bi_amiga.eclock);
+
+ /* display autoconfig devices */
+ if (bi.bi_amiga.num_autocon) {
+ Printf("Found %ld AutoConfig Device%s\n", bi.bi_amiga.num_autocon,
+ bi.bi_amiga.num_autocon > 1 ? "s" : "");
+ for (i = 0; i < bi.bi_amiga.num_autocon; i++) {
+ Printf("Device %ld: addr = 0x%08lx", i,
+ (u_long)bi.bi_amiga.autocon[i].cd_BoardAddr);
+ boardresetfuncs[i] = NULL;
+ if (reset_boards) {
+ manuf = bi.bi_amiga.autocon[i].cd_Rom.er_Manufacturer;
+ prod = bi.bi_amiga.autocon[i].cd_Rom.er_Product;
+ for (j = 0; j < NUM_BOARDRESET; j++)
+ if ((manuf == boardresetdb[j].manuf) &&
+ (prod == boardresetdb[j].prod)) {
+ Printf(" [%s - will be reset at kernel boot time]",
+ boardresetdb[j].name);
+ boardresetfuncs[i] = boardresetdb[j].reset;
+ break;
+ }
+ }
+ PutChar('\n');
+ }
+ } else
+ Puts("No AutoConfig Devices Found\n");
+
+ /* display memory */
+ if (bi.num_memory) {
+ Printf("\nFound %ld Block%sof Memory\n", bi.num_memory,
+ bi.num_memory > 1 ? "s " : " ");
+ for (i = 0; i < bi.num_memory; i++)
+ Printf("Block %ld: 0x%08lx to 0x%08lx (%ldK)\n", i,
+ bi.memory[i].addr, bi.memory[i].addr+bi.memory[i].size,
+ bi.memory[i].size>>10);
+ } else {
+ Puts("No memory found?! Aborting...\n");
+ goto Fail;
+ }
+
+ /* display chip memory size */
+ Printf("%ldK of CHIP memory\n", bi.bi_amiga.chip_size>>10);
+
+ start_mem = bi.memory[0].addr;
+ mem_size = bi.memory[0].size;
+
+ /* tell us where the kernel will go */
+ Printf("\nThe kernel will be located at 0x%08lx\n", start_mem);
+
+ /* verify that there is enough Chip RAM */
+ if (bi.bi_amiga.chip_size < 512*1024) {
+ Puts("Not enough Chip RAM in this system. Aborting...\n");
+ goto Fail;
+ }
+
+ /* verify that there is enough Fast RAM */
+ for (fast_total = 0, i = 0; i < bi.num_memory; i++)
+ fast_total += bi.memory[i].size;
+ if (fast_total < 2*1024*1024) {
+ Puts("Not enough Fast RAM in this system. Aborting...\n");
+ goto Fail;
+ }
+
+ /* support for ramdisk */
+ if (ramdiskname) {
+ int size;
+
+ if ((size = FileSize(ramdiskname)) == -1) {
+ Printf("Unable to find size of ramdisk file `%s'\n", ramdiskname);
+ goto Fail;
+ }
+ /* record ramdisk size */
+ bi.ramdisk_size = (size+1023)>>10;
+ } else
+ bi.ramdisk_size = 0;
+ rd_size = bi.ramdisk_size<<10;
+ bi.ramdisk_addr = start_mem+mem_size-rd_size;
+
+ /* open kernel executable and read exec header */
+ if ((kfd = Open(kernelname)) == -1) {
+ Printf("Unable to open kernel file `%s'\n", kernelname);
+ goto Fail;
+ }
+ if (Read(kfd, (void *)&kexec, sizeof(kexec)) != sizeof(kexec)) {
+ Puts("Unable to read exec header from kernel file\n");
+ goto Fail;
+ }
+
+ switch (N_MAGIC(kexec)) {
+ case ZMAGIC:
+ if (debugflag)
+ Puts("\nLoading a.out (ZMAGIC) Linux/m68k kernel...\n");
+ text_offset = N_TXTOFF(kexec);
+ break;
+
+ case QMAGIC:
+ if (debugflag)
+ Puts("\nLoading a.out (QMAGIC) Linux/m68k kernel...\n");
+ text_offset = sizeof(kexec);
+ /* the text size includes the exec header; remove this */
+ kexec.a_text -= sizeof(kexec);
+ break;
+
+ default:
+ /* Try to parse it as an ELF header */
+ Seek(kfd, 0);
+ if ((Read(kfd, (void *)&kexec_elf, sizeof(kexec_elf)) ==
+ sizeof(kexec_elf)) &&
+ (memcmp(&kexec_elf.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0)) {
+ elf_kernel = 1;
+ if (debugflag)
+ Puts("\nLoading ELF Linux/m68k kernel...\n");
+ /* A few plausibility checks */
+ if ((kexec_elf.e_type != ET_EXEC) ||
+ (kexec_elf.e_machine != EM_68K) ||
+ (kexec_elf.e_version != EV_CURRENT)) {
+ Puts("Invalid ELF header contents in kernel\n");
+ goto Fail;
+ }
+ /* Load the program headers */
+ if (!(kernel_phdrs =
+ (Elf32_Phdr *)AllocMem(kexec_elf.e_phnum*sizeof(Elf32_Phdr),
+ MEMF_FAST | MEMF_PUBLIC |
+ MEMF_CLEAR))) {
+ Puts("Unable to allocate memory for program headers\n");
+ goto Fail;
+ }
+ Seek(kfd, kexec_elf.e_phoff);
+ if (Read(kfd, (void *)kernel_phdrs,
+ kexec_elf.e_phnum*sizeof(*kernel_phdrs)) !=
+ kexec_elf.e_phnum*sizeof(*kernel_phdrs)) {
+ Puts("Unable to read program headers from kernel file\n");
+ goto Fail;
+ }
+ break;
+ }
+ Printf("Wrong magic number 0x%08lx in kernel header\n",
+ N_MAGIC(kexec));
+ goto Fail;
+ }
+
+ /* Load the kernel at one page after start of mem */
+ start_mem += PAGE_SIZE;
+ mem_size -= PAGE_SIZE;
+ /* Align bss size to multiple of four */
+ if (!elf_kernel)
+ kexec.a_bss = (kexec.a_bss+3) & ~3;
+
+ /* calculate the total required amount of memory */
+ if (elf_kernel) {
+ u_long min_addr = 0xffffffff, max_addr = 0;
+ for (i = 0; i < kexec_elf.e_phnum; i++) {
+ if (min_addr > kernel_phdrs[i].p_vaddr)
+ min_addr = kernel_phdrs[i].p_vaddr;
+ if (max_addr < kernel_phdrs[i].p_vaddr+kernel_phdrs[i].p_memsz)
+ max_addr = kernel_phdrs[i].p_vaddr+kernel_phdrs[i].p_memsz;
+ }
+ /* This is needed for newer linkers that include the header in
+ the first segment. */
+ if (min_addr == 0) {
+ min_addr = PAGE_SIZE;
+ kernel_phdrs[0].p_vaddr += PAGE_SIZE;
+ kernel_phdrs[0].p_offset += PAGE_SIZE;
+ kernel_phdrs[0].p_filesz -= PAGE_SIZE;
+ kernel_phdrs[0].p_memsz -= PAGE_SIZE;
+ }
+ kernel_size = max_addr-min_addr;
+ } else
+ kernel_size = kexec.a_text+kexec.a_data+kexec.a_bss;
+ memreq = kernel_size+sizeof(struct bootinfo)+rd_size;
+ if (!(memptr = (char *)AllocMem(memreq, MEMF_FAST | MEMF_PUBLIC |
+ MEMF_CLEAR))) {
+ Puts("Unable to allocate memory\n");
+ goto Fail;
+ }
+
+ /* read the text and data segments from the kernel image */
+ if (elf_kernel)
+ for (i = 0; i < kexec_elf.e_phnum; i++) {
+ if (Seek(kfd, kernel_phdrs[i].p_offset) == -1) {
+ Printf("Failed to seek to segment %ld\n", i);
+ goto Fail;
+ }
+ if (Read(kfd, memptr+kernel_phdrs[i].p_vaddr-PAGE_SIZE,
+ kernel_phdrs[i].p_filesz) != kernel_phdrs[i].p_filesz) {
+ Printf("Failed to read segment %ld\n", i);
+ goto Fail;
+ }
+ }
+ else {
+ if (Seek(kfd, text_offset) == -1) {
+ Printf("Failed to seek to text\n");
+ goto Fail;
+ }
+ if (Read(kfd, memptr, kexec.a_text) != kexec.a_text) {
+ Printf("Failed to read text\n");
+ goto Fail;
+ }
+ /* data follows immediately after text */
+ if (Read(kfd, memptr+kexec.a_text, kexec.a_data) != kexec.a_data) {
+ Printf("Failed to read data\n");
+ goto Fail;
+ }
+ }
+ Close(kfd);
+ kfd = -1;
+
+ /* Check kernel's bootinfo version */
+ if (!check_bootinfo_version(memptr))
+ goto Fail;
+
+ /* copy the bootinfo to the end of the kernel image */
+ memcpy((void *)(memptr+kernel_size), &bi, sizeof(struct bootinfo));
+
+ if (ramdiskname) {
+ if ((rfd = Open(ramdiskname)) == -1) {
+ Printf("Unable to open ramdisk file `%s'\n", ramdiskname);
+ goto Fail;
+ }
+ if (Read(rfd, memptr+kernel_size+sizeof(bi), rd_size) != rd_size) {
+ Printf("Failed to read ramdisk file\n");
+ goto Fail;
+ }
+ Close(rfd);
+ rfd = -1;
+ }
+
+ /* allocate temporary chip ram stack */
+ if (!(stack = (u_long *)AllocMem(TEMP_STACKSIZE, MEMF_CHIP | MEMF_CLEAR))) {
+ Puts("Unable to allocate memory for stack\n");
+ goto Fail;
+ }
+
+ /* allocate chip ram for copy of startup code */
+ startcodesize = &copyallend-&copyall;
+ if (!(startfunc = (void (*)(void))AllocMem(startcodesize,
+ MEMF_CHIP | MEMF_CLEAR))) {
+ Puts("Unable to allocate memory for startcode\n");
+ goto Fail;
+ }
+
+ /* copy startup code to CHIP RAM */
+ memcpy(startfunc, &copyall, startcodesize);
+
+ if (debugflag) {
+ if (bi.ramdisk_size)
+ Printf("RAM disk at 0x%08lx, size is %ldK\n",
+ (u_long)memptr+kernel_size, bi.ramdisk_size);
+
+ if (elf_kernel) {
+ PutChar('\n');
+ for (i = 0; i < kexec_elf.e_phnum; i++)
+ Printf("Kernel segment %ld at 0x%08lx, size %ld\n", i,
+ start_mem+kernel_phdrs[i].p_vaddr-PAGE_SIZE,
+ kernel_phdrs[i].p_memsz);
+ Printf("Boot info at 0x%08lx\n", start_mem+kernel_size);
+ } else {
+ Printf("\nKernel text at 0x%08lx, code size 0x%08lx\n", start_mem,
+ kexec.a_text);
+ Printf("Kernel data at 0x%08lx, data size 0x%08lx\n",
+ start_mem+kexec.a_text, kexec.a_data);
+ Printf("Kernel bss at 0x%08lx, bss size 0x%08lx\n",
+ start_mem+kexec.a_text+kexec.a_data, kexec.a_bss);
+ Printf("Boot info at 0x%08lx\n", start_mem+kernel_size);
+ }
+ Printf("\nKernel entry is 0x%08lx\n", elf_kernel ? kexec_elf.e_entry :
+ kexec.a_entry);
+
+ Printf("ramdisk dest top is 0x%08lx\n", start_mem+mem_size);
+ Printf("ramdisk lower limit is 0x%08lx\n", (u_long)memptr+kernel_size);
+ Printf("ramdisk src top is 0x%08lx\n",
+ (u_long)memptr+kernel_size+rd_size);
+
+ Puts("\nType a key to continue the Linux/m68k boot...");
+ GetChar();
+ PutChar('\n');
+ }
+
+ /* wait for things to settle down */
+ Sleep(1000000);
+
+ if (!keep_video)
+ /* set graphics mode to a nice normal one */
+ LoadView(NULL);
+
+ Disable();
+
+ /* reset nasty Zorro boards */
+ if (reset_boards)
+ for (i = 0; i < bi.bi_amiga.num_autocon; i++)
+ if (boardresetfuncs[i])
+ boardresetfuncs[i](&bi.bi_amiga.autocon[i]);
+
+ /* Turn off all DMA */
+ custom.dmacon = DMAF_ALL | DMAF_MASTER;
+
+ /* turn off caches */
+ CacheControl(0, ~0);
+
+ /* Go into supervisor state */
+ SuperState();
+
+ /* turn off any mmu translation */
+ disable_mmu();
+
+ /* execute the copy-and-go code (from CHIP RAM) */
+ start_kernel(startfunc, (char *)stack+TEMP_STACKSIZE, memptr, start_mem,
+ mem_size, rd_size, kernel_size);
+
+ /* Clean up and exit in case of a failure */
+Fail:
+ if (kfd != -1)
+ Close(kfd);
+ if (rfd != -1)
+ Close(rfd);
+ if (memptr)
+ FreeMem((void *)memptr, memreq);
+ if (stack)
+ FreeMem((void *)stack, TEMP_STACKSIZE);
+ if (kernel_phdrs)
+ FreeMem((void *)kernel_phdrs, kexec_elf.e_phnum*sizeof(Elf32_Phdr));
+ return(FALSE);
+}
+
+
+ /*
+ * Determine the Chipset
+ */
+
+static u_long get_chipset(void)
+{
+ u_char cs;
+ u_long chipset;
+
+ if (GfxBase->Version >= 39)
+ cs = SetChipRev(SETCHIPREV_BEST);
+ else
+ cs = GfxBase->ChipRevBits0;
+ if ((cs & GFXG_AGA) == GFXG_AGA)
+ chipset = CS_AGA;
+ else if ((cs & GFXG_ECS) == GFXG_ECS)
+ chipset = CS_ECS;
+ else if ((cs & GFXG_OCS) == GFXG_OCS)
+ chipset = CS_OCS;
+ else
+ chipset = CS_STONEAGE;
+ return(chipset);
+}
+
+
+ /*
+ * Determine the CPU Type
+ */
+
+static u_long get_cpu(void)
+{
+ u_long cpu = 0;
+
+ if (SysBase->AttnFlags & AFF_68060) {
+ cpu = CPU_68060;
+ if (SysBase->AttnFlags & AFF_FPU40)
+ cpu |= FPU_68060;
+ } else if (SysBase->AttnFlags & AFF_68040) {
+ cpu = CPU_68040;
+ if (SysBase->AttnFlags & AFF_FPU40)
+ cpu |= FPU_68040;
+ } else {
+ if (SysBase->AttnFlags & AFF_68030)
+ cpu = CPU_68030;
+ else if (SysBase->AttnFlags & AFF_68020)
+ cpu = CPU_68020;
+ if (SysBase->AttnFlags & AFF_68882)
+ cpu |= FPU_68882;
+ else if (SysBase->AttnFlags & AFF_68881)
+ cpu |= FPU_68881;
+ }
+ return(cpu);
+}
+
+
+ /*
+ * Determine the Amiga Model
+ */
+
+static u_long get_model(u_long chipset)
+{
+ u_long model = AMI_UNKNOWN;
+
+ if (debugflag)
+ Puts("Amiga model identification:\n");
+ if (probe_resource("draco.resource"))
+ model = AMI_DRACO;
+ else {
+ if (debugflag)
+ Puts(" Chipset: ");
+ switch(chipset) {
+ case CS_STONEAGE:
+ if (debugflag)
+ Puts("Old or unknown\n");
+ goto OCS;
+ break;
+
+ case CS_OCS:
+ if (debugflag)
+ Puts("OCS\n");
+OCS: if (probe_resident("cd.device"))
+ model = AMI_CDTV;
+ else
+ /* let's call it an A2000 (may be A500, A1000, A2500) */
+ model = AMI_2000;
+ break;
+
+ case CS_ECS:
+ if (debugflag)
+ Puts("ECS\n");
+ if (probe_resident("Magic 36.7") ||
+ probe_resident("kickad 36.57") ||
+ probe_resident("A3000 Bonus") ||
+ probe_resident("A3000 bonus"))
+ /* let's call it an A3000 (may be A3000T) */
+ model = AMI_3000;
+ else if (probe_resource("card.resource"))
+ model = AMI_600;
+ else
+ /* let's call it an A2000 (may be A500[+], A1000, A2500) */
+ model = AMI_2000;
+ break;
+
+ case CS_AGA:
+ if (debugflag)
+ Puts("AGA\n");
+ if (probe_resident("A1000 Bonus") ||
+ probe_resident("A4000 bonus"))
+ model = probe_resident("NCR scsi.device") ? AMI_4000T :
+ AMI_4000;
+ else if (probe_resource("card.resource"))
+ model = AMI_1200;
+ else if (probe_resident("cd.device"))
+ model = AMI_CD32;
+ else
+ model = AMI_3000PLUS;
+ break;
+ }
+ }
+ if (debugflag) {
+ Puts("\nType a key to continue...");
+ GetChar();
+ Puts("\n\n");
+ }
+ return(model);
+}
+
+
+ /*
+ * Probe for a Resident Modules
+ */
+
+static int probe_resident(const char *name)
+{
+ const struct Resident *res;
+
+ if (debugflag)
+ Printf(" Module `%s': ", name);
+ res = FindResident(name);
+ if (debugflag)
+ if (res)
+ Printf("0x%08lx\n", res);
+ else
+ Printf("not present\n");
+ return(res ? TRUE : FALSE);
+}
+
+
+ /*
+ * Probe for an available Resource
+ */
+
+static int probe_resource(const char *name)
+{
+ const void *res;
+
+ if (debugflag)
+ Printf(" Resource `%s': ", name);
+ res = OpenResource(name);
+ if (debugflag)
+ if (res)
+ Printf("0x%08lx\n", res);
+ else
+ Printf("not present\n");
+ return(res ? TRUE : FALSE);
+}
+
+
+ /*
+ * Compare the Bootstrap and Kernel Versions
+ */
+
+static int check_bootinfo_version(const char *memptr)
+{
+ const struct bootversion *bv = (struct bootversion *)memptr;
+ unsigned long version = 0;
+ int i, kernel_major, kernel_minor, boots_major, boots_minor;
+
+ if (bv->magic == BOOTINFOV_MAGIC)
+ for (i = 0; bv->machversions[i].machtype != 0; ++i)
+ if (bv->machversions[i].machtype == MACH_AMIGA) {
+ version = bv->machversions[i].version;
+ break;
+ }
+ if (!version)
+ Printf("Kernel has no bootinfo version info, assuming 0.0\n");
+
+ kernel_major = BI_VERSION_MAJOR(version);
+ kernel_minor = BI_VERSION_MINOR(version);
+ boots_major = BI_VERSION_MAJOR(AMIGA_BOOTI_VERSION);
+ boots_minor = BI_VERSION_MINOR(AMIGA_BOOTI_VERSION);
+ Printf("Bootstrap's bootinfo version: %ld.%ld\n", boots_major,
+ boots_minor);
+ Printf("Kernel's bootinfo version : %ld.%ld\n", kernel_major,
+ kernel_minor);
+
+ if (kernel_major != boots_major) {
+ Printf("\nThis bootstrap is too %s for this kernel!\n",
+ boots_major < kernel_major ? "old" : "new");
+ return(0);
+ }
+ if (kernel_minor > boots_minor) {
+ Printf("Warning: Bootinfo version of bootstrap and kernel differ!\n" );
+ Printf(" Certain features may not work.\n");
+ }
+ return(1);
+}
+
+
+ /*
+ * Call the copy-and-go-code
+ */
+
+static void start_kernel(void (*startfunc)(), char *stackp, char *memptr,
+ u_long start_mem, u_long mem_size, u_long rd_size,
+ u_long kernel_size)
+{
+ register void (*a0)() __asm("a0") = startfunc;
+ register char *a2 __asm("a2") = stackp;
+ register char *a3 __asm("a3") = memptr;
+ register u_long a4 __asm("a4") = start_mem;
+ register u_long d0 __asm("d0") = mem_size;
+ register u_long d1 __asm("d1") = rd_size;
+ register u_long d2 __asm("d2") = kernel_size;
+ register u_long d3 __asm("d3") = sizeof(struct bootinfo);
+
+ __asm __volatile ("movel a2,sp;"
+ "jmp a0@"
+ : /* no outputs */
+ : "r" (a0), "r" (a2), "r" (a3), "r" (a4), "r" (d0),
+ "r" (d1), "r" (d2), "r" (d3)
+ /* no return */);
+ /* fake a noreturn */
+ for (;;);
+}
+
+
+ /*
+ * This assembler code is copied to chip ram, and then executed.
+ * It copies the kernel to it's final resting place.
+ *
+ * It is called with:
+ *
+ * a3 = memptr
+ * a4 = start_mem
+ * d0 = mem_size
+ * d1 = rd_size
+ * d2 = kernel_size
+ * d3 = sizeof(struct bootinfo)
+ */
+
+asm(".text\n"
+ALIGN_STR "\n"
+SYMBOL_NAME_STR(copyall) ":
+ | /* copy kernel text and data */
+ movel a3,a0 | src = (u_long *)memptr;
+ movel a0,a2 | limit = (u_long *)(memptr+kernel_size);
+ addl d2,a2
+ movel a4,a1 | dest = (u_long *)start_mem;
+1: cmpl a0,a2
+ jeq 2f | while (src < limit)
+ moveb a0@+,a1@+ | *dest++ = *src++;
+ jra 1b
+2:
+ | /* copy early bootinfo to end of bss */
+ movel a3,a0 | src = (u_long *)(memptr+kernel_size);
+ addl d2,a0 | dest = end of bss (already in a1)
+ movel d3,d7 | count = sizeof(struct bootinfo)
+ subql #1,d7
+1: moveb a0@+,a1@+ | while (--count > -1)
+ dbra d7,1b | *dest++ = *src++
+
+ | /* copy the ramdisk to the top of memory */
+ | /* (from back to front) */
+ movel a4,a1 | dest = (u_long *)(start_mem+mem_size);
+ addl d0,a1
+ movel a3,a2 | limit = (u_long *)(memptr+kernel_size +
+ addl d2,a2 | sizeof(struct bootinfo));
+ addl d3,a2
+ movel a2,a0 | src = (u_long *)((u_long)limit+rd_size);
+ addl d1,a0
+1: cmpl a0,a2
+ beqs 2f | while (src > limit)
+ moveb a0@-,a1@- | *--dest = *--src;
+ bras 1b
+2:
+ | /* jump to start of kernel */
+ movel a4,a0 | jump_to (start_mem);
+ jmp a0@
+"
+SYMBOL_NAME_STR(copyallend) ":
+");
+
+
+ /*
+ * Test for a MapROMmed A3640 Board
+ */
+
+asm(".text\n"
+ALIGN_STR "\n"
+SYMBOL_NAME_STR(maprommed) ":
+ oriw #0x0700,sr
+ moveml #0x3f20,sp@-
+ | /* Save cache settings */
+ .long 0x4e7a1002 | movec cacr,d1 */
+ | /* Save MMU settings */
+ .long 0x4e7a2003 | movec tc,d2
+ .long 0x4e7a3004 | movec itt0,d3
+ .long 0x4e7a4005 | movec itt1,d4
+ .long 0x4e7a5006 | movec dtt0,d5
+ .long 0x4e7a6007 | movec dtt1,d6
+ moveq #0,d0
+ movel d0,a2
+ | /* Disable caches */
+ .long 0x4e7b0002 | movec d0,cacr
+ | /* Disable MMU */
+ .long 0x4e7b0003 | movec d0,tc
+ .long 0x4e7b0004 | movec d0,itt0
+ .long 0x4e7b0005 | movec d0,itt1
+ .long 0x4e7b0006 | movec d0,dtt0
+ .long 0x4e7b0007 | movec d0,dtt1
+ lea 0x07f80000,a0
+ lea 0x00f80000,a1
+ movel a0@,d7
+ cmpl a1@,d7
+ jne 1f
+ movel d7,d0
+ notl d0
+ movel d0,a0@
+ nop | /* Thanks to Jörg Mayer! */
+ cmpl a1@,d0
+ jne 1f
+ moveq #-1,d0 | /* MapROMmed A3640 present */
+ movel d0,a2
+1: movel d7,a0@
+ | /* Restore MMU settings */
+ .long 0x4e7b2003 | movec d2,tc
+ .long 0x4e7b3004 | movec d3,itt0
+ .long 0x4e7b4005 | movec d4,itt1
+ .long 0x4e7b5006 | movec d5,dtt0
+ .long 0x4e7b6007 | movec d6,dtt1
+ | /* Restore cache settings */
+ .long 0x4e7b1002 | movec d1,cacr
+ movel a2,d0
+ moveml sp@+,#0x04fc
+ rte
+");
+
+
+ /*
+ * Reset functions for nasty Zorro boards
+ */
+
+static void reset_rb3(const struct ConfigDev *cd)
+{
+ volatile u_char *rb3_reg = (u_char *)(cd->cd_BoardAddr+0x01002000);
+
+ /* FN: If a Rainbow III board is present, reset it to disable */
+ /* its (possibly activated) vertical blank interrupts as the */
+ /* kernel is not yet prepared to handle them (level 6). */
+
+ /* set RESET bit in special function register */
+ *rb3_reg = 0x01;
+ /* actually, only a few cycles delay are required... */
+ Sleep(1000000);
+ /* clear reset bit */
+ *rb3_reg = 0x00;
+}
+
+static void reset_piccolo(const struct ConfigDev *cd)
+{
+ volatile u_char *piccolo_reg = (u_char *)(cd->cd_BoardAddr+0x8000);
+
+ /* FN: the same stuff as above, for the Piccolo board. */
+ /* this also has the side effect of resetting the board's */
+ /* output selection logic to use the Amiga's display in single */
+ /* monitor systems - which is currently what we want. */
+
+ /* set RESET bit in special function register */
+ *piccolo_reg = 0x01;
+ /* actually, only a few cycles delay are required... */
+ Sleep(1000000);
+ /* clear reset bit */
+ *piccolo_reg = 0x51;
+}
+
+static void reset_sd64(const struct ConfigDev *cd)
+{
+ volatile u_char *sd64_reg = (u_char *)(cd->cd_BoardAddr+0x8000);
+
+ /* FN: the same stuff as above, for the SD64 board. */
+ /* just as on the Piccolo, this also resets the monitor switch */
+
+ /* set RESET bit in special function register */
+ *sd64_reg = 0x1f;
+ /* actually, only a few cycles delay are required... */
+ Sleep(1000000);
+ /* clear reset bit AND switch monitor bit (0x20) */
+ *sd64_reg = 0x4f;
+}
+
+static void reset_ariadne(const struct ConfigDev *cd)
+{
+ volatile u_short *lance_rdp = (u_short *)(cd->cd_BoardAddr+0x0370);
+ volatile u_short *lance_rap = (u_short *)(cd->cd_BoardAddr+0x0372);
+ volatile u_short *lance_reset = (u_short *)(cd->cd_BoardAddr+0x0374);
+
+ volatile u_char *pit_paddr = (u_char *)(cd->cd_BoardAddr+0x1004);
+ volatile u_char *pit_pbddr = (u_char *)(cd->cd_BoardAddr+0x1006);
+ volatile u_char *pit_pacr = (u_char *)(cd->cd_BoardAddr+0x100b);
+ volatile u_char *pit_pbcr = (u_char *)(cd->cd_BoardAddr+0x100e);
+ volatile u_char *pit_psr = (u_char *)(cd->cd_BoardAddr+0x101a);
+
+ u_short in;
+
+ Disable();
+
+ /*
+ * Reset the Ethernet part (Am79C960 PCnet-ISA)
+ */
+
+ in = *lance_reset; /* Reset Chip on Read Access */
+ *lance_rap = 0x0000; /* PCnet-ISA Controller Status (CSR0) */
+ *lance_rdp = 0x0400; /* STOP */
+
+ /*
+ * Reset the Parallel part (MC68230 PI/T)
+ */
+
+ *pit_pacr &= 0xfd; /* Port A Control Register */
+ *pit_pbcr &= 0xfd; /* Port B Control Register */
+ *pit_psr = 0x05; /* Port Status Register */
+ *pit_paddr = 0x00; /* Port A Data Direction Register */
+ *pit_pbddr = 0x00; /* Port B Data Direction Register */
+
+ Enable();
+}
+
+static void reset_hydra(const struct ConfigDev *cd)
+{
+ volatile u_char *nic_cr = (u_char *)(cd->cd_BoardAddr+0xffe1);
+ volatile u_char *nic_isr = (u_char *)(cd->cd_BoardAddr+0xffe1 + 14);
+ int n = 5000;
+
+ Disable();
+
+ *nic_cr = 0x21; /* nic command register: software reset etc. */
+ while(((*nic_isr & 0x80) == 0) && --n) /* wait for reset to complete */
+ ;
+
+ Enable();
+}
+
+#if 0
+static void reset_a2060(const struct ConfigDev *cd)
+{
+#error reset_a2060: not yet implemented
+}
+#endif
diff --git a/arch/m68k/boot/amiga/linuxboot.h b/arch/m68k/boot/amiga/linuxboot.h
new file mode 100644
index 000000000..2331a994d
--- /dev/null
+++ b/arch/m68k/boot/amiga/linuxboot.h
@@ -0,0 +1,427 @@
+/*
+ * linux/arch/m68k/boot/amiga/linuxboot.h -- Generic routine to boot Linux/m68k
+ * on Amiga, used by both Amiboot and
+ * Amiga-Lilo.
+ *
+ * Created 1996 by Geert Uytterhoeven
+ *
+ *
+ * This file is based on the original bootstrap code (bootstrap.c):
+ *
+ * Copyright (C) 1993, 1994 Hamish Macdonald
+ * Greg Harp
+ *
+ * with work by Michael Rausch
+ * Geert Uytterhoeven
+ * Frank Neumann
+ * Andreas Schwab
+ *
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+
+#include <asm/setup.h>
+#include <asm/zorro.h>
+
+
+ /*
+ * Amiboot Version
+ */
+
+#define AMIBOOT_VERSION "4.0"
+
+
+ /*
+ * Parameters passed to linuxboot()
+ */
+
+struct linuxboot_args {
+ const char *kernelname;
+ const char *ramdiskname;
+ const char *commandline;
+ int debugflag;
+ int keep_video;
+ int reset_boards;
+ void (*puts)(const char *str);
+ long (*getchar)(void);
+ void (*putchar)(char c);
+ void (*printf)(const char *fmt, ...);
+ int (*open)(const char *path);
+ int (*seek)(int fd, int offset);
+ int (*read)(int fd, char *buf, int count);
+ void (*close)(int fd);
+ int (*filesize)(const char *path);
+ void (*sleep)(u_long micros);
+ int (*modify_bootinfo)(struct bootinfo *bi);
+};
+
+
+ /*
+ * Boot the Linux/m68k Operating System
+ */
+
+extern u_long linuxboot(const struct linuxboot_args *args);
+
+
+ /*
+ * Amiga Models
+ */
+
+extern const char *amiga_models[];
+extern const u_long first_amiga_model;
+extern const u_long last_amiga_model;
+
+
+ /*
+ * Exec Library Definitions
+ */
+
+#define TRUE (1)
+#define FALSE (0)
+
+
+struct List {
+ struct Node *lh_Head;
+ struct Node *lh_Tail;
+ struct Node *lh_TailPred;
+ u_char lh_Type;
+ u_char l_pad;
+};
+
+struct MemChunk {
+ struct MemChunk *mc_Next; /* pointer to next chunk */
+ u_long mc_Bytes; /* chunk byte size */
+};
+
+#define MEMF_PUBLIC (1<<0)
+#define MEMF_CHIP (1<<1)
+#define MEMF_FAST (1<<2)
+#define MEMF_LOCAL (1<<8)
+#define MEMF_CLEAR (1<<16)
+
+struct MemHeader {
+ struct Node mh_Node;
+ u_short mh_Attributes; /* characteristics of this region */
+ struct MemChunk *mh_First; /* first free region */
+ void *mh_Lower; /* lower memory bound */
+ void *mh_Upper; /* upper memory bound+1 */
+ u_long mh_Free; /* total number of free bytes */
+};
+
+struct ExecBase {
+ u_char fill1[20];
+ u_short Version;
+ u_char fill2[274];
+ u_short AttnFlags;
+ u_char fill3[24];
+ struct List MemList;
+ u_char fill4[194];
+ u_char VBlankFrequency;
+ u_char PowerSupplyFrequency;
+ u_char fill5[36];
+ u_long ex_EClockFrequency;
+ u_char fill6[60];
+};
+
+#define AFB_68020 (1)
+#define AFF_68020 (1<<AFB_68020)
+#define AFB_68030 (2)
+#define AFF_68030 (1<<AFB_68030)
+#define AFB_68040 (3)
+#define AFF_68040 (1<<AFB_68040)
+#define AFB_68881 (4)
+#define AFF_68881 (1<<AFB_68881)
+#define AFB_68882 (5)
+#define AFF_68882 (1<<AFB_68882)
+#define AFB_FPU40 (6) /* ONLY valid if AFB_68040 or AFB_68060 */
+#define AFF_FPU40 (1<<AFB_FPU40) /* is set; also set for 68060 FPU */
+#define AFB_68060 (7)
+#define AFF_68060 (1<<AFB_68060)
+
+struct Resident;
+
+
+ /*
+ * Graphics Library Definitions
+ */
+
+struct GfxBase {
+ u_char fill1[20];
+ u_short Version;
+ u_char fill2[194];
+ u_short NormalDisplayRows;
+ u_short NormalDisplayColumns;
+ u_char fill3[16];
+ u_char ChipRevBits0;
+ u_char fill4[307];
+};
+
+#define GFXB_HR_AGNUS (0)
+#define GFXF_HR_AGNUS (1<<GFXB_HR_AGNUS)
+#define GFXB_HR_DENISE (1)
+#define GFXF_HR_DENISE (1<<GFXB_HR_DENISE)
+#define GFXB_AA_ALICE (2)
+#define GFXF_AA_ALICE (1<<GFXB_AA_ALICE)
+#define GFXB_AA_LISA (3)
+#define GFXF_AA_LISA (1<<GFXB_AA_LISA)
+
+ /*
+ * HiRes(=Big) Agnus present; i.e.
+ * 1MB chipmem, big blits (none of interest so far) and programmable sync
+ */
+#define GFXG_OCS (GFXF_HR_AGNUS)
+ /*
+ * HiRes Agnus/Denise present; we are running on ECS
+ */
+#define GFXG_ECS (GFXF_HR_AGNUS|GFXF_HR_DENISE)
+ /*
+ * Alice and Lisa present; we are running on AGA
+ */
+#define GFXG_AGA (GFXF_AA_ALICE|GFXF_AA_LISA)
+
+#define SETCHIPREV_BEST (0xffffffff)
+#define HIRES (0x8000)
+
+struct View;
+
+
+ /*
+ * Amiga Shared Library/Device Functions
+ */
+
+extern const struct ExecBase *SysBase;
+
+#define LVOAllocMem (-0xc6)
+#define LVOAllocVec (-0x2ac)
+#define LVOCacheControl (-0x288)
+#define LVODisable (-0x78)
+#define LVOEnable (-0x7e)
+#define LVOFindResident (-0x60)
+#define LVOFreeMem (-0xd2)
+#define LVOFreeVec (-0x2b2)
+#define LVOOpenresource (-0x1f2)
+#define LVOSuperState (-0x96)
+#define LVOSupervisor (-0x1e)
+
+static __inline void *AllocMem(u_long byteSize, u_long requirements)
+{
+ register void *_res __asm("d0");
+ register const struct ExecBase *_base __asm("a6") = SysBase;
+ register u_long d0 __asm("d0") = byteSize;
+ register u_long d1 __asm("d1") = requirements;
+
+ __asm __volatile ("jsr a6@(-0xc6)"
+ : "=r" (_res)
+ : "r" (_base), "r" (d0), "r" (d1)
+ : "a0", "a1", "d0", "d1", "memory");
+ return(_res);
+}
+
+static __inline void *AllocVec(u_long byteSize, u_long requirements)
+{
+ register void *_res __asm("d0");
+ register const struct ExecBase *_base __asm("a6") = SysBase;
+ register u_long d0 __asm("d0") = byteSize;
+ register u_long d1 __asm("d1") = requirements;
+
+ __asm __volatile ("jsr a6@(-0x2ac)"
+ : "=r" (_res)
+ : "r" (_base), "r" (d0), "r" (d1)
+ : "a0", "a1", "d0", "d1", "memory");
+ return(_res);
+}
+
+static __inline u_long CacheControl(u_long cacheBits, u_long cacheMask)
+{
+ register u_long _res __asm("d0");
+ register const struct ExecBase *_base __asm("a6") = SysBase;
+ register u_long d0 __asm("d0") = cacheBits;
+ register u_long d1 __asm("d1") = cacheMask;
+
+ __asm __volatile ("jsr a6@(-0x288)"
+ : "=r" (_res)
+ : "r" (_base), "r" (d0), "r" (d1)
+ : "a0", "a1", "d0", "d1", "memory");
+ return(_res);
+}
+
+static __inline void Disable(void)
+{
+ register const struct ExecBase *_base __asm("a6") = SysBase;
+
+ __asm __volatile ("jsr a6@(-0x78)"
+ : /* no output */
+ : "r" (_base)
+ : "a0", "a1", "d0", "d1", "memory");
+}
+
+static __inline void Enable(void)
+{
+ register const struct ExecBase *_base __asm("a6") = SysBase;
+
+ __asm __volatile ("jsr a6@(-0x7e)"
+ : /* no output */
+ : "r" (_base)
+ : "a0", "a1", "d0", "d1", "memory");
+}
+
+static __inline struct Resident *FindResident(const u_char *name)
+{
+ register struct Resident *_res __asm("d0");
+ register const struct ExecBase *_base __asm("a6") = SysBase;
+ register const u_char *a1 __asm("a1") = name;
+
+ __asm __volatile ("jsr a6@(-0x60)"
+ : "=r" (_res)
+ : "r" (_base), "r" (a1)
+ : "a0", "a1", "d0", "d1", "memory");
+ return _res;
+}
+
+static __inline void FreeMem(void *memoryBlock, u_long byteSize)
+{
+ register const struct ExecBase *_base __asm("a6") = SysBase;
+ register void *a1 __asm("a1") = memoryBlock;
+ register u_long d0 __asm("d0") = byteSize;
+
+ __asm __volatile ("jsr a6@(-0xd2)"
+ : /* no output */
+ : "r" (_base), "r" (a1), "r" (d0)
+ : "a0", "a1", "d0", "d1", "memory");
+}
+
+static __inline void FreeVec(void *memoryBlock)
+{
+ register const struct ExecBase *_base __asm("a6") = SysBase;
+ register void *a1 __asm("a1") = memoryBlock;
+
+ __asm __volatile ("jsr a6@(-0x2b2)"
+ : /* no output */
+ : "r" (_base), "r" (a1)
+ : "a0", "a1", "d0", "d1", "memory");
+}
+
+static __inline void *OpenResource(const u_char *resName)
+{
+ register void *_res __asm("d0");
+ register const struct ExecBase *_base __asm("a6") = SysBase;
+ register const u_char *a1 __asm("a1") = resName;
+
+ __asm __volatile ("jsr a6@(-0x1f2)"
+ : "=r" (_res)
+ : "r" (_base), "r" (a1)
+ : "a0", "a1", "d0", "d1", "memory");
+ return _res;
+}
+
+static __inline void *SuperState(void)
+{
+ register void *_res __asm("d0");
+ register const struct ExecBase *_base __asm("a6") = SysBase;
+
+ __asm __volatile ("jsr a6@(-0x96)"
+ : "=r" (_res)
+ : "r" (_base)
+ : "a0", "a1", "d0", "d1", "memory");
+ return(_res);
+}
+
+static __inline u_long Supervisor(u_long (*userfunc)(void))
+{
+ register u_long _res __asm("d0");
+ register const struct ExecBase *_base __asm("a6") = SysBase;
+ register u_long (*d7)() __asm("d7") = userfunc;
+
+ __asm __volatile ("exg d7,a5;"
+ "jsr a6@(-0x1e);"
+ "exg d7,a5"
+ : "=r" (_res)
+ : "r" (_base), "r" (d7)
+ : "a0", "a1", "d0", "d1", "memory");
+ return(_res);
+}
+
+
+extern const struct ExpansionBase *ExpansionBase;
+
+#define LVOFindConfigDev (-0x48)
+
+static __inline struct ConfigDev *FindConfigDev(struct ConfigDev *oldConfigDev,
+ long manufacturer, long product)
+{
+ register struct ConfigDev *_res __asm("d0");
+ register const struct ExpansionBase *_base __asm("a6") = ExpansionBase;
+ register struct ConfigDev *a0 __asm("a0") = oldConfigDev;
+ register long d0 __asm("d0") = manufacturer;
+ register long d1 __asm("d1") = product;
+
+ __asm __volatile ("jsr a6@(-0x48)"
+ : "=r" (_res)
+ : "r" (_base), "r" (a0), "r" (d0), "r" (d1)
+ : "a0", "a1", "d0", "d1", "memory");
+ return(_res);
+}
+
+
+extern const struct GfxBase *GfxBase;
+
+#define LVOLoadView (-0xde)
+#define LVOSetChipRev (-0x378)
+
+static __inline void LoadView(struct View *view)
+{
+ register const struct GfxBase *_base __asm("a6") = GfxBase;
+ register struct View *a1 __asm("a1") = view;
+
+ __asm __volatile ("jsr a6@(-0xde)"
+ : /* no output */
+ : "r" (_base), "r" (a1)
+ : "a0", "a1", "d0", "d1", "memory");
+}
+
+static __inline u_long SetChipRev(u_long want)
+{
+ register u_long _res __asm("d0");
+ register const struct GfxBase *_base __asm("a6") = GfxBase;
+ register u_long d0 __asm("d0") = want;
+
+ __asm __volatile ("jsr a6@(-0x378)"
+ : "=r" (_res)
+ : "r" (_base), "r" (d0)
+ : "a0", "a1", "d0", "d1", "memory");
+ return(_res);
+}
+
+
+ /*
+ * Bootstrap Support Functions
+ */
+
+static __inline void disable_mmu(void)
+{
+ if (SysBase->AttnFlags & AFF_68040)
+ __asm __volatile ("moveq #0,d0;"
+ ".long 0x4e7b0003;" /* movec d0,tc */
+ ".long 0x4e7b0004;" /* movec d0,itt0 */
+ ".long 0x4e7b0005;" /* movec d0,itt1 */
+ ".long 0x4e7b0006;" /* movec d0,dtt0 */
+ ".long 0x4e7b0007" /* movec d0,dtt1 */
+ : /* no outputs */
+ : /* no inputs */
+ : "d0");
+ else {
+ __asm __volatile ("subl #4,sp;"
+ "pmove tc,sp@;"
+ "bclr #7,sp@;"
+ "pmove sp@,tc;"
+ "addl #4,sp");
+ if (SysBase->AttnFlags & AFF_68030)
+ __asm __volatile ("clrl sp@-;"
+ ".long 0xf0170800;" /* pmove sp@,tt0 */
+ ".long 0xf0170c00;" /* pmove sp@,tt1 */
+ "addql #4,sp");
+ }
+}
diff --git a/arch/m68k/boot/atari/bootp.c b/arch/m68k/boot/atari/bootp.c
new file mode 100644
index 000000000..db4fc284f
--- /dev/null
+++ b/arch/m68k/boot/atari/bootp.c
@@ -0,0 +1,793 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "bootp.h"
+
+
+/* --------------------------------------------------------------------- */
+/* Protocol Header Structures */
+
+struct etherhdr {
+ HWADDR dst_addr;
+ HWADDR src_addr;
+ unsigned short type;
+};
+
+struct arphdr {
+ unsigned short hrd; /* format of hardware address */
+ unsigned short pro; /* format of protocol address */
+ unsigned char hln; /* length of hardware address */
+ unsigned char pln; /* length of protocol address */
+ unsigned short op; /* ARP opcode (command) */
+ unsigned char addr[0]; /* addresses (var len) */
+};
+
+struct iphdr {
+ unsigned char version : 4;
+ unsigned char ihl : 4;
+ unsigned char tos;
+ unsigned short tot_len;
+ unsigned short id;
+ unsigned short frag_off;
+ unsigned char ttl;
+ unsigned char protocol;
+ unsigned short chksum;
+ IPADDR src_addr;
+ IPADDR dst_addr;
+};
+
+struct udphdr {
+ unsigned short src_port;
+ unsigned short dst_port;
+ unsigned short len;
+ unsigned short chksum;
+};
+
+struct bootp {
+ unsigned char op; /* packet opcode type */
+ unsigned char htype; /* hardware addr type */
+ unsigned char hlen; /* hardware addr length */
+ unsigned char hops; /* gateway hops */
+ unsigned long xid; /* transaction ID */
+ unsigned short secs; /* seconds since boot began */
+ unsigned short unused;
+ IPADDR ciaddr; /* client IP address */
+ IPADDR yiaddr; /* 'your' IP address */
+ IPADDR siaddr; /* server IP address */
+ IPADDR giaddr; /* gateway IP address */
+ unsigned char chaddr[16]; /* client hardware address */
+ unsigned char sname[64]; /* server host name */
+ unsigned char file[128]; /* boot file name */
+ unsigned char vend[64]; /* vendor-specific area */
+};
+
+struct tftp_req {
+ unsigned short opcode;
+ char name[512];
+};
+
+struct tftp_data {
+ unsigned short opcode;
+ unsigned short nr;
+ unsigned char data[512];
+};
+
+struct tftp_ack {
+ unsigned short opcode;
+ unsigned short nr;
+};
+
+struct tftp_error {
+ unsigned short opcode;
+ unsigned short errcode;
+ char str[512];
+};
+
+
+typedef struct {
+ struct etherhdr ether;
+ struct arphdr arp;
+} ARP;
+
+typedef struct {
+ struct etherhdr ether;
+ struct iphdr ip;
+ struct udphdr udp;
+} UDP;
+
+#define UDP_BOOTPS 67
+#define UDP_BOOTPC 68
+#define UDP_TFTP 69
+
+typedef struct {
+ struct etherhdr ether;
+ struct iphdr ip;
+ struct udphdr udp;
+ struct bootp bootp;
+} BOOTP;
+
+#define BOOTREQUEST 1
+#define BOOTREPLY 2
+#define BOOTP_RETRYS 5
+
+typedef struct {
+ struct etherhdr ether;
+ struct iphdr ip;
+ struct udphdr udp;
+ union tftp {
+ unsigned short opcode;
+ struct tftp_req req;
+ struct tftp_data data;
+ struct tftp_ack ack;
+ struct tftp_error error;
+ } tftp;
+} TFTP;
+
+#define TFTP_RRQ 1
+#define TFTP_WRQ 2
+#define TFTP_DATA 3
+#define TFTP_ACK 4
+#define TFTP_ERROR 5
+
+
+/* --------------------------------------------------------------------- */
+/* Addresses */
+
+static HWADDR MyHwaddr;
+static HWADDR ServerHwaddr;
+static IPADDR MyIPaddr;
+static IPADDR ServerIPaddr;
+
+static IPADDR IP_Unknown_Addr = 0x00000000;
+static IPADDR IP_Broadcast_Addr = 0xffffffff;
+static HWADDR Eth_Broadcast_Addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+
+#define HZ 200
+#define _hz_200 (*(volatile unsigned long *)0x4ba)
+
+
+/* --------------------------------------------------------------------- */
+/* Error Strings */
+
+static char *ErrStr[] = {
+ "timeout",
+ "general Ethernet transmit error",
+ "general Ethernet receive error",
+ "Ethernet framing error",
+ "Ethernet overflow error",
+ "Ethernet CRC error"
+};
+
+
+/* --------------------------------------------------------------------- */
+/* Kfile Emulation Definitions */
+
+#define KFILE_CHUNK_BITS 16 /* chunk is 64 KB */
+#define KFILE_CHUNK_SIZE (1 << KFILE_CHUNK_BITS)
+#define KFILE_CHUNK_MASK (KFILE_CHUNK_SIZE-1)
+#define KFILE_N_CHUNKS (2*1024*1024/KFILE_CHUNK_SIZE)
+
+char *KFile[KFILE_N_CHUNKS];
+int KFileSize = 0;
+int KFpos = 0;
+
+
+
+
+/***************************** Prototypes *****************************/
+
+static void free_kfile( void );
+static int bootp( char *image_name );
+static int tftp( char *image_name );
+static int udp_send( UDP *pkt, int len, int fromport, int toport );
+static unsigned short ip_checksum( struct iphdr *buf );
+static int udp_rcv( UDP *pkt, int *len, int fromport, int atport );
+static void print_ip( IPADDR addr );
+static void print_hw( HWADDR addr );
+static int check_ethif( void );
+static int eth_send( Packet *pkt, int len );
+static int eth_rcv( Packet *pkt, int *len );
+
+/************************* End of Prototypes **************************/
+
+
+
+
+/* --------------------------------------------------------------------- */
+/* Interface to bootstrap.c */
+
+/* get_remote_kernel():
+ * Perform all necessary steps to get the kernel image
+ * from the boot server. If successfull (retval == 0), subsequent calls to
+ * kread() can access the data.
+ */
+
+int get_remote_kernel( const char *kname /* optional */ )
+
+{ char image_name[256];
+
+ /* Check if a Ethernet interface is present and determine the Ethernet
+ * address */
+ if (check_ethif() < 0) {
+ printf( "No Ethernet interface found -- no remote boot possible.\n" );
+ return( -1 );
+ }
+
+ /* Do a BOOTP request to find out our IP address and the kernel image's
+ * name; we also learn the IP and Ethernet address of our server */
+ if (kname)
+ strcpy( image_name, kname );
+ else
+ *image_name = 0;
+ if (bootp( image_name ) < 0)
+ return( -1 );
+
+ /* Now start a TFTP connection to receive the kernel image */
+ if (tftp( image_name ) < 0)
+ return( -1 );
+
+ return( 0 );
+}
+
+
+/* kread(), klseek(), kclose():
+ * Functions for accessing the received kernel image like with read(),
+ * lseek(), close().
+ */
+
+int kread( int fd, void *buf, unsigned cnt )
+
+{ unsigned done = 0;
+
+ if (!KFileSize)
+ return( read( fd, buf, cnt ) );
+
+ if (KFpos + cnt > KFileSize)
+ cnt = KFileSize - KFpos;
+
+ while( cnt > 0 ) {
+ unsigned chunk = KFpos >> KFILE_CHUNK_BITS;
+ unsigned endchunk = (chunk+1) << KFILE_CHUNK_BITS;
+ unsigned n = cnt;
+
+ if (KFpos + n > endchunk)
+ n = endchunk - KFpos;
+ memcpy( buf, KFile[chunk] + (KFpos & KFILE_CHUNK_MASK), n );
+ cnt -= n;
+ buf += n;
+ done += n;
+ KFpos += n;
+ }
+
+ return( done );
+}
+
+
+int klseek( int fd, int where, int whence )
+
+{
+ if (!KFileSize)
+ return( lseek( fd, where, whence ) );
+
+ switch( whence ) {
+ case SEEK_SET:
+ KFpos = where;
+ break;
+ case SEEK_CUR:
+ KFpos += where;
+ break;
+ case SEEK_END:
+ KFpos = KFileSize + where;
+ break;
+ default:
+ return( -1 );
+ }
+ if (KFpos < 0) {
+ KFpos = 0;
+ return( -1 );
+ }
+ else if (KFpos > KFileSize) {
+ KFpos = KFileSize;
+ return( -1 );
+ }
+
+ return( KFpos );
+}
+
+
+int kclose( int fd )
+
+{
+ if (!KFileSize)
+ return( close( fd ) );
+
+ free_kfile();
+ return( 0 );
+}
+
+
+static void free_kfile( void )
+
+{ int i;
+
+ for( i = 0; i < KFILE_N_CHUNKS; ++i )
+ if (KFile[i]) free( KFile[i] );
+}
+
+
+
+/* --------------------------------------------------------------------- */
+/* BOOTP Procedure */
+
+
+static int bootp( char *image_name )
+
+{ BOOTP req;
+ Packet _reply;
+ BOOTP *reply = (BOOTP *)_reply;
+ static unsigned char mincookie[] = { 99, 130, 83, 99, 255 };
+ unsigned long starttime, rancopy;
+ int err, len, retry;
+
+ memset( (char *)&req, 0, sizeof(req) );
+ /* Now fill in the packet... */
+ req.bootp.op = BOOTREQUEST;
+ req.bootp.htype = 1; /* 10Mb/s Ethernet */
+ req.bootp.hlen = 6;
+ memcpy( req.bootp.chaddr, &MyHwaddr, ETHADDRLEN );
+
+ /* Put in the minimal RFC1497 Magic cookie */
+ memcpy( req.bootp.vend, mincookie, sizeof(mincookie) );
+ /* Put the user precified bootfile name in place */
+ memcpy( req.bootp.file, image_name, strlen(image_name)+1);
+
+ starttime = _hz_200;
+ for( retry = 0; retry < BOOTP_RETRYS; ++retry ) {
+
+ /* Initialize server addresses and own IP to defaults */
+ ServerIPaddr = IP_Broadcast_Addr; /* 255.255.255.255 */
+ MyIPaddr = IP_Unknown_Addr; /* 0.0.0.0 */
+ memcpy( ServerHwaddr, Eth_Broadcast_Addr, ETHADDRLEN );
+
+ if (retry)
+ sleep( 3 );
+
+ req.bootp.xid = rancopy = _hz_200;
+ req.bootp.secs = (_hz_200 - starttime) / HZ;
+
+ if ((err = udp_send( (UDP *)&req, sizeof(req.bootp),
+ UDP_BOOTPC, UDP_BOOTPS )) < 0) {
+ printf( "bootp send: %s\n", ErrStr[-err-1] );
+ continue;
+ }
+
+ if ((err = udp_rcv( (UDP *)reply, &len,
+ UDP_BOOTPS, UDP_BOOTPC )) < 0) {
+ printf( "bootp rcv: %s\n", ErrStr[-err-1] );
+ continue;
+ }
+ if (len < sizeof(struct bootp)) {
+ printf( "received short BOOTP packet (%d bytes)\n", len );
+ continue;
+ }
+
+ if (reply->bootp.xid == rancopy)
+ /* Ok, got the answer */
+ break;
+ printf( "bootp: xid mismatch\n" );
+ }
+ if (retry >= BOOTP_RETRYS) {
+ printf( "No response from a bootp server\n" );
+ return( -1 );
+ }
+
+ ServerIPaddr = reply->bootp.siaddr;
+ memcpy( ServerHwaddr, reply->ether.src_addr, ETHADDRLEN );
+ printf( "\nBoot server is " );
+ if (strlen(reply->bootp.sname) > 0)
+ printf( "%s, IP ", reply->bootp.sname );
+ print_ip( ServerIPaddr );
+ printf( ", HW address " );
+ print_hw( ServerHwaddr );
+ printf( "\n" );
+
+ MyIPaddr = reply->bootp.yiaddr;
+ printf( "My IP address is " );
+ print_ip( MyIPaddr );
+ printf( "\n" );
+
+ strcpy( image_name, reply->bootp.file );
+ return( 0 );
+}
+
+
+/* --------------------------------------------------------------------- */
+/* TFTP Procedure */
+
+
+static int tftp( char *image_name )
+
+{ TFTP spkt;
+ Packet _rpkt;
+ TFTP *rpkt = (TFTP *)&_rpkt;
+ unsigned short mytid, rtid = 0;
+ int blk, retries, i, wpos, err, len, datalen;
+ static char rotchar[4] = { '|', '/', '-', '\\' };
+
+ retries = 5;
+ /* Construct and send a read request */
+ repeat_req:
+ spkt.tftp.req.opcode = TFTP_RRQ;
+ strcpy( spkt.tftp.req.name, image_name );
+ strcpy( spkt.tftp.req.name + strlen(spkt.tftp.req.name) + 1, "octet" );
+ mytid = _hz_200 & 0xffff;
+
+ if ((err = udp_send( (UDP *)&spkt, sizeof(spkt.tftp.req.opcode) +
+ strlen(image_name) + 1 +
+ strlen( "octect" ) +1,
+ mytid, UDP_TFTP )) < 0) {
+ printf( "TFTP RREQ: %s\n", ErrStr[-err-1] );
+ if (--retries > 0)
+ goto repeat_req;
+ return( -1 );
+ }
+
+ retries = 5;
+ for( i = 0; i < KFILE_N_CHUNKS; ++i )
+ KFile[i] = NULL;
+ wpos = 0;
+ printf( "Receiving kernel image %s:\n", image_name );
+
+ for( blk = 1; ; ++blk ) {
+
+ repeat_data:
+ if ((err = udp_rcv( (UDP *)rpkt, &len, rtid, mytid )) < 0) {
+ printf( "TFTP rcv: %s\n", ErrStr[-err-1] );
+ if (--retries > 0)
+ goto repeat_data;
+ goto err;
+ }
+ if (rtid == 0)
+ /* Store the remote port at the first packet received */
+ rtid = rpkt->udp.src_port;
+
+ if (rpkt->tftp.opcode == TFTP_ERROR) {
+ if (strlen(rpkt->tftp.error.str) > 0)
+ printf( "TFTP error: %s\n", rpkt->tftp.error.str );
+ else
+ printf( "TFTP error #%d (no description)\n",
+ rpkt->tftp.error.errcode );
+ goto err;
+ }
+ else if (rpkt->tftp.opcode != TFTP_DATA) {
+ printf( "Bad TFTP packet type: %d\n", rpkt->tftp.opcode );
+ if (--retries > 0)
+ goto repeat_data;
+ goto err;
+ }
+
+ if (rpkt->tftp.data.nr != blk) {
+ /* doubled data packet; ignore it */
+ goto repeat_data;
+ }
+ datalen = len - sizeof(rpkt->tftp.data.opcode) -
+ sizeof(rpkt->tftp.data.nr);
+
+ /* store data */
+ if (datalen > 0) {
+ int chunk = wpos >> KFILE_CHUNK_BITS;
+ if (chunk >= KFILE_N_CHUNKS) {
+ printf( "TFTP: file too large! Aborting.\n" );
+ out_of_mem:
+ spkt.tftp.error.opcode = TFTP_ERROR;
+ spkt.tftp.error.errcode = 3;
+ strcpy( spkt.tftp.error.str, "Out of memory" );
+ udp_send( (UDP *)&spkt, sizeof(spkt.tftp.ack), mytid, rtid );
+ goto err;
+ }
+ if (!KFile[chunk]) {
+ if (!(KFile[chunk] = malloc( KFILE_CHUNK_SIZE ))) {
+ printf( "TFTP: Out of memory for kernel image\n" );
+ goto out_of_mem;
+ }
+ }
+ memcpy( KFile[chunk] + (wpos & KFILE_CHUNK_MASK),
+ rpkt->tftp.data.data, datalen );
+ wpos += datalen;
+
+#define DISPLAY_BITS 13
+ if ((wpos & ((1 << DISPLAY_BITS)-1)) == 0) {
+ printf( "\r %c %7d Bytes ",
+ rotchar[(wpos>>DISPLAY_BITS)&3], wpos );
+ fflush( stdout );
+ }
+ }
+
+ /* Send ACK packet */
+ repeat_ack:
+ spkt.tftp.ack.opcode = TFTP_ACK;
+ spkt.tftp.ack.nr = blk;
+ if ((err = udp_send( (UDP *)&spkt, sizeof(spkt.tftp.ack),
+ mytid, rtid )) < 0) {
+ printf( "TFTP ACK: %s\n", ErrStr[-err-1] );
+ if (--retries > 0)
+ goto repeat_ack;
+ goto err;
+ }
+
+ if (datalen < 512) {
+ /* This was the last packet */
+ printf( "\r %7d Bytes done\n\n", wpos );
+ break;
+ }
+
+ retries = 5;
+ }
+
+ KFileSize = wpos;
+ return( 0 );
+
+ err:
+ free_kfile();
+ return( -1 );
+}
+
+
+
+/* --------------------------------------------------------------------- */
+/* UDP/IP Protocol Quick Hack Implementation */
+
+
+static int udp_send( UDP *pkt, int len, int fromport, int toport )
+
+{
+ /* UDP layer */
+ pkt->udp.src_port = fromport;
+ pkt->udp.dst_port = toport;
+ pkt->udp.len = (len += sizeof(struct udphdr));
+ pkt->udp.chksum = 0; /* Too lazy to calculate :-) */
+
+ /* IP layer */
+ pkt->ip.version = 4;
+ pkt->ip.ihl = 5;
+ pkt->ip.tos = 0;
+ pkt->ip.tot_len = (len += sizeof(struct iphdr));
+ pkt->ip.id = 0;
+ pkt->ip.frag_off = 0;
+ pkt->ip.ttl = 255;
+ pkt->ip.protocol = 17; /* UDP */
+ pkt->ip.src_addr = MyIPaddr;
+ pkt->ip.dst_addr = ServerIPaddr;
+ pkt->ip.chksum = 0;
+ pkt->ip.chksum = ip_checksum( &pkt->ip );
+
+ /* Ethernet layer */
+ memcpy( &pkt->ether.dst_addr, ServerHwaddr, ETHADDRLEN );
+ memcpy( &pkt->ether.src_addr, MyHwaddr, ETHADDRLEN );
+ pkt->ether.type = 0x0800;
+ len += sizeof(struct etherhdr);
+
+ return( eth_send( (Packet *)pkt, len ) );
+}
+
+
+static unsigned short ip_checksum( struct iphdr *buf )
+
+{ unsigned long sum = 0, wlen = 5;
+
+ __asm__ ("subqw #1,%2\n"
+ "1:\t"
+ "movel %1@+,%/d0\n\t"
+ "addxl %/d0,%0\n\t"
+ "dbra %2,1b\n\t"
+ "movel %0,%/d0\n\t"
+ "swap %/d0\n\t"
+ "addxw %/d0,%0\n\t"
+ "clrw %/d0\n\t"
+ "addxw %/d0,%0"
+ : "=d" (sum), "=a" (buf), "=d" (wlen)
+ : "0" (sum), "1" (buf), "2" (wlen)
+ : "d0");
+ return( (~sum) & 0xffff );
+}
+
+
+static int udp_rcv( UDP *pkt, int *len, int fromport, int atport )
+
+{ int err;
+
+ repeat:
+ if ((err = eth_rcv( (Packet *)pkt, len )))
+ return( err );
+
+ /* Ethernet layer */
+ if (pkt->ether.type == 0x0806) {
+ /* ARP */
+ ARP *pk = (ARP *)pkt;
+ unsigned char *shw, *sip, *thw, *tip;
+
+ if (pk->arp.hrd != 1 || pk->arp.pro != 0x0800 ||
+ pk->arp.op != 1 || MyIPaddr == IP_Unknown_Addr)
+ /* Wrong hardware type or protocol; or reply -> ignore */
+ goto repeat;
+ shw = pk->arp.addr;
+ sip = shw + pk->arp.hln;
+ thw = sip + pk->arp.pln;
+ tip = thw + pk->arp.hln;
+
+ if (memcmp( tip, &MyIPaddr, pk->arp.pln ) == 0) {
+ memcpy( thw, shw, pk->arp.hln );
+ memcpy( tip, sip, pk->arp.pln );
+ memcpy( shw, &MyHwaddr, pk->arp.hln );
+ memcpy( sip, &MyIPaddr, pk->arp.pln );
+
+ memcpy( &pk->ether.dst_addr, thw, ETHADDRLEN );
+ memcpy( &pk->ether.src_addr, &MyHwaddr, ETHADDRLEN );
+ eth_send( (Packet *)pk, *len );
+ }
+ goto repeat;
+ }
+ else if (pkt->ether.type != 0x0800) {
+ printf( "Unknown Ethernet packet type %04x received\n",
+ pkt->ether.type );
+ goto repeat;
+ }
+
+ /* IP layer */
+ if (MyIPaddr != IP_Unknown_Addr && pkt->ip.dst_addr != MyIPaddr) {
+ printf( "Received packet for wrong IP address\n" );
+ goto repeat;
+ }
+ if (ServerIPaddr != IP_Unknown_Addr &&
+ ServerIPaddr != IP_Broadcast_Addr &&
+ pkt->ip.src_addr != ServerIPaddr) {
+ printf( "Received packet from wrong server\n" );
+ goto repeat;
+ }
+ /* If IP header is longer than 5 longs, delete the options */
+ if (pkt->ip.ihl > 5) {
+ char *udpstart = (char *)((long *)&pkt->ip + pkt->ip.ihl);
+ memmove( &pkt->udp, udpstart, *len - (udpstart-(char *)pkt) );
+ }
+
+ /* UDP layer */
+ if (fromport != 0 && pkt->udp.src_port != fromport) {
+ printf( "Received packet from wrong port %d\n", pkt->udp.src_port );
+ goto repeat;
+ }
+ if (pkt->udp.dst_port != atport) {
+ printf( "Received packet at wrong port %d\n", pkt->udp.dst_port );
+ goto repeat;
+ }
+
+ *len = pkt->udp.len - sizeof(struct udphdr);
+ return( 0 );
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Address Printing */
+
+
+static void print_ip( IPADDR addr )
+
+{
+ printf( "%ld.%ld.%ld.%ld",
+ (addr >> 24) & 0xff,
+ (addr >> 16) & 0xff,
+ (addr >> 8) & 0xff,
+ addr & 0xff );
+}
+
+
+static void print_hw( HWADDR addr )
+
+{
+ printf( "%02x:%02x:%02x:%02x:%02x:%02x",
+ addr[0], addr[1], addr[2], addr[3], addr[4], addr[5] );
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Ethernet Interface Abstraction Layer */
+
+
+#ifdef ETHLL_LANCE
+#include "ethlance.h"
+#endif
+
+static ETHIF_SWITCH *PossibleInterfaces[] = {
+#ifdef ETHLL_LANCE
+ &LanceSwitch,
+#endif
+};
+
+#define N_PossibleInterfaces (sizeof(PossibleInterfaces)/sizeof(*PossibleInterfaces))
+
+/* Detected interface */
+static ETHIF_SWITCH *Ethif = NULL;
+
+
+static int check_ethif( void )
+
+{ int i;
+
+ /* Check for configured interfaces */
+ Ethif = NULL;
+ for( i = 0; i < N_PossibleInterfaces; ++i ) {
+ if (PossibleInterfaces[i]->probe() >= 0) {
+ Ethif = PossibleInterfaces[i];
+ break;
+ }
+ }
+ if (!Ethif)
+ return( -1 );
+
+ if (Ethif->init() < 0) {
+ printf( "Ethernet interface initialization failed\n" );
+ return( -1 );
+ }
+ Ethif->get_hwaddr( &MyHwaddr );
+ return( 0 );
+}
+
+
+static int eth_send( Packet *pkt, int len )
+
+{
+ return( Ethif->snd( pkt, len ));
+}
+
+
+static int eth_rcv( Packet *pkt, int *len )
+
+{
+ return( Ethif->rcv( pkt, len ));
+}
+
+
+#if 0
+static void dump_packet( UDP *pkt )
+
+{ int i, l;
+ unsigned char *p;
+
+ printf( "Packet dump:\n" );
+
+ printf( "Ethernet header:\n" );
+ printf( " dst addr: " ); print_hw( pkt->ether.dst_addr ); printf( "\n" );
+ printf( " src addr: " ); print_hw( pkt->ether.src_addr ); printf( "\n" );
+ printf( " type: %04x\n", pkt->ether.type );
+
+ printf( "IP header:\n" );
+ printf( " version: %d\n", pkt->ip.version );
+ printf( " hdr len: %d\n", pkt->ip.ihl );
+ printf( " tos: %d\n", pkt->ip.tos );
+ printf( " tot_len: %d\n", pkt->ip.tot_len );
+ printf( " id: %d\n", pkt->ip.id );
+ printf( " frag_off: %d\n", pkt->ip.frag_off );
+ printf( " ttl: %d\n", pkt->ip.ttl );
+ printf( " prot: %d\n", pkt->ip.protocol );
+ printf( " src addr: " ); print_ip( pkt->ip.src_addr ); printf( "\n" );
+ printf( " dst addr: " ); print_ip( pkt->ip.dst_addr ); printf( "\n" );
+
+ printf( "UDP header:\n" );
+ printf( " src port: %d\n", pkt->udp.src_port );
+ printf( " dst port: %d\n", pkt->udp.dst_port );
+ printf( " len: %d\n", pkt->udp.len );
+
+ printf( "Data:" );
+ l = pkt->udp.len - sizeof(pkt->udp);
+ p = (unsigned char *)&pkt->udp + sizeof(pkt->udp);
+ for( i = 0; i < l; ++i ) {
+ if ((i % 32) == 0)
+ printf( "\n %04x ", i );
+ printf( "%02x ", *p );
+ }
+ printf( "\n" );
+}
+#endif
diff --git a/arch/m68k/boot/atari/bootp.h b/arch/m68k/boot/atari/bootp.h
new file mode 100644
index 000000000..02988edaf
--- /dev/null
+++ b/arch/m68k/boot/atari/bootp.h
@@ -0,0 +1,44 @@
+#ifndef _bootp_h
+#define _bootp_h
+
+/* --------------------------------------------------------------------- */
+/* Ethernet Definitions */
+
+#define PKTLEN 1544
+typedef unsigned char Packet[PKTLEN];
+
+#define ETHADDRLEN 6
+typedef unsigned char HWADDR[ETHADDRLEN];
+
+typedef struct {
+ int (*probe)( void );
+ int (*init)( void );
+ void (*get_hwaddr)( HWADDR *addr );
+ int (*snd)( Packet *pkt, int len );
+ int (*rcv)( Packet *pkt, int *len );
+} ETHIF_SWITCH;
+
+
+/* error codes */
+#define ETIMEO -1 /* Timeout */
+#define ESEND -2 /* General send error (carrier, abort, ...) */
+#define ERCV -3 /* General receive error */
+#define EFRAM -4 /* Framing error */
+#define EOVERFL -5 /* Overflow (too long packet) */
+#define ECRC -6 /* CRC error */
+
+
+typedef unsigned long IPADDR;
+
+
+/***************************** Prototypes *****************************/
+
+int get_remote_kernel( const char *kname );
+int kread( int fd, void *buf, unsigned cnt );
+int klseek( int fd, int where, int whence );
+int kclose( int fd );
+
+/************************* End of Prototypes **************************/
+
+#endif /* _bootp_h */
+
diff --git a/arch/m68k/boot/atari/bootstrap.c b/arch/m68k/boot/atari/bootstrap.c
new file mode 100644
index 000000000..dbf5fada0
--- /dev/null
+++ b/arch/m68k/boot/atari/bootstrap.c
@@ -0,0 +1,1083 @@
+/*
+** bootstrap.c -- Load and launch the Atari Linux kernel
+**
+** Copyright 1993 by Arjan Knor
+**
+** This file is subject to the terms and conditions of the GNU General Public
+** License. See the file COPYING in the main directory of this archive
+** for more details.
+**
+** History:
+** 10 Dec 1995 BOOTP/TFTP support (Roman)
+** 03 Oct 1995 Allow kernel to be loaded to TT ram again (Andreas)
+** 11 Jul 1995 Add support for ELF format kernel (Andreas)
+** 16 Jun 1995 Adapted to Linux 1.2: kernel always loaded into ST ram
+** (Andreas)
+** 14 Nov 1994 YANML (Yet Another New Memory Layout :-) kernel
+** start address is KSTART_ADDR + PAGE_SIZE, this
+** does not need the ugly kludge with
+** -fwritable-strings (++andreas)
+** 09 Sep 1994 Adapted to the new memory layout: All the boot_info entry
+** mentions all ST-Ram and the mover is located somewhere
+** in the middle of memory (roman)
+** Added the default arguments file known from the other
+** bootstrap version
+** 19 Feb 1994 Changed everything so that it works? (rdv)
+** 14 Mar 1994 New mini-copy routine used (rdv)
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <string.h>
+#include <ctype.h>
+#include "sysvars.h"
+#include <osbind.h>
+#include <sys/types.h>
+#include <sys/file.h>
+
+/* linux specific include files */
+#include <linux/a.out.h>
+#include <linux/elf.h>
+#include <asm/page.h>
+
+#define _LINUX_TYPES_H /* Hack to prevent including <linux/types.h> */
+#include <asm/setup.h>
+
+/* Atari bootstrap include file */
+#include "bootstrap.h"
+
+#define MIN_RAMSIZE (3) /* 3 MB */
+#define TEMP_STACKSIZE 256
+
+extern char *optarg;
+extern int optind;
+static void get_default_args( int *argc, char ***argv );
+/* This is missing in <unistd.h> */
+extern int sync (void);
+
+struct bootinfo bi;
+u_long *cookiejar;
+u_long userstk;
+
+/* getcookie -- function to get the value of the given cookie. */
+static int getcookie(char *cookie, u_long *value)
+{
+ int i = 0;
+
+ while(cookiejar[i] != 0L) {
+ if(cookiejar[i] == *(u_long *)cookie) {
+ *value = cookiejar[i + 1];
+ return 1;
+ }
+ i += 2;
+ }
+ return -1;
+}
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage:\n"
+ "\tbootstrap [-dst] [-k kernel_executable] [-r ramdisk_file]"
+ " [option...]\n");
+ exit(EXIT_FAILURE);
+}
+
+/*
+ * Copy the kernel and the ramdisk to their final resting places.
+ *
+ * I assume that the kernel data and the ramdisk reside somewhere
+ * in the middle of the memory.
+ *
+ * This program itself should be somewhere in the first 4096 bytes of memory
+ * where the kernel never will be. In this way it can never be overwritten
+ * by itself.
+ *
+ * At this point the registers have:
+ * a0: the start of the final kernel
+ * a1: the start of the current kernel
+ * a2: the end of the final ramdisk
+ * a3: the end of the current ramdisk
+ * d0: the kernel size
+ * d1: the ramdisk size
+ */
+asm ("
+.text
+.globl _copyall, _copyallend
+_copyall:
+
+ movel a0,a4 /* save the start of the kernel for booting */
+
+1: movel a1@+,a0@+ /* copy the kernel starting at the beginning */
+ subql #4,d0
+ jcc 1b
+
+ tstl d1
+ beq 3f
+
+2: movel a3@-,a2@- /* copy the ramdisk starting at the end */
+ subql #4,d1
+ jcc 2b
+
+3: jmp a4@ /* jump to the start of the kernel */
+_copyallend:
+");
+
+extern char copyall, copyallend;
+
+
+/* Test for a Medusa: This is the only machine on which address 0 is
+ * writeable!
+ * ...err! On the Afterburner040 (for the Falcon) it's the same... So we do
+ * another test with 0x00ff82fe, that gives a bus error on the Falcon, but is
+ * in the range where the Medusa always asserts DTACK.
+ */
+
+int test_medusa( void )
+
+{ int rv = 0;
+
+ __asm__ __volatile__
+ ( "movel 0x8,a0\n\t"
+ "movel sp,a1\n\t"
+ "moveb 0x0,d1\n\t"
+ "movel #Lberr,0x8\n\t"
+ "moveq #0,%0\n\t"
+ "clrb 0x0\n\t"
+ "nop \n\t"
+ "moveb d1,0x0\n\t"
+ "nop \n\t"
+ "tstb 0x00ff82fe\n\t"
+ "nop \n\t"
+ "moveq #1,%0\n"
+ "Lberr:\t"
+ "movel a1,sp\n\t"
+ "movel a0,0x8"
+ : "=d" (rv)
+ : /* no inputs */
+ : "d1", "a0", "a1", "memory" );
+
+ return( rv );
+}
+
+
+/* Test if FPU instructions are executed in hardware, or if they're
+ emulated in software. For this, the F-line vector is temporarily
+ replaced. */
+
+int test_software_fpu(void)
+{
+ int rv = 0;
+
+ __asm__ __volatile__
+ ( "movel 0x2c,a0\n\t"
+ "movel sp,a1\n\t"
+ "movel #Lfline,0x2c\n\t"
+ "moveq #1,%0\n\t"
+ "fnop \n\t"
+ "nop \n\t"
+ "moveq #0,%0\n"
+ "Lfline:\t"
+ "movel a1,sp\n\t"
+ "movel a0,0x2c"
+ : "=d" (rv)
+ : /* no inputs */
+ : "a0", "a1" );
+
+ return rv;
+}
+
+
+void get_medusa_bank_sizes( u_long *bank1, u_long *bank2 )
+
+{ static u_long save_addr;
+ u_long test_base, saved_contents[16];
+#define TESTADDR(i) (*((u_long *)((char *)test_base + i*8*MB)))
+#define TESTPAT 0x12345678
+ unsigned short oldflags;
+ int i;
+
+ /* This ensures at least that none of the test addresses conflicts
+ * with the test code itself */
+ test_base = ((unsigned long)&save_addr & 0x007fffff) | 0x20000000;
+ *bank1 = *bank2 = 0;
+
+ /* Interrupts must be disabled because arbitrary addresses may be
+ * temporarily overwritten, even code of an interrupt handler */
+ __asm__ __volatile__ ( "movew sr,%0; oriw #0x700,sr" : "=g" (oldflags) : );
+ disable_cache();
+
+ /* save contents of the test addresses */
+ for( i = 0; i < 16; ++i )
+ saved_contents[i] = TESTADDR(i);
+
+ /* write 0s into all test addresses */
+ for( i = 0; i < 16; ++i )
+ TESTADDR(i) = 0;
+
+ /* test for bank 1 */
+#if 0
+ /* This is Freddi's original test, but it didn't work. */
+ TESTADDR(0) = TESTADDR(1) = TESTPAT;
+ if (TESTADDR(1) == TESTPAT) {
+ if (TESTADDR(2) == TESTPAT)
+ *bank1 = 8*MB;
+ else if (TESTADDR(3) == TESTPAT)
+ *bank1 = 16*MB;
+ else
+ *bank1 = 32*MB;
+ }
+ else {
+ if (TESTADDR(2) == TESTPAT)
+ *bank1 = 0;
+ else
+ *bank1 = 16*MB;
+ }
+#else
+ TESTADDR(0) = TESTPAT;
+ if (TESTADDR(1) == TESTPAT)
+ *bank1 = 8*MB;
+ else if (TESTADDR(2) == TESTPAT)
+ *bank1 = 16*MB;
+ else if (TESTADDR(4) == TESTPAT)
+ *bank1 = 32*MB;
+ else
+ *bank1 = 64*MB;
+#endif
+
+ /* test for bank2 */
+ if (TESTADDR(8) != 0)
+ *bank2 = 0;
+ else {
+ TESTADDR(8) = TESTPAT;
+ if (TESTADDR(9) != 0) {
+ if (TESTADDR(10) == TESTPAT)
+ *bank2 = 8*MB;
+ else
+ *bank2 = 32*MB;
+ }
+ else {
+ TESTADDR(9) = TESTPAT;
+ if (TESTADDR(10) == TESTPAT)
+ *bank2 = 16*MB;
+ else
+ *bank2 = 64*MB;
+ }
+ }
+
+ /* restore contents of the test addresses and restore interrupt mask */
+ for( i = 0; i < 16; ++i )
+ TESTADDR(i) = saved_contents[i];
+ __asm__ __volatile__ ( "movew %0,sr" : : "g" (oldflags) );
+}
+
+#undef TESTADDR
+#undef TESTPAT
+
+
+static int check_bootinfo_version(char *memptr)
+{
+ struct bootversion *bv = (struct bootversion *)memptr;
+ unsigned long version = 0;
+ int i, kernel_major, kernel_minor, boots_major, boots_minor;
+
+ printf( "\n" );
+ if (bv->magic == BOOTINFOV_MAGIC) {
+ for( i = 0; bv->machversions[i].machtype != 0; ++i ) {
+ if (bv->machversions[i].machtype == MACH_ATARI) {
+ version = bv->machversions[i].version;
+ break;
+ }
+ }
+ }
+ if (!version)
+ printf("Kernel has no bootinfo version info, assuming 0.0\n");
+
+ kernel_major = BI_VERSION_MAJOR(version);
+ kernel_minor = BI_VERSION_MINOR(version);
+ boots_major = BI_VERSION_MAJOR(ATARI_BOOTI_VERSION);
+ boots_minor = BI_VERSION_MINOR(ATARI_BOOTI_VERSION);
+ printf("Bootstrap's bootinfo version: %d.%d\n",
+ boots_major, boots_minor);
+ printf("Kernel's bootinfo version : %d.%d\n",
+ kernel_major, kernel_minor);
+
+ if (kernel_major != boots_major) {
+ printf("\nThis bootstrap is too %s for this kernel!\n",
+ boots_major < kernel_major ? "old" : "new");
+ return 0;
+ }
+ if (kernel_minor > boots_minor) {
+ printf("Warning: Bootinfo version of bootstrap and kernel differ!\n");
+ printf(" Certain features may not work.\n");
+ }
+ return 1;
+}
+
+
+#ifdef USE_BOOTP
+# include "bootp.h"
+#else
+# define kread read
+# define klseek lseek
+# define kclose close
+#endif
+
+
+/* ++andreas: this must be inline due to Super */
+static inline void boot_exit (int) __attribute__ ((noreturn));
+static inline void boot_exit(int status)
+{
+ /* first go back to user mode */
+ (void)Super(userstk);
+ getchar();
+ exit(status);
+}
+
+int main(int argc, char *argv[])
+{
+ int debugflag = 0, ch, kfd, rfd = -1, i, ignore_ttram = 0;
+ int load_to_stram = 0;
+ char *ramdisk_name, *kernel_name, *memptr;
+ u_long ST_ramsize, TT_ramsize, memreq;
+ u_long cpu_type, fpu_type, mch_type, mint;
+ struct exec kexec;
+ int elf_kernel = 0;
+ Elf32_Ehdr kexec_elf;
+ Elf32_Phdr *kernel_phdrs = NULL;
+ u_long start_mem, mem_size, rd_size, text_offset = 0, kernel_size;
+#ifdef USE_BOOTP
+ int prefer_bootp = 1, kname_set = 0;
+#endif
+
+ ramdisk_name = NULL;
+ kernel_name = "vmlinux";
+
+ /* print the startup message */
+ puts("\fLinux/68k Atari Bootstrap version 1.8"
+#ifdef USE_BOOTP
+ " (with BOOTP)"
+#endif
+ );
+ puts("Copyright 1993,1994 by Arjan Knor, Robert de Vries, Roman Hodek, Andreas Schwab\n");
+
+ /* ++roman: If no arguments on the command line, read them from
+ * file */
+ if (argc == 1)
+ get_default_args( &argc, &argv );
+
+ /* machine is Atari */
+ bi.machtype = MACH_ATARI;
+
+ /* check arguments */
+#ifdef USE_BOOTP
+ while ((ch = getopt(argc, argv, "bdtsk:r:")) != EOF)
+#else
+ while ((ch = getopt(argc, argv, "dtsk:r:")) != EOF)
+#endif
+ switch (ch) {
+ case 'd':
+ debugflag = 1;
+ break;
+ case 't':
+ ignore_ttram = 1;
+ break;
+ case 's':
+ load_to_stram = 1;
+ break;
+ case 'k':
+ kernel_name = optarg;
+#ifdef USE_BOOTP
+ kname_set = 1;
+#endif
+ break;
+ case 'r':
+ ramdisk_name = optarg;
+ break;
+#ifdef USE_BOOTP
+ case 'b':
+ prefer_bootp = 0;
+ break;
+#endif
+ case '?':
+ default:
+ usage();
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* We have to access some system variables to get
+ * the information we need, so we must switch to
+ * supervisor mode first.
+ */
+ userstk = Super(0L);
+
+ /* get the info we need from the cookie-jar */
+ cookiejar = *_p_cookies;
+ if(cookiejar == 0L) {
+ /* if we find no cookies, it's probably an ST */
+ fprintf(stderr, "Error: No cookiejar found. Is this an ST?\n");
+ boot_exit(EXIT_FAILURE);
+ }
+
+ /* Exit if MiNT/MultiTOS is running. */
+ if(getcookie("MiNT", &mint) != -1)
+ {
+ puts("Warning: MiNT is running\n");
+#if 0
+ puts("Linux cannot be started when MiNT is running. Aborting...\n");
+ boot_exit(EXIT_FAILURE);
+#endif
+ }
+
+ /* get _CPU, _FPU and _MCH */
+ getcookie("_CPU", &cpu_type);
+ getcookie("_FPU", &fpu_type);
+ getcookie("_MCH", &mch_type);
+
+ /* check if we are on a 68030/40 with FPU */
+ if ((cpu_type != 30 && cpu_type != 40 && cpu_type != 60))
+ {
+ puts("Machine type currently not supported. Aborting...");
+ boot_exit(EXIT_FAILURE);
+ }
+
+ switch(cpu_type) {
+ case 0:
+ case 10: break;
+ case 20: bi.cputype = CPU_68020; break;
+ case 30: bi.cputype = CPU_68030; break;
+ case 40: bi.cputype = CPU_68040; break;
+ case 60: bi.cputype = CPU_68060; break;
+ default:
+ fprintf(stderr, "Error: Unknown CPU type. Aborting...\n");
+ boot_exit(EXIT_FAILURE);
+ break;
+ }
+
+ printf("CPU: %ld; ", cpu_type + 68000);
+ printf("FPU: ");
+
+ /* check for FPU; in case of a '040 or '060, don't look at _FPU itself,
+ * some software may set it to wrong values (68882 or the like) */
+ if (cpu_type == 40) {
+ bi.cputype |= FPU_68040;
+ puts( "68040\n" );
+ }
+ else if (cpu_type == 60) {
+ bi.cputype |= FPU_68060;
+ puts( "68060\n" );
+ }
+ else {
+ switch ((fpu_type >> 16) & 7) {
+ case 0:
+ puts("not present\n");
+ break;
+ case 1:
+ puts("SFP004 not supported. Assuming no FPU.");
+ break;
+ case 2:
+ /* try to determine real type */
+ if (fpu_idle_frame_size () != 0x18)
+ goto m68882;
+ /* fall through */
+ case 4:
+ bi.cputype |= FPU_68881;
+ puts("68881\n");
+ break;
+ case 6:
+ m68882:
+ bi.cputype |= FPU_68882;
+ puts("68882\n");
+ break;
+ default:
+ puts("Unknown FPU type. Assuming no FPU.");
+ break;
+ }
+ }
+ /* ++roman: If an FPU was announced in the cookie, test
+ whether it is a real hardware FPU or a software emulator! */
+ if (bi.cputype & FPU_MASK) {
+ if (test_software_fpu()) {
+ bi.cputype &= ~FPU_MASK;
+ puts("FPU: software emulated. Assuming no FPU.");
+ }
+ }
+
+ memset(&bi.bi_atari.hw_present, 0, sizeof(bi.bi_atari.hw_present));
+
+ /* Get the amounts of ST- and TT-RAM. */
+ /* The size must be a multiple of 1MB. */
+ i = 0;
+
+ if (!test_medusa()) {
+ struct {
+ unsigned short version; /* version - currently 1 */
+ unsigned long fr_start; /* start addr FastRAM */
+ unsigned long fr_len; /* length FastRAM */
+ } *magn_cookie;
+ struct {
+ unsigned long version;
+ unsigned long fr_start; /* start addr */
+ unsigned long fr_len; /* length */
+ } *fx_cookie;
+
+ TT_ramsize = 0;
+ if (!ignore_ttram) {
+ /* "Original" or properly emulated TT-Ram */
+ if (*ramtop) {
+ /* the 'ramtop' variable at 0x05a4 is not
+ * officially documented. We use it anyway
+ * because it is the only way to get the TTram size.
+ * (It is zero if there is no TTram.)
+ */
+ bi.memory[i].addr = TT_RAM_BASE;
+ bi.memory[i].size = (*ramtop - TT_RAM_BASE) & ~(MB - 1);
+ TT_ramsize = bi.memory[i].size / MB;
+ i++;
+ printf("TT-RAM: %ld Mb; ", TT_ramsize);
+ }
+
+ /* test for MAGNUM alternate RAM
+ * added 26.9.1995 M. Schwingen, rincewind@discworld.oche.de
+ */
+ if (getcookie("MAGN", (u_long *)&magn_cookie) != -1) {
+ bi.memory[i].addr = magn_cookie->fr_start;
+ bi.memory[i].size = magn_cookie->fr_len & ~(MB - 1);
+ TT_ramsize += bi.memory[i].size / MB;
+ printf("MAGNUM alternate RAM: %ld Mb; ", bi.memory[i].size/MB);
+ i++;
+ }
+
+ /* BlowUps FX */
+ if (getcookie("BPFX", (u_long *)&fx_cookie) != -1 && fx_cookie) {
+ /* if fx is set (cookie call above),
+ * we assume that BlowUps FX-card
+ * is installed. (Nat!)
+ */
+ bi.memory[i].addr = fx_cookie->fr_start;
+ bi.memory[i].size = fx_cookie->fr_len & ~(MB - 1);
+ printf("FX alternate RAM: %ld Mb; ", bi.memory[i].size/MB);
+ i++;
+ }
+ }
+
+ bi.memory[i].addr = 0;
+ bi.memory[i].size = *phystop & ~(MB - 1);
+ ST_ramsize = bi.memory[i].size / MB;
+ i++;
+ printf("ST-RAM: %ld Mb\n", ST_ramsize );
+
+ bi.num_memory = i;
+
+ if (load_to_stram && i > 1) {
+ /* Put ST-RAM first in the list of mem blocks */
+ struct mem_info temp = bi.memory[i - 1];
+ bi.memory[i - 1] = bi.memory[0];
+ bi.memory[0] = temp;
+ }
+ }
+ else {
+ u_long bank1, bank2, medusa_st_ram;
+
+ get_medusa_bank_sizes( &bank1, &bank2 );
+ medusa_st_ram = *phystop & ~(MB - 1);
+ bank1 -= medusa_st_ram;
+ TT_ramsize = 0;
+
+ bi.memory[i].addr = 0;
+ bi.memory[i].size = medusa_st_ram;
+ ST_ramsize = bi.memory[i].size / MB;
+ i++;
+ printf("Medusa pseudo ST-RAM from bank 1: %ld Mb; ", ST_ramsize );
+
+ if (!ignore_ttram && bank1 > 0) {
+ bi.memory[i].addr = 0x20000000 + medusa_st_ram;
+ bi.memory[i].size = bank1;
+ TT_ramsize += bank1;
+ i++;
+ printf("TT-RAM bank 1: %ld Mb; ", bank1/MB );
+ }
+
+ if (!ignore_ttram && bank2 > 0) {
+ bi.memory[i].addr = 0x24000000;
+ bi.memory[i].size = bank2;
+ TT_ramsize += bank2;
+ i++;
+ printf("TT-RAM bank 2: %ld Mb; ", bank2/MB );
+ }
+
+ bi.num_memory = i;
+ printf("\n");
+ }
+
+ /* verify that there is enough RAM; ST- and TT-RAM combined */
+ if (ST_ramsize + TT_ramsize < MIN_RAMSIZE) {
+ puts("Not enough RAM. Aborting...");
+ boot_exit(10);
+ }
+
+#if 0
+ /* Get language/keyboard info */
+ /* TODO: do we need this ? */
+ /* Could be used to auto-select keyboard map later on. (rdv) */
+ if (getcookie("_AKP",&language) == -1)
+ {
+ /* Get the language info from the OS-header */
+ os_header = *_sysbase;
+ os_header = os_header->os_beg;
+ lang = (os_header->os_conf) >> 1;
+ printf("Language: ");
+ switch(lang) {
+ case HOL: puts("Dutch"); break; /* Own country first :-) */
+ case USA: puts("American"); break;
+ case SWG: puts("Switzerland (German)"); break;
+ case FRG: puts("German"); break;
+ case FRA: puts("French"); break;
+ case SWF: puts("Switzerland (French)"); break;
+ case UK: puts("English"); break;
+ case SPA: puts("Spanish"); break;
+ case ITA: puts("Italian"); break;
+ case SWE: puts("Swedish"); break;
+ case TUR: puts("Turkey"); break;
+ case FIN: puts("Finnish"); break;
+ case NOR: puts("Norwegian"); break;
+ case DEN: puts("Danish"); break;
+ case SAU: puts("Saudi-Arabian"); break;
+ default: puts("Unknown"); break;
+ }
+ }
+ else
+ {
+ printf("Language: ");
+ switch(language & 0x0F)
+ {
+ case 1: printf("German "); break;
+ case 2: printf("French "); break;
+ case 4: printf("Spanish "); break;
+ case 5: printf("Italian "); break;
+ case 7: printf("Swiss French "); break;
+ case 8: printf("Swiss German "); break;
+ default: printf("English ");
+ }
+ printf("Keyboard type :");
+ switch(language >> 8)
+ {
+ case 1: printf("German "); break;
+ case 2: printf("French "); break;
+ case 4: printf("Spanish "); break;
+ case 5: printf("Italian "); break;
+ case 7: printf("Swiss French "); break;
+ case 8: printf("Swiss German "); break;
+ default: printf("English ");
+ }
+ printf("\n");
+ }
+#endif
+
+ /* Pass contents of the _MCH cookie to the kernel */
+ bi.bi_atari.mch_cookie = mch_type;
+
+ /*
+ * Copy command line options into the kernel command line.
+ */
+ i = 0;
+ while (argc--) {
+ if ((i+strlen(*argv)+1) < CL_SIZE) {
+ i += strlen(*argv) + 1;
+ if (bi.command_line[0])
+ strcat (bi.command_line, " ");
+ strcat (bi.command_line, *argv++);
+ }
+ }
+ printf ("Command line is '%s'\n", bi.command_line);
+
+ start_mem = bi.memory[0].addr;
+ mem_size = bi.memory[0].size;
+
+ /* tell us where the kernel will go */
+ printf("\nThe kernel will be located at 0x%08lx\n", start_mem);
+
+#ifdef TEST
+ /*
+ ** Temporary exit point for testing
+ */
+ boot_exit(-1);
+#endif /* TEST */
+
+#ifdef USE_BOOTP
+ kfd = -1;
+ if (prefer_bootp) {
+ /* First try to get a remote kernel, then use a local kernel (if
+ * present) */
+ if (get_remote_kernel( kname_set ? kernel_name : NULL ) < 0) {
+ printf( "\nremote boot failed; trying local kernel\n" );
+ if ((kfd = open (kernel_name, O_RDONLY)) == -1) {
+ fprintf (stderr, "Unable to open kernel file %s\n",
+ kernel_name);
+ boot_exit (EXIT_FAILURE);
+ }
+ }
+ }
+ else {
+ /* Try BOOTP if local kernel cannot be opened */
+ if ((kfd = open (kernel_name, O_RDONLY)) == -1) {
+ printf( "\nlocal kernel failed; trying remote boot\n" );
+ if (get_remote_kernel( kname_set ? kernel_name : NULL ) < 0) {
+ fprintf (stderr, "Unable to remote boot and "
+ "to open kernel file %s\n", kernel_name);
+ boot_exit (EXIT_FAILURE);
+ }
+ }
+ }
+#else
+ /* open kernel executable and read exec header */
+ if ((kfd = open (kernel_name, O_RDONLY)) == -1) {
+ fprintf (stderr, "Unable to open kernel file %s\n", kernel_name);
+ boot_exit (EXIT_FAILURE);
+ }
+#endif
+
+ if (kread (kfd, (void *)&kexec, sizeof(kexec)) != sizeof(kexec))
+ {
+ fprintf (stderr, "Unable to read exec header from %s\n", kernel_name);
+ boot_exit (EXIT_FAILURE);
+ }
+
+ switch (N_MAGIC(kexec)) {
+ case ZMAGIC:
+ text_offset = N_TXTOFF(kexec);
+ break;
+ case QMAGIC:
+ text_offset = sizeof(kexec);
+ /* the text size includes the exec header; remove this */
+ kexec.a_text -= sizeof(kexec);
+ break;
+ default:
+ /* Try to parse it as an ELF header */
+ klseek (kfd, 0, SEEK_SET);
+ if (kread (kfd, (void *)&kexec_elf, sizeof (kexec_elf)) == sizeof (kexec_elf)
+ && memcmp (&kexec_elf.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0)
+ {
+ elf_kernel = 1;
+ /* A few plausibility checks */
+ if (kexec_elf.e_type != ET_EXEC || kexec_elf.e_machine != EM_68K
+ || kexec_elf.e_version != EV_CURRENT)
+ {
+ fprintf (stderr, "Invalid ELF header contents in kernel\n");
+ boot_exit (EXIT_FAILURE);
+ }
+ /* Load the program headers */
+ kernel_phdrs = (Elf32_Phdr *) Malloc (kexec_elf.e_phnum * sizeof (Elf32_Phdr));
+ if (kernel_phdrs == NULL)
+ {
+ fprintf (stderr, "Unable to allocate memory for program headers\n");
+ boot_exit (EXIT_FAILURE);
+ }
+ klseek (kfd, kexec_elf.e_phoff, SEEK_SET);
+ if (kread (kfd, (void *) kernel_phdrs,
+ kexec_elf.e_phnum * sizeof (*kernel_phdrs))
+ != kexec_elf.e_phnum * sizeof (*kernel_phdrs))
+ {
+ fprintf (stderr, "Unable to read program headers from %s\n",
+ kernel_name);
+ boot_exit (EXIT_FAILURE);
+ }
+ break;
+ }
+ fprintf (stderr, "Wrong magic number %lo in kernel header\n",
+ N_MAGIC(kexec));
+ boot_exit (EXIT_FAILURE);
+ }
+
+ /* Load the kernel one page after start of mem */
+ start_mem += PAGE_SIZE;
+ mem_size -= PAGE_SIZE;
+ /* Align bss size to multiple of four */
+ if (!elf_kernel)
+ kexec.a_bss = (kexec.a_bss + 3) & ~3;
+
+ /* init ramdisk */
+ if(ramdisk_name) {
+ if((rfd = open(ramdisk_name, O_RDONLY)) == -1) {
+ fprintf(stderr, "Unable to open ramdisk file %s\n",
+ ramdisk_name);
+ boot_exit(EXIT_FAILURE);
+ }
+ bi.ramdisk_size = (lseek(rfd, 0, SEEK_END) + 1023) / 1024;
+ }
+ else
+ bi.ramdisk_size = 0;
+
+ rd_size = bi.ramdisk_size << 10;
+ if (mem_size - rd_size < MB && bi.num_memory > 1)
+ /* If running low on ST ram load ramdisk into alternate ram. */
+ bi.ramdisk_addr = (u_long) bi.memory[1].addr + bi.memory[1].size - rd_size;
+ else
+ /* Else hopefully there is enough ST ram. */
+ bi.ramdisk_addr = (u_long)start_mem + mem_size - rd_size;
+
+ /* calculate the total required amount of memory */
+ if (elf_kernel)
+ {
+ u_long min_addr = 0xffffffff, max_addr = 0;
+ for (i = 0; i < kexec_elf.e_phnum; i++)
+ {
+ if (min_addr > kernel_phdrs[i].p_vaddr)
+ min_addr = kernel_phdrs[i].p_vaddr;
+ if (max_addr < kernel_phdrs[i].p_vaddr + kernel_phdrs[i].p_memsz)
+ max_addr = kernel_phdrs[i].p_vaddr + kernel_phdrs[i].p_memsz;
+ }
+ /* This is needed for newer linkers that include the header in
+ the first segment. */
+ if (min_addr == 0)
+ {
+ min_addr = PAGE_SIZE;
+ kernel_phdrs[0].p_vaddr += PAGE_SIZE;
+ kernel_phdrs[0].p_offset += PAGE_SIZE;
+ kernel_phdrs[0].p_filesz -= PAGE_SIZE;
+ kernel_phdrs[0].p_memsz -= PAGE_SIZE;
+ }
+ kernel_size = max_addr - min_addr;
+ }
+ else
+ kernel_size = kexec.a_text + kexec.a_data + kexec.a_bss;
+ memreq = kernel_size + sizeof (bi);
+ /* align load address of ramdisk image, read() is sloooow on odd addr. */
+ memreq = ((memreq + 3) & ~3) + rd_size;
+
+ /* allocate RAM for the kernel */
+ if (!(memptr = (char *)Malloc (memreq)))
+ {
+ fprintf (stderr, "Unable to allocate memory for kernel and ramdisk\n");
+ boot_exit (EXIT_FAILURE);
+ }
+ else
+ fprintf(stderr, "kernel at address %lx\n", (u_long) memptr);
+
+ (void)memset(memptr, 0, memreq);
+
+ /* read the text and data segments from the kernel image */
+ if (elf_kernel)
+ {
+ for (i = 0; i < kexec_elf.e_phnum; i++)
+ {
+ if (klseek (kfd, kernel_phdrs[i].p_offset, SEEK_SET) == -1)
+ {
+ fprintf (stderr, "Failed to seek to segment %d\n", i);
+ boot_exit (EXIT_FAILURE);
+ }
+ if (kread (kfd, memptr + kernel_phdrs[i].p_vaddr - PAGE_SIZE,
+ kernel_phdrs[i].p_filesz)
+ != kernel_phdrs[i].p_filesz)
+ {
+ fprintf (stderr, "Failed to read segment %d\n", i);
+ boot_exit (EXIT_FAILURE);
+ }
+ }
+ }
+ else
+ {
+ if (klseek (kfd, text_offset, SEEK_SET) == -1)
+ {
+ fprintf (stderr, "Failed to seek to text\n");
+ Mfree ((void *)memptr);
+ boot_exit (EXIT_FAILURE);
+ }
+
+ if (kread (kfd, memptr, kexec.a_text) != kexec.a_text)
+ {
+ fprintf (stderr, "Failed to read text\n");
+ Mfree ((void *)memptr);
+ boot_exit (EXIT_FAILURE);
+ }
+
+ /* data follows immediately after text */
+ if (kread (kfd, memptr + kexec.a_text, kexec.a_data) != kexec.a_data)
+ {
+ fprintf (stderr, "Failed to read data\n");
+ Mfree ((void *)memptr);
+ boot_exit (EXIT_FAILURE);
+ }
+ }
+ kclose (kfd);
+
+ /* Check kernel's bootinfo version */
+ if (!check_bootinfo_version(memptr)) {
+ Mfree ((void *)memptr);
+ boot_exit (EXIT_FAILURE);
+ }
+
+ /* copy the boot_info struct to the end of the kernel image */
+ memcpy ((void *)(memptr + kernel_size),
+ &bi, sizeof(bi));
+
+ /* read the ramdisk image */
+ if (rfd != -1)
+ {
+ if (lseek (rfd, 0, SEEK_SET) == -1)
+ {
+ fprintf (stderr, "Failed to seek to beginning of ramdisk file\n");
+ Mfree ((void *)memptr);
+ boot_exit (EXIT_FAILURE);
+ }
+ if (read (rfd, memptr + memreq - rd_size,
+ rd_size) != rd_size)
+ {
+ fprintf (stderr, "Failed to read ramdisk file\n");
+ Mfree ((void *)memptr);
+ boot_exit (EXIT_FAILURE);
+ }
+ close (rfd);
+ }
+
+ /* for those who want to debug */
+ if (debugflag)
+ {
+ if (bi.ramdisk_size)
+ printf ("RAM disk at %#lx, size is %ldK\n",
+ (u_long)(memptr + memreq - rd_size),
+ bi.ramdisk_size);
+
+ if (elf_kernel)
+ {
+ for (i = 0; i < kexec_elf.e_phnum; i++)
+ {
+ printf ("Kernel segment %d at %#lx, size %ld\n", i,
+ start_mem + kernel_phdrs[i].p_vaddr - PAGE_SIZE,
+ kernel_phdrs[i].p_memsz);
+ }
+ }
+ else
+ {
+ printf ("\nKernel text at %#lx, code size %d\n",
+ start_mem, kexec.a_text);
+ printf ("Kernel data at %#lx, data size %d\n",
+ start_mem + kexec.a_text, kexec.a_data );
+ printf ("Kernel bss at %#lx, bss size %d\n",
+ start_mem + kexec.a_text + kexec.a_data, kexec.a_bss );
+ }
+ printf ("\nboot_info is at %#lx\n",
+ start_mem + kernel_size);
+ printf ("\nKernel entry is %#lx\n",
+ elf_kernel ? kexec_elf.e_entry : kexec.a_entry);
+ printf ("ramdisk dest top is %#lx\n", bi.ramdisk_addr + rd_size);
+ printf ("ramdisk lower limit is %#lx\n",
+ (u_long)(memptr + memreq - rd_size));
+ printf ("ramdisk src top is %#lx\n", (u_long)(memptr + memreq));
+
+ printf ("Type a key to continue the Linux boot...");
+ fflush (stdout);
+ getchar();
+ }
+
+ printf("Booting Linux...\n");
+
+ sync ();
+
+ /* turn off interrupts... */
+ disable_interrupts();
+
+ /* turn off caches... */
+ disable_cache();
+
+ /* ..and any MMU translation */
+ disable_mmu();
+
+ /* ++guenther: allow reset if launched with MiNT */
+ *(long*)0x426 = 0;
+
+ /* copy mover code to a safe place if needed */
+ memcpy ((void *) 0x400, &copyall, &copyallend - &copyall);
+
+ /* setup stack */
+ change_stack ((void *) PAGE_SIZE);
+
+ /*
+ * On the Atari you can have two situations:
+ * 1. One piece of contiguous RAM (Falcon)
+ * 2. Two pieces of contiguous RAM (TT)
+ * In case 2 you can load your program into ST-ram and load your data in
+ * any old RAM you have left.
+ * In case 1 you could overwrite your own program when copying the
+ * kernel and ramdisk to their final positions.
+ * To solve this the mover code is copied to a safe place first.
+ * Then this program jumps to the mover code. After the mover code
+ * has finished it jumps to the start of the kernel in its new position.
+ * I thought the memory just after the interrupt vector table was a safe
+ * place because it is used by TOS to store some system variables.
+ * This range goes from 0x400 to approx. 0x5B0.
+ * This is more than enough for the miniscule mover routine (16 bytes).
+ */
+
+ jump_to_mover((char *) start_mem, memptr,
+ (char *) bi.ramdisk_addr + rd_size, memptr + memreq,
+ kernel_size + sizeof (bi),
+ rd_size,
+ (void *) 0x400);
+
+ for (;;);
+ /* NOTREACHED */
+}
+
+
+
+#define MAXARGS 30
+
+static void get_default_args( int *argc, char ***argv )
+
+{ FILE *f;
+ static char *nargv[MAXARGS];
+ char arg[256], *p;
+ int c, quote, state;
+
+ if (!(f = fopen( "bootargs", "r" )))
+ return;
+
+ *argc = 1;
+ if (***argv)
+ nargv[0] = **argv;
+ else
+ nargv[0] = "bootstrap";
+ *argv = nargv;
+
+ quote = state = 0;
+ p = arg;
+ while( (c = fgetc(f)) != EOF ) {
+
+ if (state == 0) {
+ /* outside args, skip whitespace */
+ if (!isspace(c)) {
+ state = 1;
+ p = arg;
+ }
+ }
+
+ if (state) {
+ /* inside an arg: copy it into 'arg', obeying quoting */
+ if (!quote && (c == '\'' || c == '"'))
+ quote = c;
+ else if (quote && c == quote)
+ quote = 0;
+ else if (!quote && isspace(c)) {
+ /* end of this arg */
+ *p = 0;
+ nargv[(*argc)++] = strdup(arg);
+ state = 0;
+ }
+ else
+ *p++ = c;
+ }
+ }
+ if (state) {
+ /* last arg finished by EOF! */
+ *p = 0;
+ nargv[(*argc)++] = strdup(arg);
+ }
+ fclose( f );
+
+ nargv[*argc] = 0;
+}
+
diff --git a/arch/m68k/boot/atari/bootstrap.h b/arch/m68k/boot/atari/bootstrap.h
new file mode 100644
index 000000000..5f8644f44
--- /dev/null
+++ b/arch/m68k/boot/atari/bootstrap.h
@@ -0,0 +1,147 @@
+/*
+** bootstrap.h -- This file is a part of the Atari bootloader.
+**
+** Copyright 1993 by Arjan Knor
+**
+** Modified by Andreas Schwab
+** - clear transparent translation registers
+**
+** This file is subject to the terms and conditions of the GNU General Public
+** License. See the file COPYING in the main directory of this archive
+** for more details.
+**
+*/
+
+#ifndef BOOTSTRAP_H
+#define BOOTSTRAP_H
+
+/* _MCH cookie values */
+#define MACH_ST 0
+#define MACH_STE 1
+#define MACH_TT 2
+#define MACH_FALCON 3
+
+/* some constants for memory handling */
+#define ST_RAM 0
+#define TT_RAM 1
+#define TT_RAM_BASE (u_long)(0x01000000)
+#define MB (1024 * 1024)
+#define START_MEM (bi.memory[0].addr)
+#define MEM_SIZE (bi.memory[0].size)
+
+/* the various CPU- and FPU-types */
+#define AFF_68000 (1)
+#define AFF_68020 (2)
+#define AFF_68030 (4)
+#define AFF_68040 (8)
+#define AFF_68881 (16)
+#define AFF_68882 (32)
+
+/* the possible OS-languages */
+#define USA 0
+#define FRG 1
+#define FRA 2
+#define UK 3
+#define SPA 4
+#define ITA 5
+#define SWE 6
+#define SWF 7
+#define SWG 8
+#define TUR 9
+#define FIN 10
+#define NOR 11
+#define DEN 12
+#define SAU 13
+#define HOL 14
+
+/* some inline functions */
+
+static __inline int fpu_idle_frame_size (void)
+{
+ char fpu_frame[216];
+ __asm__ __volatile__ ("fnop"::);
+ __asm__ __volatile__ ("fsave %0@" : : "a" (fpu_frame));
+ return fpu_frame[1];
+}
+
+static __inline void change_stack (u_long *stackp)
+{
+ __asm__ volatile ("movel %0,sp\n\t" :: "g" (stackp) : "sp");
+}
+
+static __inline void disable_interrupts (void)
+{
+ __asm__ volatile ("orw #0x700,sr":);
+}
+
+extern struct bootinfo bi;
+static __inline void disable_cache (void)
+{
+ __asm__ volatile ("movec %0,cacr" :: "d" (0));
+ if (bi.cputype & CPU_68060) {
+ /* '060: clear branch cache after disabling it;
+ * disable superscalar operation (and enable FPU) */
+ __asm__ volatile ("movec %0,cacr" :: "d" (0x00400000));
+ __asm__ volatile ("moveq #0,d0;"
+ ".long 0x4e7b0808" /* movec d0,pcr */
+ : /* no outputs */
+ : /* no inputs */
+ : "d0");
+ }
+}
+
+static __inline void disable_mmu (void)
+{
+ if (bi.cputype & (CPU_68040|CPU_68060)) {
+ __asm__ volatile ("moveq #0,d0;"
+ ".long 0x4e7b0003;" /* movec d0,tc */
+ ".long 0x4e7b0004;" /* movec d0,itt0 */
+ ".long 0x4e7b0005;" /* movec d0,itt1 */
+ ".long 0x4e7b0006;" /* movec d0,dtt0 */
+ ".long 0x4e7b0007" /* movec d0,dtt1 */
+ : /* no outputs */
+ : /* no inputs */
+ : "d0");
+ }
+ else {
+ __asm__ volatile ("subl #4,sp\n\t"
+ "pmove tc,sp@\n\t"
+ "bclr #7,sp@\n\t"
+ "pmove sp@,tc\n\t"
+ "addl #4,sp");
+ if (bi.cputype & CPU_68030) {
+ __asm__ volatile ("clrl sp@-\n\t"
+ ".long 0xf0170800\n\t" /* pmove sp@,tt0 */
+ ".long 0xf0170c00\n\t" /* pmove sp@,tt1 */
+ "addl #4,sp\n");
+ }
+ }
+}
+
+static __inline void jump_to_mover (void *, void *, void *, void *, int, int,
+ void *) __attribute__ ((noreturn));
+static __inline void jump_to_mover (void *kernel_start, void *mem_start,
+ void *ramdisk_end, void *mem_end,
+ int kernel_size, int ramdisk_size,
+ void *mover_addr)
+{
+ asm volatile ("movel %0,a0\n\t"
+ "movel %1,a1\n\t"
+ "movel %2,a2\n\t"
+ "movel %3,a3\n\t"
+ "movel %4,d0\n\t"
+ "movel %5,d1\n\t"
+ "jmp %6@\n"
+ : /* no outputs */
+ : "g" (kernel_start), "g" (mem_start),
+ "g" (ramdisk_end), "g" (mem_end),
+ "g" (kernel_size), "g" (ramdisk_size),
+ "a" (mover_addr)
+ : "a0", "a1", "a2", "a3", "d0", "d1");
+
+ /* Avoid warning that function may return */
+ for (;;) ;
+}
+
+#endif /* BOOTSTRAP_H */
+
diff --git a/arch/m68k/boot/atari/ethlance.c b/arch/m68k/boot/atari/ethlance.c
new file mode 100644
index 000000000..3b248c4af
--- /dev/null
+++ b/arch/m68k/boot/atari/ethlance.c
@@ -0,0 +1,435 @@
+
+#include <stdio.h>
+#include <string.h>
+
+#include "bootp.h"
+#include "ethlance.h"
+
+
+struct {
+ volatile unsigned short *memaddr;
+ volatile unsigned short *ioaddr;
+} lance_addr_list[] = {
+ { (void *)0xfe010000, (void *)0xfe00fff0 }, /* RieblCard VME in TT */
+ { (void *)0xfec10000, (void *)0xfec0fff0 }, /* RieblCard VME in MegaSTE
+ (highest byte stripped) */
+ { (void *)0xfee00000, (void *)0xfeff7000 }, /* RieblCard in ST
+ (highest byte stripped) */
+ { (void *)0xfecf0000, (void *)0xfecffff0 }, /* PAMCard VME in TT and MSTE
+ (highest byte stripped) */
+};
+
+#define N_LANCE_ADDR (sizeof(lance_addr_list)/sizeof(*lance_addr_list))
+
+#define TX_RING_SIZE 1
+#define TX_RING_LEN_BITS 0
+
+#define RX_RING_SIZE 16
+#define RX_RING_LEN_BITS (4 << 5)
+
+#define offsetof(type,elt) ((unsigned long)(&(((type *)0)->elt)))
+
+/* The LANCE Rx and Tx ring descriptors. */
+struct lance_rx_head {
+ unsigned short base; /* Low word of base addr */
+ volatile unsigned char flag;
+ unsigned char base_hi; /* High word of base addr (unused) */
+ short buf_length; /* This length is 2s complement! */
+ short msg_length; /* This length is "normal". */
+};
+
+struct lance_tx_head {
+ unsigned short base; /* Low word of base addr */
+ volatile unsigned char flag;
+ unsigned char base_hi; /* High word of base addr (unused) */
+ short length; /* Length is 2s complement! */
+ volatile short misc;
+};
+
+struct ringdesc {
+ unsigned short adr_lo; /* Low 16 bits of address */
+ unsigned char len; /* Length bits */
+ unsigned char adr_hi; /* High 8 bits of address (unused) */
+};
+
+struct lance_packet {
+ volatile unsigned char data[PKTLEN];
+};
+
+/* The LANCE initialization block, described in databook. */
+struct lance_init_block {
+ unsigned short mode; /* Pre-set mode */
+ unsigned char hwaddr[6]; /* Physical ethernet address */
+ unsigned filter[2]; /* Multicast filter (unused). */
+ /* Receive and transmit ring base, along with length bits. */
+ struct ringdesc rx_ring;
+ struct ringdesc tx_ring;
+};
+
+/* The whole layout of the Lance shared memory */
+struct lance_memory {
+ struct lance_init_block init;
+ struct lance_tx_head tx_head[TX_RING_SIZE];
+ struct lance_rx_head rx_head[RX_RING_SIZE];
+ struct lance_packet tx_packet[TX_RING_SIZE];
+ struct lance_packet rx_packet[TX_RING_SIZE];
+};
+
+#define RIEBL_MAGIC 0x09051990
+#define RIEBL_MAGIC_ADDR ((unsigned long *)(((char *)MEM) + 0xee8a))
+#define RIEBL_HWADDR_ADDR ((unsigned char *)(((char *)MEM) + 0xee8e))
+#define RIEBL_IVEC_ADDR ((unsigned short *)(((char *)MEM) + 0xfffe))
+
+struct lance_ioreg {
+/* base+0x0 */ volatile unsigned short data;
+/* base+0x2 */ volatile unsigned short addr;
+ unsigned char _dummy1[3];
+/* base+0x7 */ volatile unsigned char ivec;
+ unsigned char _dummy2[5];
+/* base+0xd */ volatile unsigned char eeprom;
+ unsigned char _dummy3;
+/* base+0xf */ volatile unsigned char mem;
+};
+
+enum lance_type {
+ OLD_RIEBL, /* old Riebl card without battery */
+ NEW_RIEBL, /* new Riebl card with battery */
+ PAM_CARD /* PAM card with EEPROM */
+} CardType;
+
+HWADDR dev_addr;
+
+/* This is a default address for the old RieblCards without a battery
+ * that have no ethernet address at boot time. 00:00:36:04 is the
+ * prefix for Riebl cards, the 00:00 at the end is arbitrary.
+ */
+
+HWADDR OldRieblDefHwaddr = {
+ 0x00, 0x00, 0x36, 0x04, 0x00, 0x00
+};
+
+struct lance_ioreg *IO;
+struct lance_memory *MEM;
+
+#define DREG IO->data
+#define AREG IO->addr
+#define REGA(a) ( AREG = (a), DREG )
+
+int CurRx;
+
+
+/* Definitions for the Lance */
+
+/* tx_head flags */
+#define TMD1_ENP 0x01
+#define TMD1_STP 0x02
+#define TMD1_DEF 0x04
+#define TMD1_ONE 0x08
+#define TMD1_MORE 0x10
+#define TMD1_ERR 0x40
+#define TMD1_OWN 0x80
+
+#define TMD1_OWN_CHIP TMD1_OWN
+#define TMD1_OWN_HOST 0
+
+/* tx_head misc field */
+#define TMD3_TDR 0x03FF
+#define TMD3_RTRY 0x0400
+#define TMD3_LCAR 0x0800
+#define TMD3_LCOL 0x1000
+#define TMD3_UFLO 0x4000
+#define TMD3_BUFF3 0x8000
+
+/* rx_head flags */
+#define RMD1_ENP 0x01
+#define RMD1_STP 0x02
+#define RMD1_BUFF 0x04
+#define RMD1_CRC 0x08
+#define RMD1_OFLO 0x10
+#define RMD1_FRAM 0x20
+#define RMD1_ERR 0x40
+#define RMD1_OWN 0x80
+
+#define RMD1_OWN_CHIP RMD1_OWN
+#define RMD1_OWN_HOST 0
+
+/* register names */
+#define CSR0 0
+#define CSR1 1
+#define CSR2 2
+#define CSR3 3
+
+/* CSR0 */
+#define CSR0_INIT 0x0001 /* initialize */
+#define CSR0_STRT 0x0002 /* start */
+#define CSR0_STOP 0x0004 /* stop */
+#define CSR0_TDMD 0x0008 /* transmit demand */
+#define CSR0_TXON 0x0010 /* transmitter on */
+#define CSR0_RXON 0x0020 /* receiver on */
+#define CSR0_INEA 0x0040 /* interrupt enable */
+#define CSR0_INTR 0x0080 /* interrupt active */
+#define CSR0_IDON 0x0100 /* initialization done */
+#define CSR0_TINT 0x0200 /* transmitter interrupt */
+#define CSR0_RINT 0x0400 /* receiver interrupt */
+#define CSR0_MERR 0x0800 /* memory error */
+#define CSR0_MISS 0x1000 /* missed frame */
+#define CSR0_CERR 0x2000 /* carrier error (no heartbeat :-) */
+#define CSR0_BABL 0x4000 /* babble: tx-ed too many bits */
+#define CSR0_ERR 0x8000 /* error */
+
+/* CSR3 */
+#define CSR3_BCON 0x0001
+#define CSR3_ACON 0x0002
+#define CSR3_BSWP 0x0004
+
+
+#define HZ 200
+#define _hz_200 (*(volatile unsigned long *)0x4ba)
+
+
+
+
+/***************************** Prototypes *****************************/
+
+static int lance_probe( void );
+static int addr_readable( volatile void *regp, int wordflag );
+static int lance_init( void );
+static void lance_get_hwaddr( HWADDR *addr );
+static int lance_snd( Packet *pkt, int len );
+static int lance_rcv( Packet *pkt, int *len );
+
+/************************* End of Prototypes **************************/
+
+
+
+ETHIF_SWITCH LanceSwitch = {
+ lance_probe, lance_init, lance_get_hwaddr,
+ lance_snd, lance_rcv
+};
+
+
+static int lance_probe( void )
+
+{ int i;
+
+ for( i = 0; i < N_LANCE_ADDR; ++i ) {
+ if (addr_readable( lance_addr_list[i].memaddr, 1 ) &&
+ (lance_addr_list[i].memaddr[0] = 1,
+ lance_addr_list[i].memaddr[0] == 1) &&
+ (lance_addr_list[i].memaddr[0] = 0,
+ lance_addr_list[i].memaddr[0] == 0) &&
+ addr_readable( lance_addr_list[i].ioaddr, 1 )) {
+ break;
+ }
+ }
+ if (i == N_LANCE_ADDR) return( -1 );
+
+ IO = (struct lance_ioreg *)lance_addr_list[i].ioaddr;
+ MEM = (struct lance_memory *)lance_addr_list[i].memaddr;
+ REGA( CSR0 ) = CSR0_STOP;
+
+ return( 0 );
+}
+
+
+static int addr_readable( volatile void *regp, int wordflag )
+
+{ int ret;
+ long *vbr, save_berr;
+
+ __asm__ __volatile__ ( "movec %/vbr,%0" : "=r" (vbr) : );
+ save_berr = vbr[2];
+
+ __asm__ __volatile__
+ ( "movel %/sp,%/d1\n\t"
+ "movel #Lberr,%2@\n\t"
+ "moveq #0,%0\n\t"
+ "tstl %3\n\t"
+ "bne 1f\n\t"
+ "tstb %1@\n\t"
+ "bra 2f\n"
+"1: tstw %1@\n"
+"2: moveq #1,%0\n"
+"Lberr: movel %/d1,%/sp"
+ : "=&d" (ret)
+ : "a" (regp), "a" (&vbr[2]), "rm" (wordflag)
+ : "d1", "memory"
+ );
+
+ vbr[2] = save_berr;
+
+ return( ret );
+}
+
+
+static int lance_init( void )
+
+{ int i;
+
+ /* Now test for type: If the eeprom I/O port is readable, it is a
+ * PAM card */
+ if (addr_readable( &(IO->eeprom), 0 )) {
+ /* Switch back to Ram */
+ i = IO->mem;
+ CardType = PAM_CARD;
+ }
+ else if (*RIEBL_MAGIC_ADDR == RIEBL_MAGIC) {
+ CardType = NEW_RIEBL;
+ }
+ else
+ CardType = OLD_RIEBL;
+
+ /* Get the ethernet address */
+ switch( CardType ) {
+ case OLD_RIEBL:
+ /* No ethernet address! (Set some default address) */
+ memcpy( dev_addr, OldRieblDefHwaddr, ETHADDRLEN );
+ break;
+ case NEW_RIEBL:
+ memcpy( dev_addr, RIEBL_HWADDR_ADDR, ETHADDRLEN );
+ break;
+ case PAM_CARD:
+ i = IO->eeprom;
+ for( i = 0; i < ETHADDRLEN; ++i )
+ dev_addr[i] =
+ ((((unsigned short *)MEM)[i*2] & 0x0f) << 4) |
+ ((((unsigned short *)MEM)[i*2+1] & 0x0f));
+ i = IO->mem;
+ break;
+ }
+
+ MEM->init.mode = 0x0000; /* Disable Rx and Tx. */
+ for( i = 0; i < ETHADDRLEN; i++ )
+ MEM->init.hwaddr[i] = dev_addr[i^1]; /* <- 16 bit swap! */
+ MEM->init.filter[0] = 0x00000000;
+ MEM->init.filter[1] = 0x00000000;
+ MEM->init.rx_ring.adr_lo = offsetof( struct lance_memory, rx_head );
+ MEM->init.rx_ring.adr_hi = 0;
+ MEM->init.rx_ring.len = RX_RING_LEN_BITS;
+ MEM->init.tx_ring.adr_lo = offsetof( struct lance_memory, tx_head );
+ MEM->init.tx_ring.adr_hi = 0;
+ MEM->init.tx_ring.len = TX_RING_LEN_BITS;
+
+ REGA( CSR3 ) = CSR3_BSWP | (CardType == PAM_CARD ? CSR3_ACON : 0);
+ REGA( CSR2 ) = 0;
+ REGA( CSR1 ) = 0;
+ REGA( CSR0 ) = CSR0_INIT | CSR0_STRT;
+
+ i = 1000000;
+ while( i-- > 0 )
+ if (DREG & CSR0_IDON)
+ break;
+ if (i < 0 || (DREG & CSR0_ERR)) {
+ DREG = CSR0_STOP;
+ return( -1 );
+ }
+ DREG = CSR0_IDON;
+
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ MEM->tx_head[i].base = offsetof( struct lance_memory, tx_packet[i] );
+ MEM->tx_head[i].flag = TMD1_OWN_HOST;
+ MEM->tx_head[i].base_hi = 0;
+ MEM->tx_head[i].length = 0;
+ MEM->tx_head[i].misc = 0;
+ }
+
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ MEM->rx_head[i].base = offsetof( struct lance_memory, rx_packet[i] );
+ MEM->rx_head[i].flag = TMD1_OWN_CHIP;
+ MEM->rx_head[i].base_hi = 0;
+ MEM->rx_head[i].buf_length = -PKTLEN;
+ MEM->rx_head[i].msg_length = 0;
+ }
+ CurRx = 0;
+
+ return( 0 );
+}
+
+
+static void lance_get_hwaddr( HWADDR *addr )
+
+{
+ memcpy( addr, dev_addr, ETHADDRLEN );
+}
+
+
+static int lance_snd( Packet *pkt, int len )
+
+{ unsigned long timeout;
+
+ /* The old LANCE chips doesn't automatically pad buffers to min. size. */
+ len = (len < 60) ? 60 : len;
+ /* PAM-Card has a bug: Can only send packets with even number of bytes! */
+ if (CardType == PAM_CARD && (len & 1))
+ ++len;
+
+ MEM->tx_head[0].length = -len;
+ MEM->tx_head[0].misc = 0;
+ memcpy( (void *)&MEM->tx_packet[0].data, pkt, len );
+ MEM->tx_head[0].base = offsetof(struct lance_memory, tx_packet[0]);
+ MEM->tx_head[0].base_hi = 0;
+ MEM->tx_head[0].flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP;
+
+ /* Trigger an immediate send poll. */
+ REGA( CSR0 ) = CSR0_TDMD;
+
+ /* Wait for packet being sent */
+ timeout = _hz_200 + 3*HZ;
+ while( (MEM->tx_head[0].flag & TMD1_OWN_CHIP) &&
+ !MEM->tx_head[0].misc &&
+ _hz_200 < timeout )
+ ;
+
+ if ((MEM->tx_head[0].flag & TMD1_OWN) == TMD1_OWN_HOST &&
+ !(MEM->tx_head[0].misc & TMD1_ERR))
+ /* sent ok */
+ return( 0 );
+
+ /* failure */
+ if (_hz_200 >= timeout)
+ return( ETIMEO );
+ if (MEM->tx_head[0].misc & TMD3_UFLO) {
+ /* On FIFO errors, must re-turn on TX! */
+ DREG = CSR0_STRT;
+ }
+
+ return( ESEND );
+}
+
+
+static int lance_rcv( Packet *pkt, int *len )
+
+{ unsigned long timeout;
+ int stat;
+
+ /* Wait for a packet */
+ timeout = _hz_200 + 4*HZ;
+ while( (MEM->rx_head[CurRx].flag & TMD1_OWN_CHIP) &&
+ _hz_200 < timeout )
+ ;
+ /* Not ours -> was a timeout */
+ if (((stat = MEM->rx_head[CurRx].flag) & TMD1_OWN) == TMD1_OWN_CHIP)
+ return( ETIMEO );
+
+ /* Check for errors */
+ if (stat != (RMD1_ENP|RMD1_STP)) {
+ MEM->rx_head[CurRx].flag &= (RMD1_ENP|RMD1_STP);
+ if (stat & RMD1_FRAM) return( EFRAM );
+ if (stat & RMD1_OFLO) return( EOVERFL );
+ if (stat & RMD1_CRC) return( ECRC );
+ return( ERCV );
+ }
+
+ /* Get the packet */
+ *len = MEM->rx_head[CurRx].msg_length & 0xfff;
+ memcpy( pkt, (void *)&MEM->rx_packet[CurRx].data, *len );
+
+ /* Give the buffer back to the chip */
+ MEM->rx_head[CurRx].buf_length = -PKTLEN;
+ MEM->rx_head[CurRx].flag |= RMD1_OWN_CHIP;
+ CurRx = (CurRx + 1) % RX_RING_SIZE;
+
+ return( 0 );
+}
+
+
diff --git a/arch/m68k/boot/atari/ethlance.h b/arch/m68k/boot/atari/ethlance.h
new file mode 100644
index 000000000..4f9c90241
--- /dev/null
+++ b/arch/m68k/boot/atari/ethlance.h
@@ -0,0 +1,7 @@
+
+#ifndef _ethlance_h
+#define _ethlance_h
+
+extern ETHIF_SWITCH LanceSwitch;
+
+#endif /* _ethlance_h */
diff --git a/arch/m68k/boot/atari/sysvars.h b/arch/m68k/boot/atari/sysvars.h
new file mode 100644
index 000000000..087d9f695
--- /dev/null
+++ b/arch/m68k/boot/atari/sysvars.h
@@ -0,0 +1,22 @@
+typedef struct _osheader
+{
+ unsigned short os_entry;
+ unsigned short os_version;
+ void *reseth;
+ struct _osheader *os_beg;
+ void *os_end;
+ long os_rsv1;
+ void *os_magic;
+ long os_date;
+ unsigned short os_conf;
+ unsigned short os_dosdate;
+ char **p_root;
+ unsigned char **pkbshift;
+ void **p_run;
+ char *p_rsv2;
+} OSHEADER;
+
+#define phystop ((unsigned long *)0x42e)
+#define _sysbase ((OSHEADER **)0x4f2)
+#define _p_cookies ((unsigned long **)0x5a0)
+#define ramtop ((unsigned long *)0x5a4)