From 3b75784a5cf83b34ba7b4ecfe2b80908cedb2982 Mon Sep 17 00:00:00 2001
From: Waldemar Brodkorb <wbx@openadk.org>
Date: Mon, 16 Feb 2015 12:42:44 -0600
Subject: prepare for Sun Voyager.

Bootloader needs a.out formatted kernel.
Unfortunately I get "Illegal instruction" after loading
a.out kernel via TFTP. Old gentoo 2.6 kernel boots fine.
---
 package/elftoaout/Makefile                    |  31 ++
 package/elftoaout/src/elftoaout.c             | 618 ++++++++++++++++++++++++++
 target/config/Config.in.kernel                |   5 +
 target/config/Config.in.tools                 |   4 +
 target/linux/config/Config.in.graphics        |  13 +
 target/linux/patches/3.19/sparc-aout.patch    |  24 +
 target/linux/patches/3.4.103/sparc-aout.patch |  24 +
 target/sparc/Makefile                         |  13 +
 target/sparc/kernel/sun-voyager               |   9 +
 target/sparc/systems/sun-voyager              |  11 +
 toolchain/gcc/Makefile                        |   4 +
 11 files changed, 756 insertions(+)
 create mode 100644 package/elftoaout/Makefile
 create mode 100644 package/elftoaout/src/elftoaout.c
 create mode 100644 target/linux/patches/3.19/sparc-aout.patch
 create mode 100644 target/linux/patches/3.4.103/sparc-aout.patch
 create mode 100644 target/sparc/kernel/sun-voyager
 create mode 100644 target/sparc/systems/sun-voyager

diff --git a/package/elftoaout/Makefile b/package/elftoaout/Makefile
new file mode 100644
index 000000000..9f374e31d
--- /dev/null
+++ b/package/elftoaout/Makefile
@@ -0,0 +1,31 @@
+# This file is part of the OpenADK project. OpenADK is copyrighted
+# material, please see the LICENCE file in the top-level directory.
+
+include $(ADK_TOPDIR)/rules.mk
+
+PKG_NAME:=		elftoaout
+PKG_VERSION:=		2.3
+PKG_RELEASE:=		1
+PKG_DESCR:=		elf to a.out converter
+PKG_SECTION:=		sys/misc
+
+PKG_CFLINE_ELFTOAOUT:=	depends on ADK_HOST_ONLY
+
+NO_DISTFILES:=		1
+
+include $(ADK_TOPDIR)/mk/host.mk
+include $(ADK_TOPDIR)/mk/package.mk
+
+$(eval $(call HOST_template,ELFTOAOUT,elftoaout,$(PKG_VERSION)-$(PKG_RELEASE)))
+
+HOST_STYLE:=		manual
+
+host-build:
+	$(HOST_CC) $(HOST_CFLAGS) -o $(WRKBUILD)/elftoaout $(WRKBUILD)/elftoaout.c
+
+elftoaout-hostinstall:
+	$(INSTALL_DIR) $(STAGING_HOST_DIR)/usr/bin
+	$(INSTALL_BIN) $(WRKBUILD)/elftoaout $(STAGING_HOST_DIR)/usr/bin
+
+include $(ADK_TOPDIR)/mk/host-bottom.mk
+include $(ADK_TOPDIR)/mk/pkg-bottom.mk
diff --git a/package/elftoaout/src/elftoaout.c b/package/elftoaout/src/elftoaout.c
new file mode 100644
index 000000000..943c9ef34
--- /dev/null
+++ b/package/elftoaout/src/elftoaout.c
@@ -0,0 +1,618 @@
+/* $Id: elftoaout.c,v 1.1.1.1 1998/03/02 16:30:10 jj Exp $
+ * elftoaout.c: ELF to a.out convertor for SPARC and SPARC64 bootstraps
+ *
+ * Copyright (C) 1995,1996 Pete A. Zaitcev (zaitcev@vger.rutgers.edu)
+ * Copyright (C) 1997 Jakub Jelinek (jj@ultra.linux.cz)
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software Foundation,
+ *  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef linux
+#include <linux/elf.h>
+#define ELFDATA2MSB   2
+#else
+#include <sys/elf.h>
+#endif
+
+#define swab16(x)  (((x)<<8&0xFF00)|((x)>>8&0x00FF))
+#define swab32(x)  (((x)<<24&0xFF000000)|((x)<<8&0x00FF0000)|((x)>>24&0x000000FF)|((x)>>8&0x0000FF00))
+#define swab64(x)  ((((unsigned long long)(swab32((unsigned int)x))) << 32) | (swab32(((unsigned long long)x)>>32)))
+
+/* We carry a.out header here in order to compile the thing on Solaris */
+
+#define	AMAGIC	    0x01030107
+#define	CMAGIC	    0x01030108
+
+typedef struct {
+	unsigned long	a_magic;	/* magic number */
+	unsigned long	a_text;		/* size of text segment */
+	unsigned long	a_data;		/* size of initialized data */
+	unsigned long	a_bss;		/* size of uninitialized data */
+	unsigned long	a_syms;		/* size of symbol table || checksum */
+	unsigned long	a_entry;	/* entry point */
+	unsigned long	a_trsize;	/* size of text relocation */
+	unsigned long	a_drsize;	/* size of data relocation */
+} Exec;
+
+
+typedef struct {
+	const char *iname;
+	const char *oname;
+	int sun4_mode;
+	int version;
+	int swab;
+	int sparc64;
+	int csum;
+	/* friend void Usage(void); */
+} Application;
+
+typedef struct {
+	Elf32_Phdr *tab;
+	unsigned len;
+} ProgTable;
+
+typedef struct {
+	Elf64_Phdr *tab;
+	unsigned len;
+} ProgTable64;
+
+void get_ptab(ProgTable *t, FILE *inp, const Elf32_Ehdr *h);
+void get_ptab64(ProgTable64 *t, FILE *inp, const Elf64_Ehdr *h);
+void print_ptab(ProgTable *t);
+void print_ptab64(ProgTable64 *t);
+
+typedef struct {
+	char *buf;                /* Image data */
+	unsigned len;             /* Length of buffer */
+	unsigned bss;             /* Length of extra data */
+} Segment;
+
+void load_image(Segment *t, const ProgTable *h, FILE *inp);
+void load_image64(Segment *t, const ProgTable64 *h, FILE *inp);
+void store_image(Segment *t, FILE *out);
+
+Application prog;
+
+void parse_args(Application *t, unsigned argc, const char **argv);
+void get_header(Elf32_Ehdr *t, FILE *inp);
+void Usage(void);
+void Version(void);
+int ipchksum(unsigned char *data, int leng);
+
+int main(int argc, const char **argv)
+{
+	FILE *inp = stdin;
+	FILE *out;
+	union {
+		Elf32_Ehdr h32;
+		Elf64_Ehdr h64;
+	} hdrb;
+	ProgTable pt;
+	Segment image;
+
+	parse_args(&prog, argc, argv);
+
+	if (prog.version) Version();
+
+	if (freopen(prog.iname, "r", stdin) == NULL) {
+		fprintf(stderr, "Cannot open \"%s\"\n", prog.iname);
+		exit(1);
+	}
+
+	if ((out = fopen(prog.oname, "w")) == NULL) {
+		fprintf(stderr, "Cannot open \"%s\"\n", prog.oname);
+		exit(1);
+	}
+
+	get_header(&hdrb.h32, inp);
+	/* Now can use longer fields */
+
+	if (hdrb.h32.e_type != ET_EXEC) {
+		fprintf(stderr, "Wrong ELF file type\n");
+		exit(1);
+	}
+
+	if (prog.sparc64) {
+		get_ptab64((ProgTable64 *)&pt, inp, &hdrb.h64);
+		print_ptab64((ProgTable64 *)&pt);
+		load_image64(&image, (ProgTable64 *)&pt, inp);
+	} else { 
+		get_ptab(&pt, inp, &hdrb.h32);
+		print_ptab(&pt);
+		load_image(&image, &pt, inp);
+	}
+
+	store_image(&image, out);
+
+	fclose(out);
+	exit(0);
+}
+
+void parse_args( Application *t, unsigned argc, const char **argv ){
+	const char *arg;
+	union {
+		char c[4];
+		int i;
+	} bord;
+
+	--argc;  argv++;
+
+	/* construct invariant */
+	t->sparc64 = 0;
+	t->iname = 0;
+	t->oname = 0;
+	t->sun4_mode = 0;
+	t->version = 0;
+	t->csum = 0;
+	bord.i = 1;
+	t->swab = (bord.c[0] == 1);
+	/* adjust */
+	while ((arg = *argv++) != 0) {
+		if (arg[0] == '-') {
+			if (arg[1] == 'o') {
+				if ((arg = *argv++) == 0) Usage();
+				if (t->oname != 0) Usage();
+				t->oname = arg;
+			} else if (arg[1] == 'b') {
+				t->sun4_mode = 1;
+			} else if (arg[1] == 'c') {
+				t->csum = 1;
+			} else if (arg[1] == 'V') {
+				t->version = 1;
+			} else {
+				Usage();
+			}
+		} else {
+			if (t->iname != 0) Usage();
+			t->iname = arg;
+		}
+	}
+	if (t->iname == 0) Usage();      /* We do not read from the stdin */
+	if (t->oname == 0) t->oname = "a.out";
+	if (t->csum && t->sun4_mode) Usage ();	/* Checksum lives in header. */
+}
+
+void get_header(Elf32_Ehdr *t, FILE *inp) {
+
+        if (fread((void*) t, sizeof(Elf64_Ehdr), 1, inp) != 1) {
+		fprintf(stderr, "Read error on header\n");
+		exit(1);
+	}
+
+	if (t->e_ident[EI_MAG0] != ELFMAG0 ||
+		t->e_ident[EI_MAG1] != ELFMAG1 ||
+		t->e_ident[EI_MAG2] != ELFMAG2 ||
+		t->e_ident[EI_MAG3] != ELFMAG3)
+	{
+		fprintf(stderr, "Not an ELF file\n");
+		exit(1);
+	}
+
+	if (t->e_ident[EI_CLASS] != ELFCLASS32) {
+		if (t->e_ident[EI_CLASS] != ELFCLASS64) {
+			fprintf(stderr, "Neither 32bit nor 64bit ELF\n");
+			exit(1);
+		} else {
+			prog.sparc64 = 1;
+		}
+	}
+
+	if (t->e_ident[EI_DATA] != ELFDATA2MSB) {
+		fprintf(stderr, "Not an MSB ELF\n");
+		exit(1);
+	}
+	/* There is no need for the run-time check actualy. XXX */
+	if (prog.swab) {
+		if (!prog.sparc64) {
+			t->e_type = swab16(t->e_type);
+			t->e_machine = swab16(t->e_machine);
+			t->e_version = swab32(t->e_version);
+			t->e_entry = swab32(t->e_entry);
+			t->e_phoff = swab32(t->e_phoff);
+			t->e_shoff = swab32(t->e_shoff);
+			t->e_flags = swab32(t->e_flags);
+			t->e_ehsize = swab16(t->e_ehsize);
+			t->e_phentsize = swab16(t->e_phentsize);
+			t->e_phnum = swab16(t->e_phnum);
+			t->e_shentsize = swab16(t->e_shentsize);
+			t->e_shnum = swab16(t->e_shnum);
+			t->e_shstrndx = swab16(t->e_shstrndx);
+		} else {
+			Elf64_Ehdr *u = (Elf64_Ehdr *)t;
+			u->e_type = swab16(u->e_type);
+			u->e_machine = swab16(u->e_machine);
+			u->e_version = swab32(u->e_version);
+			u->e_entry = swab64(u->e_entry);
+			u->e_phoff = swab64(u->e_phoff);
+			u->e_shoff = swab64(u->e_shoff);
+			u->e_flags = swab32(u->e_flags);
+			u->e_ehsize = swab16(u->e_ehsize);
+			u->e_phentsize = swab16(u->e_phentsize);
+			u->e_phnum = swab16(u->e_phnum);
+			u->e_shentsize = swab16(u->e_shentsize);
+			u->e_shnum = swab16(u->e_shnum);
+			u->e_shstrndx = swab16(u->e_shstrndx);
+		}
+	}
+}
+
+void get_ptab(ProgTable *t, FILE *inp, const Elf32_Ehdr *h) {
+	unsigned x;
+
+	/** fprintf(stderr, "Program header table off = 0x%x\n",
+		(unsigned) h->e_phoff); **/
+	if (h->e_phoff == 0) {
+		fprintf(stderr, "No Program Header Table\n");
+		exit(1);
+	}
+
+	/**
+	fprintf(stderr, "Program header table entry size = 0x%x\n", (unsigned) h->e_phentsize);
+	fprintf(stderr, "Program header table entries total = 0x%x\n", (unsigned) h->e_phnum);
+	**/
+
+	t->len = h->e_phnum;
+	t->tab = malloc(sizeof(Elf32_Phdr) * t->len);
+	if (t->tab == 0) {
+		fprintf(stderr, "No core for program table\n");
+		exit(1);
+	}
+
+	for (x = 0; x < t->len; x++) {
+		Elf32_Phdr *p = &t->tab[ x ];
+		if (fseek(inp, (long) (h->e_phoff + h->e_phentsize*x), SEEK_SET) == -1) {
+			fprintf(stderr, "Seek error on program table\n");
+			exit(1);
+		}
+		if (fread((char *)p, sizeof(Elf32_Phdr), 1, inp) != 1) {
+			fprintf(stderr, "Read error on program table\n");
+			exit(1);
+		}
+		if (prog.swab) {
+			p->p_type = swab32(p->p_type);
+			p->p_offset = swab32(p->p_offset);
+			p->p_vaddr = swab32(p->p_vaddr);
+			p->p_paddr = swab32(p->p_paddr);
+			p->p_filesz = swab32(p->p_filesz);
+			p->p_memsz = swab32(p->p_memsz);
+			p->p_flags = swab32(p->p_flags);
+			p->p_align = swab32(p->p_align);
+		}
+	}
+}
+
+void get_ptab64(ProgTable64 *t, FILE *inp, const Elf64_Ehdr *h) {
+	unsigned x;
+
+	if (h->e_phoff == 0) {
+		fprintf(stderr, "No Program Header Table\n");
+		exit(1);
+	}
+
+	t->len = h->e_phnum;
+	t->tab = malloc(sizeof(Elf64_Phdr) * t->len);
+	if (t->tab == 0) {
+		fprintf(stderr, "No core for program table\n");
+		exit(1);
+	}
+
+	for (x = 0; x < t->len; x++) {
+		Elf64_Phdr *p = &t->tab[ x ];
+		if (fseek(inp, (long) (h->e_phoff + h->e_phentsize*x), SEEK_SET) == -1) {
+			fprintf(stderr, "Seek error on program table\n");
+			exit(1);
+		}
+		if (fread((char *)p, sizeof(Elf64_Phdr), 1, inp) != 1) {
+			fprintf(stderr, "Read error on program table\n");
+			exit(1);
+		}
+		if (prog.swab) {
+			p->p_type = swab32(p->p_type);
+			p->p_offset = swab64(p->p_offset);
+			p->p_vaddr = swab64(p->p_vaddr);
+			p->p_paddr = swab64(p->p_paddr);
+			p->p_filesz = swab64(p->p_filesz);
+			p->p_memsz = swab64(p->p_memsz);
+			p->p_flags = swab32(p->p_flags);
+			p->p_align = swab64(p->p_align);
+		}
+	}
+}
+
+void print_ptab(ProgTable *t) {
+	unsigned x;
+	const Elf32_Phdr *p;
+
+	for (x = 0; x < t->len; x++) {
+		p = &t->tab[ x ];
+		printf("PT %d Entry: ", x);
+		switch (p->p_type) {
+		case PT_NULL:
+			printf("NULL");
+			break;
+		case PT_LOAD:
+			printf("Loadable to 0x%x[0x%x] from 0x%x[0x%x] align 0x%x",
+				p->p_vaddr, p->p_memsz, p->p_offset, p->p_filesz,
+				p->p_align);
+			break;
+		case PT_DYNAMIC:
+			printf("Dynamic");
+			break;
+		case PT_INTERP:
+			printf("Interpreter");
+			break;
+		case PT_NOTE:
+			printf("Note");
+			break;
+		case PT_SHLIB:
+			printf("SHLIB");
+			break;
+		case PT_PHDR:
+			printf("Header Locator");
+			break;
+		default:
+			if( p->p_type >= PT_LOPROC && p->p_type <= PT_HIPROC ){
+				printf("CPU specific");
+			} else {
+				printf("unknown");
+			}
+		}
+		printf("\n");
+	}
+}
+
+void print_ptab64(ProgTable64 *t) {
+	unsigned x;
+	const Elf64_Phdr *p;
+
+	for (x = 0; x < t->len; x++) {
+		p = &t->tab[ x ];
+		printf("PT %d Entry: ", x);
+		switch (p->p_type) {
+		case PT_NULL:
+			printf("NULL");
+			break;
+		case PT_LOAD:
+			printf("Loadable to 0x%Lx[0x%Lx] from 0x%Lx[0x%Lx] align 0x%Lx",
+				p->p_vaddr, p->p_memsz, p->p_offset, p->p_filesz,
+				p->p_align);
+			break;
+		case PT_DYNAMIC:
+			printf("Dynamic");
+			break;
+		case PT_INTERP:
+			printf("Interpreter");
+			break;
+		case PT_NOTE:
+			printf("Note");
+			break;
+		case PT_SHLIB:
+			printf("SHLIB");
+			break;
+		case PT_PHDR:
+			printf("Header Locator");
+			break;
+		default:
+			if( p->p_type >= PT_LOPROC && p->p_type <= PT_HIPROC ){
+				printf("CPU specific");
+			} else {
+				printf("unknown");
+			}
+		}
+		printf("\n");
+	}
+}
+
+void load_image(Segment *t, const ProgTable *tp, FILE *inp) {
+	Elf32_Phdr *p, *q;
+	unsigned x;
+	unsigned long off, len;
+
+	p = 0;
+	for (x = 0; x < tp->len; x++) {
+		if (tp->tab[x].p_type == PT_LOAD) {
+			if (p != 0) {
+				q = &tp->tab[x];
+				off = (q->p_offset - p->p_offset);
+				if (q->p_vaddr - p->p_vaddr == off &&
+				    q->p_paddr - p->p_paddr == off &&
+				    p->p_memsz == p->p_filesz &&
+				    p->p_memsz <= off) {
+					p->p_filesz = off + q->p_filesz;
+					p->p_memsz = off + q->p_memsz;
+				} else {
+					fprintf(stderr, "Several loadable segments\n");
+					exit(1);
+				}
+			} else
+				p = &tp->tab[x];
+		}
+	}
+	if (p == 0) {
+		fprintf(stderr, "No loadable segments\n");
+		exit(1);
+	}
+
+	/* Now base address is 0xf0004000. */
+	/** if (p->p_vaddr != 0x4000) {		**/
+	/**	fprintf(stderr, "Warning: Load address is not 0x4000\n"); **/
+	/** }					**/
+
+	/*
+	 * This trick is from ecd@Pool.Informatik.RWTH-Aachen.DE,
+	 * needed for native binutils-2.6.x.
+	 */
+	off = p->p_offset;
+	len = p->p_filesz;
+	if (off == 0) {
+		/* Surely we are about to load garbage, try to skip page 0. */
+		if (p->p_vaddr != 0xf0000000) {
+			fprintf(stderr, "Warning: Kernel workaround on non-kernel image\n");
+		}
+		off += 0x4000;
+		len -= 0x4000;
+	}
+
+	t->buf = malloc(len);
+	if (t->buf == 0) {
+		fprintf(stderr, "No core for program image\n");
+		exit(1);
+	}
+	t->len = len;
+	t->bss = p->p_memsz - p->p_filesz;
+
+	if (fseek(inp, (long)off, SEEK_SET) == -1) {
+		fprintf(stderr, "Seek error on program image\n");
+		exit(1);
+	}
+	if (fread(t->buf, 1, len, inp) != len) {
+		fprintf(stderr, "Read error on program image\n");
+		exit(1);
+	}
+}
+
+void load_image64(Segment *t, const ProgTable64 *tp, FILE *inp) {
+	Elf64_Phdr *p, *q;
+	unsigned x;
+	unsigned long long off, len;
+
+	p = 0;
+	for (x = 0; x < tp->len; x++) {
+		if (tp->tab[x].p_type == PT_LOAD) {
+			if (p != 0) {
+				q = &tp->tab[x];
+				off = (q->p_offset - p->p_offset);
+				if (q->p_vaddr - p->p_vaddr == off &&
+				    q->p_paddr - p->p_paddr == off &&
+				    p->p_memsz == p->p_filesz &&
+				    p->p_memsz <= off) {
+					p->p_filesz = off + q->p_filesz;
+					p->p_memsz = off + q->p_memsz;
+				} else {
+					fprintf(stderr, "Several loadable segments\n");
+					exit(1);
+				}
+			} else
+				p = &tp->tab[x];
+		}
+	}
+	if (p == 0) {
+		fprintf(stderr, "No loadable segments\n");
+		exit(1);
+	}
+
+	/*
+	 * This trick is from ecd@skynet.be
+	 * needed for native binutils-2.6.x.
+	 */
+	off = p->p_offset;
+	len = p->p_filesz;
+	if (off == 0) {
+		/* Surely we are about to load garbage, try to skip page 0. */
+		if (p->p_vaddr != 0x0000000000400000ULL) {
+			fprintf(stderr, "Warning: Kernel workaround on non-kernel image\n");
+		}
+		off += 0x4000;
+		len -= 0x4000;
+	}
+
+	t->buf = malloc(len);
+	if (t->buf == 0) {
+		fprintf(stderr, "No core for program image\n");
+		exit(1);
+	}
+	t->len = len;
+	t->bss = p->p_memsz - p->p_filesz;
+
+	if (fseek(inp, (long)off, SEEK_SET) == -1) {
+		fprintf(stderr, "Seek error on program image\n");
+		exit(1);
+	}
+	if (fread(t->buf, 1, len, inp) != len) {
+		fprintf(stderr, "Read error on program image\n");
+		exit(1);
+	}
+}
+
+void store_image(Segment *t, FILE *out) {
+	Exec ohdb;
+
+	if (prog.swab) {
+		ohdb.a_magic = prog.csum ? swab32(CMAGIC) : swab32(AMAGIC);
+		ohdb.a_text = swab32(t->len);
+		ohdb.a_data = 0;
+		ohdb.a_bss = swab32(t->bss);
+		ohdb.a_syms = 0;
+		ohdb.a_entry = swab32(0x4000);
+		ohdb.a_trsize = 0;
+		ohdb.a_drsize = 0;
+	} else {
+		ohdb.a_magic = prog.csum ? CMAGIC : AMAGIC;
+		ohdb.a_text = t->len;
+		ohdb.a_data = 0;
+		ohdb.a_bss = t->bss;
+		ohdb.a_syms = 0;
+		ohdb.a_entry = 0x4000;
+		ohdb.a_trsize = 0;
+		ohdb.a_drsize = 0;
+	}
+	if (prog.csum)
+		ohdb.a_syms = ipchksum(t->buf, t->len);
+
+	if (!prog.sun4_mode) {
+		if (fwrite((void*)&ohdb, 1, sizeof(Exec), out) != sizeof(Exec))
+			goto ewrite;
+	}
+	if (fwrite(t->buf, 1, t->len, out) != t->len) goto ewrite;
+	return;
+
+ewrite:
+	fprintf(stderr, "Write error on program image\n");
+	exit(1);
+	return;
+}
+
+void Usage(){
+	if (prog.version) Version();
+	fprintf(stderr, "Usage: elftoaout [-o output] [-c|-b] [-V] input\n");
+	exit(1);
+}
+
+void Version(){
+	printf("elftoaout 2.3: ELF to a.out convertor for SPARC and SPARC64 bootstraps\n");
+}
+
+int
+ipchksum(unsigned char *data, int leng)
+{
+	long sum;
+
+	sum = 0;
+	while (leng >= 2) {
+		leng -= 2;
+		sum += (data[0] << 8) | data[1];
+		sum += (sum>>16) & 1;
+		sum &= 0xFFFF;
+		data += 2;
+	}
+	if (leng) {
+		sum += *data << 8;
+		sum += (sum>>16) & 1;
+		sum &= 0xFFFF;
+	}
+
+	return (~sum) & 0xFFFF;
+}
diff --git a/target/config/Config.in.kernel b/target/config/Config.in.kernel
index a7cb63f77..993fd0a77 100644
--- a/target/config/Config.in.kernel
+++ b/target/config/Config.in.kernel
@@ -19,6 +19,9 @@ config ADK_TARGET_KERNEL_UIMAGE
 config ADK_TARGET_KERNEL_BZIMAGE
 	bool
 
+config ADK_TARGET_KERNEL_VMLINUX_AOUT
+	bool
+
 config ADK_TARGET_KERNEL
 	string
 	default "uImage" if ADK_TARGET_KERNEL_UIMAGE
@@ -27,6 +30,7 @@ config ADK_TARGET_KERNEL
 	default "linux.bin" if ADK_TARGET_KERNEL_LINUXBIN
 	default "vmlinuz" if ADK_TARGET_KERNEL_VMLINUZ
 	default "bzImage" if ADK_TARGET_KERNEL_BZIMAGE
+	default "vmlinux.aout" if ADK_TARGET_KERNEL_VMLINUX_AOUT
 	default "vmlinux"
 
 config ADK_TARGET_KERNEL_MINICONFIG
@@ -70,4 +74,5 @@ config ADK_TARGET_KERNEL_MINICONFIG
 	default "pcengines-apu" if ADK_TARGET_SYSTEM_PCENGINES_APU
 	default "atmel-ngw100" if ADK_TARGET_SYSTEM_ATMEL_NGW100
 	default "apple-macmini" if ADK_TARGET_SYSTEM_APPLE_MACMINI
+	default "sun-voyager" if ADK_TARGET_SYSTEM_SUN_VOYAGER
 
diff --git a/target/config/Config.in.tools b/target/config/Config.in.tools
index 04d8ff949..f7cf5938c 100644
--- a/target/config/Config.in.tools
+++ b/target/config/Config.in.tools
@@ -7,6 +7,10 @@ config ADK_HOST_BUILD_ADK_HELPER
 	boolean
 	default y
 
+config ADK_HOST_BUILD_ELFTOAOUT
+	boolean
+	default y if ADK_TARGET_ARCH_SPARC
+
 config ADK_HOST_BUILD_AUTOCONF
 	boolean
 	default y
diff --git a/target/linux/config/Config.in.graphics b/target/linux/config/Config.in.graphics
index 68d3039e6..dbd6185d0 100644
--- a/target/linux/config/Config.in.graphics
+++ b/target/linux/config/Config.in.graphics
@@ -31,6 +31,9 @@ config ADK_KERNEL_FB
 	select ADK_KERNEL_VT_CONSOLE
  	boolean
 
+config ADK_KERNEL_FB_SBUS
+	bool
+
 config ADK_KERNEL_DUMMY_CONSOLE
 	boolean
  
@@ -325,5 +328,15 @@ config ADK_KERNEL_DRM_CIRRUS_QEMU
 	depends on ADK_TARGET_SYSTEM_QEMU_X86 || ADK_TARGET_SYSTEM_QEMU_X86_64
 	help
 	  DRM/KMS support for Qemu cirrus VGA emulation.
+
+config ADK_KERNEL_FB_CGSIX
+	bool "Support for CGSIX framebuffer"
+	select ADK_KERNEL_FB
+	select ADK_KERNEL_FB_SBUS
+	default y if ADK_TARGET_SYSTEM_SUN_VOYAGER
+	default n
+	depends on ADK_TARGET_SYSTEM_SUN_VOYAGER
+	help
+	  Framebuffer support for Sun Voyager.
 	
 endmenu
diff --git a/target/linux/patches/3.19/sparc-aout.patch b/target/linux/patches/3.19/sparc-aout.patch
new file mode 100644
index 000000000..3360d6a6e
--- /dev/null
+++ b/target/linux/patches/3.19/sparc-aout.patch
@@ -0,0 +1,24 @@
+diff -Nur linux-3.19.orig/arch/sparc/boot/Makefile linux-3.19/arch/sparc/boot/Makefile
+--- linux-3.19.orig/arch/sparc/boot/Makefile	2015-02-08 20:54:22.000000000 -0600
++++ linux-3.19/arch/sparc/boot/Makefile	2015-02-15 22:58:57.918666227 -0600
+@@ -25,9 +25,6 @@
+ 	$(call if_changed,gzip)
+ 	@echo '  kernel: $@ is ready'
+ 
+-$(obj)/vmlinux.aout: vmlinux FORCE
+-	$(call if_changed,elftoaout)
+-	@echo '  kernel: $@ is ready'
+ else
+ 
+ $(obj)/zImage: $(obj)/image
+@@ -62,6 +59,10 @@
+ 
+ endif
+ 
++$(obj)/vmlinux.aout: $(obj)/image FORCE
++	$(call if_changed,elftoaout)
++	@echo '  kernel: $@ is ready'
++
+ $(obj)/image: vmlinux FORCE
+ 	$(call if_changed,strip)
+ 	@echo '  kernel: $@ is ready'
diff --git a/target/linux/patches/3.4.103/sparc-aout.patch b/target/linux/patches/3.4.103/sparc-aout.patch
new file mode 100644
index 000000000..5cd74c2e7
--- /dev/null
+++ b/target/linux/patches/3.4.103/sparc-aout.patch
@@ -0,0 +1,24 @@
+diff -Nur linux-3.4.103.orig/arch/sparc/boot/Makefile linux-3.4.103/arch/sparc/boot/Makefile
+--- linux-3.4.103.orig/arch/sparc/boot/Makefile	2014-08-13 20:07:43.000000000 -0500
++++ linux-3.4.103/arch/sparc/boot/Makefile	2015-02-16 00:26:16.934618259 -0600
+@@ -74,9 +74,6 @@
+ 	$(call if_changed,gzip)
+ 	@echo '  kernel: $@ is ready'
+ 
+-$(obj)/vmlinux.aout: vmlinux FORCE
+-	$(call if_changed,elftoaout)
+-	@echo '  kernel: $@ is ready'
+ else
+ 
+ # The following lines make a readable image for U-Boot.
+@@ -107,6 +104,10 @@
+ 
+ endif
+ 
++$(obj)/vmlinux.aout: $(obj)/image FORCE
++	$(call if_changed,elftoaout)
++	@echo '  kernel: $@ is ready'
++
+ $(obj)/tftpboot.img: $(obj)/image $(obj)/piggyback System.map $(ROOT_IMG) FORCE
+ 	$(call if_changed,elftoaout)
+ 	$(call if_changed,piggy)
diff --git a/target/sparc/Makefile b/target/sparc/Makefile
index ac94569db..f203596cf 100644
--- a/target/sparc/Makefile
+++ b/target/sparc/Makefile
@@ -7,7 +7,12 @@ include $(ADK_TOPDIR)/mk/modules.mk
 include $(ADK_TOPDIR)/mk/kernel-build.mk
 include $(ADK_TOPDIR)/mk/image.mk
 
+ifeq ($(ADK_TARGET_KERNEL_ZIMAGE),y)
 KERNEL:=$(LINUX_DIR)/arch/sparc/boot/zImage
+endif
+ifeq ($(ADK_TARGET_KERNEL_VMLINUX_AOUT),y)
+KERNEL:=$(LINUX_DIR)/arch/sparc/boot/vmlinux.aout
+endif
 
 QEMU_ARGS:=-M SS-10
 QEMU_ARGS+=${ADK_QEMU_ARGS}
@@ -49,6 +54,11 @@ ifeq ($(ADK_TARGET_QEMU),y)
 	@echo 'qemu-system-${ADK_TARGET_CPU_ARCH} ${QEMU_ARGS} -kernel $(FW_DIR)/$(TARGET_KERNEL)'
 endif
 endif
+ifeq ($(ADK_TARGET_FS),nfsroot)
+targethelp:
+	@echo 'The kernel file is: $(FW_DIR)/${TARGET_KERNEL}'
+	@echo 'The nfs root tarball is: ${FW_DIR}/${ROOTFSUSERTARBALL}'
+endif
 
 # image creation and kernel install
 kernel-strip:
@@ -70,3 +80,6 @@ endif
 ifeq ($(ADK_TARGET_FS),initramfspiggyback)
 imageinstall: createinitramfs targethelp
 endif
+ifeq ($(ADK_TARGET_FS),nfsroot)
+imageinstall: kernel-install $(FW_DIR)/$(ROOTFSUSERTARBALL) targethelp
+endif
diff --git a/target/sparc/kernel/sun-voyager b/target/sparc/kernel/sun-voyager
new file mode 100644
index 000000000..ffa9bb9f8
--- /dev/null
+++ b/target/sparc/kernel/sun-voyager
@@ -0,0 +1,9 @@
+CONFIG_SPARC=y
+CONFIG_SPARC32=y
+CONFIG_SBUS=y
+CONFIG_SBUSCHAR=y
+CONFIG_PCIC_PCI=y
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_SERIAL_SUNCORE=y
+CONFIG_SERIAL_SUNZILOG=y
+CONFIG_SERIAL_SUNZILOG_CONSOLE=y
diff --git a/target/sparc/systems/sun-voyager b/target/sparc/systems/sun-voyager
new file mode 100644
index 000000000..931a46354
--- /dev/null
+++ b/target/sparc/systems/sun-voyager
@@ -0,0 +1,11 @@
+config ADK_TARGET_SYSTEM_SUN_VOYAGER
+	bool "Sun Voyager"
+	select ADK_sparc
+	select ADK_sun_voyager
+	select ADK_CPU_SPARC_V8
+	select ADK_TARGET_WITH_VGA
+	select ADK_TARGET_WITH_SERIAL
+	select ADK_TARGET_KERNEL_VMLINUX_AOUT
+	help
+	 Support for Sun Voyager.
+
diff --git a/toolchain/gcc/Makefile b/toolchain/gcc/Makefile
index f1b8c4455..2297b7ba7 100644
--- a/toolchain/gcc/Makefile
+++ b/toolchain/gcc/Makefile
@@ -149,6 +149,10 @@ ifeq ($(ADK_CPU_CORTEX_A9),y)
 GCC_CONFOPTS+=		--with-cpu=cortex-a9
 endif
 
+ifeq ($(ADK_CPU_SPARC_V8),y)
+GCC_CONFOPTS+=		--with-cpu=v8
+endif
+
 ifeq ($(ADK_CPU_SPARC_V9),y)
 GCC_CONFOPTS+=		--with-cpu=ultrasparc
 endif
-- 
cgit v1.2.3