summaryrefslogtreecommitdiffstats
path: root/arch/ppc/treeboot
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ppc/treeboot')
-rw-r--r--arch/ppc/treeboot/Makefile62
-rw-r--r--arch/ppc/treeboot/crt0.S70
-rw-r--r--arch/ppc/treeboot/elf.pl33
-rw-r--r--arch/ppc/treeboot/irSect.c36
-rw-r--r--arch/ppc/treeboot/irSect.h32
-rw-r--r--arch/ppc/treeboot/ld.script68
-rw-r--r--arch/ppc/treeboot/main.c209
-rw-r--r--arch/ppc/treeboot/misc.S28
-rw-r--r--arch/ppc/treeboot/mkevimg437
-rw-r--r--arch/ppc/treeboot/mkirimg367
10 files changed, 1342 insertions, 0 deletions
diff --git a/arch/ppc/treeboot/Makefile b/arch/ppc/treeboot/Makefile
new file mode 100644
index 000000000..405634214
--- /dev/null
+++ b/arch/ppc/treeboot/Makefile
@@ -0,0 +1,62 @@
+#
+# Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+#
+# Module name: Makefile
+#
+# Description:
+# Makefile for the IBM "tree" evaluation board Linux kernel
+# boot loaders.
+#
+
+HOSTCFLAGS = -O -I$(TOPDIR)/include
+
+CC = $(CROSS_COMPILE)gcc
+LD = $(CROSS_COMPILE)ld
+OBJCOPY = $(CROSS_COMPILE)objcopy
+OBJDUMP = $(CROSS_COMPILE)objdump
+
+GZIP = gzip -vf9
+RM = rm -f
+MKEVIMG = mkevimg -l
+MKIRIMG = mkirimg
+
+CFLAGS = -O -fno-builtin -I$(TOPDIR)/include
+LD_ARGS = -e _start -T ld.script -Ttext 80200000 -Bstatic
+
+OBJS = crt0.o main.o misc.o string.o zlib.o irSect.o
+LIBS =
+
+treeboot: $(OBJS) ld.script
+ $(LD) -o $@ $(LD_ARGS) $(OBJS) $(LIBS)
+
+zImage: vmlinux.img
+
+zImage.initrd: vmlinux.initrd.img
+
+treeboot.image: treeboot vmlinux.gz
+ $(OBJCOPY) --add-section=image=vmlinux.gz treeboot $@
+
+treeboot.initrd: treeboot.image ramdisk.image.gz
+ $(OBJCOPY) --add-section=initrd=ramdisk.image.gz treeboot.image $@
+
+vmlinux.img: treeboot.image
+ $(OBJDUMP) --syms treeboot.image | grep irSectStart > irSectStart.txt
+ $(MKIRIMG) treeboot.image treeboot.image.out irSectStart.txt
+ $(MKEVIMG) treeboot.image.out $@
+ $(RM) treeboot.image treeboot.image.out irSectStart.txt
+
+vmlinux.initrd.img: treeboot.initrd
+ $(OBJDUMP) --all-headers treeboot.initrd | grep irSectStart > irSectStart.txt
+ $(MKIRIMG) treeboot.initrd treeboot.initrd.out irSectStart.txt
+ $(MKEVIMG) treeboot.initrd.out $@
+ $(RM) treeboot.initrd treeboot.initrd.out irSectStart.txt
+
+vmlinux.gz: $(TOPDIR)/vmlinux
+ $(OBJCOPY) -S -O binary $(TOPDIR)/vmlinux vmlinux
+ $(GZIP) vmlinux
+
+clean:
+ rm -f treeboot treeboot.image treeboot.initrd irSectStart.txt vmlinux.* *.o
+
+fastdep:
+
diff --git a/arch/ppc/treeboot/crt0.S b/arch/ppc/treeboot/crt0.S
new file mode 100644
index 000000000..1f2c1c094
--- /dev/null
+++ b/arch/ppc/treeboot/crt0.S
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 1997 Paul Mackerras <paulus@cs.anu.edu.au>
+ * Initial Power Macintosh COFF version.
+ * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ * Modifications for IBM PowerPC 400-class processor evaluation
+ * boards.
+ *
+ * Module name: crt0.S
+ *
+ * Description:
+ * Boot loader execution entry point. Clears out .bss section as per
+ * ANSI C requirements. Invalidates and flushes the caches over the
+ * range covered by the boot loader's .text section. Sets up a stack
+ * below the .text section entry point.
+ *
+ * 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.
+ *
+ */
+
+#include "../kernel/ppc_asm.h"
+
+ .text
+
+ .globl _start
+_start:
+ ## Clear out the BSS as per ANSI C requirements
+
+ lis r7,_end@ha #
+ addi r7,r7,_end@l # r7 = &_end
+ lis r8,__bss_start@ha #
+ addi r8,r8,__bss_start@l # r8 = &_bss_start
+
+ ## Determine how large an area, in number of words, to clear
+
+ subf r7,r8,r7 # r7 = &_end - &_bss_start + 1
+ addi r7,r7,3 # r7 += 3
+ srwi. r7,r7,2 # r7 = size in words.
+ beq 2f # If the size is zero, do not bother
+ addi r8,r8,-4 # r8 -= 4
+ mtctr r7 # SPRN_CTR = number of words to clear
+ li r0,0 # r0 = 0
+1: stwu r0,4(r8) # Clear out a word
+ bdnz 1b # If we are not done yet, keep clearing
+
+ ## Flush and invalidate the caches for the range in memory covering
+ ## the .text section of the boot loader
+
+2: lis r9,_start@h # r9 = &_start
+ lis r8,_etext@ha #
+ addi r8,r8,_etext@l # r8 = &_etext
+3: dcbf r0,r9 # Flush the data cache
+ icbi r0,r9 # Invalidate the instruction cache
+ addi r9,r9,0x10 # Increment by one cache line
+ cmplwi cr0,r9,r8 # Are we at the end yet?
+ blt 3b # No, keep flushing and invalidating
+
+ ## Set up the stack
+
+ lis r9,_start@h # r9 = &_start (text section entry)
+ addi r9,r9,_start@l
+ subi r1,r9,64 # Start the stack 64 bytes below _start
+ clrrwi r1,r1,4 # Make sure it is aligned on 16 bytes.
+ li r0,0
+ stwu r0,-16(r1)
+ mtlr r9
+
+ b start # All done, start the real work.
diff --git a/arch/ppc/treeboot/elf.pl b/arch/ppc/treeboot/elf.pl
new file mode 100644
index 000000000..d3e9d9d5b
--- /dev/null
+++ b/arch/ppc/treeboot/elf.pl
@@ -0,0 +1,33 @@
+#
+# ELF header field numbers
+#
+
+$e_ident = 0; # Identification bytes / magic number
+$e_type = 1; # ELF file type
+$e_machine = 2; # Target machine type
+$e_version = 3; # File version
+$e_entry = 4; # Start address
+$e_phoff = 5; # Program header file offset
+$e_shoff = 6; # Section header file offset
+$e_flags = 7; # File flags
+$e_ehsize = 8; # Size of ELF header
+$e_phentsize = 9; # Size of program header
+$e_phnum = 10; # Number of program header entries
+$e_shentsize = 11; # Size of section header
+$e_shnum = 12; # Number of section header entries
+$e_shstrndx = 13; # Section header table string index
+
+#
+# Section header field numbers
+#
+
+$sh_name = 0; # Section name
+$sh_type = 1; # Section header type
+$sh_flags = 2; # Section header flags
+$sh_addr = 3; # Virtual address
+$sh_offset = 4; # File offset
+$sh_size = 5; # Section size
+$sh_link = 6; # Miscellaneous info
+$sh_info = 7; # More miscellaneous info
+$sh_addralign = 8; # Memory alignment
+$sh_entsize = 9; # Entry size if this is a table
diff --git a/arch/ppc/treeboot/irSect.c b/arch/ppc/treeboot/irSect.c
new file mode 100644
index 000000000..7f4c7f6ab
--- /dev/null
+++ b/arch/ppc/treeboot/irSect.c
@@ -0,0 +1,36 @@
+/*
+ *
+ * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ *
+ * Module name: irSect.c
+ *
+ * Description:
+ * Defines variables to hold the absolute starting address and size
+ * of the Linux kernel "image" and the initial RAM disk "initrd"
+ * sections within the boot loader.
+ *
+ */
+
+#include "irSect.h"
+
+
+/*
+ * The order of globals below must not change. If more globals are added,
+ * you must change the script 'mkirimg' accordingly.
+ *
+ */
+
+/*
+ * irSectStart must be at beginning of file
+ */
+unsigned int irSectStart = 0xdeadbeaf;
+
+unsigned int imageSect_start = 0;
+unsigned int imageSect_size = 0;
+unsigned int initrdSect_start = 0;
+unsigned int initrdSect_size = 0;
+
+/*
+ * irSectEnd must be at end of file
+ */
+unsigned int irSectEnd = 0xdeadbeaf;
diff --git a/arch/ppc/treeboot/irSect.h b/arch/ppc/treeboot/irSect.h
new file mode 100644
index 000000000..801c3b42e
--- /dev/null
+++ b/arch/ppc/treeboot/irSect.h
@@ -0,0 +1,32 @@
+/*
+ *
+ * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ *
+ * Module name: irSect.h
+ *
+ * Description:
+ * Defines variables to hold the absolute starting address and size
+ * of the Linux kernel "image" and the initial RAM disk "initrd"
+ * sections within the boot loader.
+ *
+ */
+
+#ifndef __IRSECT_H__
+#define __IRSECT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern unsigned int imageSect_start;
+extern unsigned int imageSect_size;
+
+extern unsigned int initrdSect_start;
+extern unsigned int initrdSect_size;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __IRSECT_H__ */
diff --git a/arch/ppc/treeboot/ld.script b/arch/ppc/treeboot/ld.script
new file mode 100644
index 000000000..2469ed65d
--- /dev/null
+++ b/arch/ppc/treeboot/ld.script
@@ -0,0 +1,68 @@
+OUTPUT_ARCH(powerpc)
+SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib);
+/* Do we need any of these for elf?
+ __DYNAMIC = 0; */
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = + SIZEOF_HEADERS;
+ .interp : { *(.interp) }
+ .hash : { *(.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .rel.text : { *(.rel.text) }
+ .rela.text : { *(.rela.text) }
+ .rel.data : { *(.rel.data) }
+ .rela.data : { *(.rela.data) }
+ .rel.rodata : { *(.rel.rodata) }
+ .rela.rodata : { *(.rela.rodata) }
+ .rel.got : { *(.rel.got) }
+ .rela.got : { *(.rela.got) }
+ .rel.ctors : { *(.rel.ctors) }
+ .rela.ctors : { *(.rela.ctors) }
+ .rel.dtors : { *(.rel.dtors) }
+ .rela.dtors : { *(.rela.dtors) }
+ .rel.bss : { *(.rel.bss) }
+ .rela.bss : { *(.rela.bss) }
+ .rel.plt : { *(.rel.plt) }
+ .rela.plt : { *(.rela.plt) }
+ .init : { *(.init) } =0
+ .plt : { *(.plt) }
+ .text :
+ {
+ *(.text)
+ *(.rodata)
+ *(.rodata1)
+ *(.got1)
+ }
+ .fini : { *(.fini) } =0
+ .ctors : { *(.ctors) }
+ .dtors : { *(.dtors) }
+ _etext = .;
+ PROVIDE (etext = .);
+ /* Read-write section, merged into data segment: */
+ . = (. + 0x0FFF) & 0xFFFFF000;
+ .data :
+ {
+ *(.data)
+ *(.data1)
+ *(.sdata)
+ *(.sdata2)
+ *(.got.plt) *(.got)
+ *(.dynamic)
+ CONSTRUCTORS
+ }
+ _edata = .;
+ PROVIDE (edata = .);
+ __bss_start = .;
+ .bss :
+ {
+ *(.sbss) *(.scommon)
+ *(.dynbss)
+ *(.bss)
+ *(COMMON)
+ }
+ _end = . ;
+ PROVIDE (end = .);
+}
+
diff --git a/arch/ppc/treeboot/main.c b/arch/ppc/treeboot/main.c
new file mode 100644
index 000000000..1b5ef3805
--- /dev/null
+++ b/arch/ppc/treeboot/main.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 1997 Paul Mackerras <paulus@cs.anu.edu.au>
+ * Initial Power Macintosh COFF version.
+ * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ * Modifications for an ELF-based IBM evaluation board version.
+ *
+ * Module name: main.c
+ *
+ * Description:
+ * This module does most of the real work for the boot loader. It
+ * checks the variables holding the absolute start address and size
+ * of the Linux kernel "image" and initial RAM disk "initrd" sections
+ * and if they are present, moves them to their "proper" locations.
+ *
+ * For the Linux kernel, "proper" is physical address 0x00000000.
+ * For the RAM disk, "proper" is the image's size below the top
+ * of physical memory. The Linux kernel may be in either raw
+ * binary form or compressed with GNU zip (aka gzip).
+ *
+ * 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.
+ *
+ */
+
+#include "nonstdio.h"
+#include "zlib.h"
+#include "irSect.h"
+
+
+/* Preprocessor Defines */
+
+#define RAM_SIZE (4 * 1024 * 1024)
+
+#define RAM_PBASE 0x00000000
+#define RAM_PEND (RAM_PBASE + RAM_SIZE)
+
+#define RAM_VBASE 0xC0000000
+#define RAM_VEND (RAM_VBASE + RAM_SIZE)
+
+#define RAM_START RAM_PBASE
+#define RAM_END RAM_PEND
+#define RAM_FREE (imageSect_start + imageSect_size + initrdSect_size)
+
+#define PROG_START RAM_START
+
+
+/* Function Macros */
+
+#define ALIGN_UP(x, align) (((x) + ((align) - 1)) & ~((align) - 1))
+
+
+/* Global Variables */
+
+/* Needed by zalloc and zfree for allocating memory */
+
+char *avail_ram; /* Indicates start of RAM available for heap */
+char *end_avail; /* Indicates end of RAM available for heap */
+
+
+/* Function Prototypes */
+
+void *zalloc(void *x, unsigned items, unsigned size);
+void zfree(void *x, void *addr, unsigned nb);
+
+void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp);
+
+void printf () {}
+void pause () {}
+void exit () {}
+
+
+void start(void)
+{
+ void *options;
+ int ns, oh, i;
+ unsigned sa, len;
+ void *dst;
+ unsigned char *im;
+ unsigned initrd_start, initrd_size;
+
+ /* setup_bats(RAM_START); */
+
+ /* Init RAM disk (initrd) section */
+
+ if (initrdSect_start != 0 && (initrd_size = initrdSect_size) != 0) {
+ initrd_start = (RAM_END - initrd_size) & ~0xFFF;
+
+ printf("Initial RAM disk at 0x%08x (%u bytes)\n",
+ initrd_start, initrd_size);
+
+ memcpy((char *)initrd_start,
+ (char *)(initrdSect_start),
+ initrdSect_size);
+
+ end_avail = (char *)initrd_start;
+ } else {
+ end_avail = (char *)RAM_END;
+ }
+
+ /* Linux kernel image section */
+
+ im = (unsigned char *)(imageSect_start);
+ len = imageSect_size;
+ dst = (void *)PROG_START;
+
+ /* Check for the gzip archive magic numbers */
+
+ if (im[0] == 0x1f && im[1] == 0x8b) {
+
+ /* The gunzip routine needs everything nice and aligned */
+
+ void *cp = (void *)ALIGN_UP(RAM_FREE, 8);
+ avail_ram = (void *)(cp + ALIGN_UP(len, 8));
+ memcpy(cp, im, len);
+
+ /* I'm not sure what the 0x200000 parameter is for, but it works. */
+
+ gunzip(dst, 0x200000, cp, &len);
+ } else {
+ memmove(dst, im, len);
+ }
+
+ /* flush_cache(dst, len); */
+
+ sa = (unsigned long)dst;
+
+ (*(void (*)())sa)();
+
+ pause();
+}
+
+void *zalloc(void *x, unsigned items, unsigned size)
+{
+ void *p = avail_ram;
+
+ size *= items;
+ size = ALIGN_UP(size, 8);
+ avail_ram += size;
+ if (avail_ram > end_avail) {
+ printf("oops... out of memory\n");
+ pause();
+ }
+ return p;
+}
+
+void zfree(void *x, void *addr, unsigned nb)
+{
+
+}
+
+#define HEAD_CRC 2
+#define EXTRA_FIELD 4
+#define ORIG_NAME 8
+#define COMMENT 0x10
+#define RESERVED 0xe0
+
+#define DEFLATED 8
+
+void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
+{
+ z_stream s;
+ int r, i, flags;
+
+ /* skip header */
+ i = 10;
+ flags = src[3];
+ if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
+ printf("bad gzipped data\n");
+ exit();
+ }
+ if ((flags & EXTRA_FIELD) != 0)
+ i = 12 + src[10] + (src[11] << 8);
+ if ((flags & ORIG_NAME) != 0)
+ while (src[i++] != 0)
+ ;
+ if ((flags & COMMENT) != 0)
+ while (src[i++] != 0)
+ ;
+ if ((flags & HEAD_CRC) != 0)
+ i += 2;
+ if (i >= *lenp) {
+ printf("gunzip: ran out of data in header\n");
+ exit();
+ }
+ printf("done 1\n");
+ s.zalloc = zalloc;
+ s.zfree = zfree;
+ r = inflateInit2(&s, -MAX_WBITS);
+ if (r != Z_OK) {
+ printf("inflateInit2 returned %d\n", r);
+ exit();
+ }
+ s.next_in = src + i;
+ s.avail_in = *lenp - i;
+ s.next_out = dst;
+ s.avail_out = dstlen;
+ printf("doing inflate\n");
+ r = inflate(&s, Z_FINISH);
+ printf("done inflate\n");
+ if (r != Z_OK && r != Z_STREAM_END) {
+ printf("inflate returned %d\n", r);
+ exit();
+ }
+ *lenp = s.next_out - (unsigned char *) dst;
+ printf("doing end\n");
+ inflateEnd(&s);
+}
diff --git a/arch/ppc/treeboot/misc.S b/arch/ppc/treeboot/misc.S
new file mode 100644
index 000000000..27417563f
--- /dev/null
+++ b/arch/ppc/treeboot/misc.S
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * 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.
+ */
+ .text
+
+/*
+ * Flush the dcache and invalidate the icache for a range of addresses.
+ *
+ * flush_cache(addr, len)
+ */
+ .global flush_cache
+flush_cache:
+ addi 4,4,0x1f /* len = (len + 0x1f) / 0x20 */
+ rlwinm. 4,4,27,5,31
+ mtctr 4
+ beqlr
+1: dcbf 0,3
+ icbi 0,3
+ addi 3,3,0x20
+ bdnz 1b
+ sync
+ isync
+ blr
diff --git a/arch/ppc/treeboot/mkevimg b/arch/ppc/treeboot/mkevimg
new file mode 100644
index 000000000..76f849bb7
--- /dev/null
+++ b/arch/ppc/treeboot/mkevimg
@@ -0,0 +1,437 @@
+#!/usr/local/bin/perl
+
+#
+# Copyright (c) 1998-1999 TiVo, Inc.
+# All rights reserved.
+#
+# Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+# Major syntactic and usability rework.
+#
+# Module name: mkevimg
+#
+# Description:
+# Converts an ELF output file from the linker into the format used by
+# the IBM evaluation board ROM Monitor to load programs from a host
+# onto the evaluation board. The ELF file must be an otherwise execut-
+# able file (with the text and data addresses bound at link time) and
+# have space reserved after the entry point for the load information
+# block:
+#
+# typedef struct boot_block {
+# unsigned long magic; 0x0052504F
+# unsigned long dest; Target address of the image
+# unsigned long num_512blocks; Size, rounded-up, in 512 byte blocks
+# unsigned long debug_flag; Run the debugger or image after load
+# unsigned long entry_point; The image address to jump to after load
+# unsigned long reserved[3];
+# } boot_block_t;
+#
+#
+
+use File::Basename;
+use Getopt::Std;
+
+#
+# usage()
+#
+# Description:
+# This routine prints out the proper command line usage for this program
+#
+# Input(s):
+# status - Flag determining what usage information will be printed and what
+# the exit status of the program will be after the information is
+# printed.
+#
+# Output(s):
+# N/A
+#
+# Returns:
+# This subroutine does not return.
+#
+
+sub usage {
+ my($status);
+ $status = $_[0];
+
+ printf("Usage: %s [-hlvV] <ELF input file> <Evaluation board output file>\n",
+ $program);
+
+ if ($status != 0) {
+ printf("Try `%s -h' for more information.\n", $program);
+ }
+
+ if ($status != 1) {
+ print(" -h Print out this message and exit.\n");
+ print(" -l Linux mode; if present, copy 'image' and 'initrd' sections.\n");
+ print(" -v Verbose. Print out lots of ELF information.\n");
+ print(" -V Print out version information and exit.\n");
+ }
+
+ exit($status);
+}
+
+#
+# version()
+#
+# Description:
+# This routine prints out program version information
+#
+# Input(s):
+# N/A
+#
+# Output(s):
+# N/A
+#
+# Returns:
+# This subroutine does not return.
+#
+
+sub version {
+ print("mkevimg Version 1.1.0\n");
+ print("Copyright (c) 1998-1999 TiVo, Inc.\n");
+ print("Copyright (c) 1999 Grant Erickson <grant\@lcse.umn.edu>\n");
+
+ exit (0);
+}
+
+#
+# file_check()
+#
+# Description:
+# This routine checks an input file to ensure that it exists, is a
+# regular file, and is readable.
+#
+# Input(s):
+# file - Input file to be checked.
+#
+# Output(s):
+# N/A
+#
+# Returns:
+# 0 if the file exists, is a regular file, and is readable, otherwise -1.
+#
+
+sub file_check {
+ my($file);
+ $file = $_[0];
+
+ if (!(-e $file)) {
+ printf("The file \"%s\" does not exist.\n", $file);
+ return (-1);
+ } elsif (!(-f $file)) {
+ printf("The file \"%s\" is not a regular file.\n", $file);
+ return (-1);
+ } elsif (!(-r $file)) {
+ printf("The file \"%s\" is not readable.\n", $file);
+ return (-1);
+ }
+
+ return (0);
+}
+
+#
+# decode_options()
+#
+# Description:
+# This routine steps through the command-line arguments, parsing out
+# recognzied options.
+#
+# Input(s):
+# N/A
+#
+# Output(s):
+# N/A
+#
+# Returns:
+# N/A
+#
+
+sub decode_options {
+
+ if (!getopts("hlvV")) {
+ usage(1);
+ }
+
+ if ($opt_h) {
+ usage(0);
+ }
+
+ if ($opt_l) {
+ $linux = 1;
+ }
+
+ if ($opt_V) {
+ version();
+ exit (0);
+ }
+
+ if ($opt_v) {
+ $verbose = 1;
+ }
+
+ if (!($ifile = shift(@ARGV))) {
+ usage(1);
+ }
+
+ if (!($ofile = shift(@ARGV))) {
+ usage (1);
+ }
+
+ if (file_check($ifile)) {
+ exit(1);
+ }
+
+}
+
+#
+# ELF file and section header field numbers
+#
+
+require 'elf.pl';
+
+#
+# Main program body
+#
+
+{
+ $program = basename($0);
+
+ decode_options();
+
+ open(ELF, "<$ifile") || die "Cannot open input file";
+
+ $ifilesize = (-s $ifile);
+
+ if ($verbose) {
+ print("Output file: $ofile\n");
+ print("Input file: $ifile, $ifilesize bytes.\n");
+ }
+
+ if (read(ELF, $ibuf, $ifilesize) != $ifilesize) {
+ print("Failed to read input file!\n");
+ exit(1);
+ }
+
+ #
+ # Parse ELF header
+ #
+
+ @eh = unpack("a16n2N5n6", $ibuf);
+
+ #
+ # Make sure this is actually a PowerPC ELF file.
+ #
+
+ if (substr($eh[$e_ident], 0, 4) ne "\177ELF") {
+ printf("The file \"%s\" is not an ELF file.\n", $ifile);
+ exit (1);
+ } elsif ($eh[$e_machine] != 20) {
+ printf("The file \"%s\" is not a PowerPC ELF file.\n", $ifile);
+ exit (1);
+ }
+
+ if ($verbose) {
+ print("File header:\n");
+ printf(" Identifier: %s\n", $eh[$e_ident]);
+ printf(" Type: %d\n", $eh[$e_type]);
+ printf(" Machine: %d\n", $eh[$e_machine]);
+ printf(" Version: %d\n", $eh[$e_version]);
+ printf(" Entry point: 0x%08x\n", $eh[$e_entry]);
+ printf(" Program header offset: 0x%x\n", $eh[$e_phoff]);
+ printf(" Section header offset: 0x%x\n", $eh[$e_shoff]);
+ printf(" Flags: 0x%08x\n", $eh[$e_flags]);
+ printf(" Header size: %d\n", $eh[$e_ehsize]);
+ printf(" Program entry size: %d\n", $eh[$e_phentsize]);
+ printf(" Program table entries: %d\n", $eh[$e_phnum]);
+ printf(" Section header size: %d\n", $eh[$e_shentsize]);
+ printf(" Section table entries: %d\n", $eh[$e_shnum]);
+ printf(" String table section: %d\n", $eh[$e_shstrndx]);
+ }
+
+ #
+ # Find the section header for the string table.
+ #
+
+ $strtable_section_offset = $eh[$e_shoff] +
+ $eh[$e_shstrndx] * $eh[$e_shentsize];
+
+ if ($verbose) {
+ printf("String table section header offset: 0x%x\n",
+ $strtable_section_offset);
+ }
+
+ #
+ # Find the start of the string table.
+ #
+
+ @strh = unpack("N10", substr($ibuf, $strtable_section_offset,
+ $eh[$e_shentsize]));
+
+ if ($verbose) {
+ printf("Section name strings start at: 0x%x, %d bytes.\n",
+ $strh[$sh_offset], $strh[$sh_size]);
+ }
+
+ $names = substr($ibuf, $strh[$sh_offset], $strh[$sh_size]);
+
+ # Grab each section header and find '.text' and '.bss' sections in
+ # particular.
+
+ if ($verbose) {
+ print("Section headers:\n");
+ print("Idx Name Size Address File off Algn\n");
+ print("--- ------------------------ -------- -------- -------- ----\n");
+ }
+
+ $off = $eh[$e_shoff];
+
+ for($i = 0; $i < $eh[$e_shnum]; $i++, $off += $eh[$e_shentsize]) {
+ @sh = unpack("N10", substr($ibuf, $off, $eh[$e_shentsize]));
+
+ # Take the first section name from the array returned by split.
+
+ ($name) = split(/\000/, substr($names, $sh[$sh_name]));
+
+ if ($verbose) {
+ printf("%3d %-24s %8x %08x %08x %4d\n",
+ $i, $name, $sh[$sh_size], $sh[$sh_addr],
+ $sh[$sh_offset], $sh[$sh_addralign]);
+ }
+
+ # Attempt to find the .text and .bss sections
+
+ if ($name =~ /^\.bss$/) {
+ ($bss_addr, $bss_offset, $bss_size) =
+ ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]);
+
+ } elsif ($name =~ /^\.text$/) {
+ ($text_addr, $text_offset, $text_size) =
+ ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]);
+
+ } elsif ($linux && ($name =~ /^\image$/)) {
+ $image_found = 1;
+
+ ($image_addr, $image_offset, $image_size) =
+ ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]);
+
+ } elsif ($linux && ($name =~ /^\initrd$/)) {
+ $initrd_found = 1;
+
+ ($initrd_addr, $initrd_offset, $initrd_size) =
+ ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]);
+
+ }
+ }
+
+ printf("Text section - Address: 0x%08x, Size: 0x%08x\n",
+ $text_addr, $text_size);
+ printf("Bss section - Address: 0x%08x, Size: 0x%08x\n",
+ $bss_addr, $bss_size);
+
+ if ($linux) {
+ if ($image_found) {
+ printf("Image section - Address: 0x%08x, Size: 0x%08x\n",
+ $image_addr, $image_size);
+ }
+
+ if ($initrd_found) {
+ printf("Initrd section - Address: 0x%08x, Size: 0x%08x\n",
+ $initrd_addr, $initrd_size);
+ }
+ }
+
+ #
+ # Open output file
+ #
+
+ open(BOOT, ">$ofile") || die "Cannot open output file";
+
+ #
+ # Compute image size
+ #
+
+ $output_size = $bss_offset - $text_offset + $bss_size;
+
+ if ($linux && $image_found) {
+ $output_size += $image_size;
+ }
+
+ if ($linux && $initrd_found) {
+ $output_size += $initrd_size;
+ }
+
+ $num_blocks = $output_size / 512 + 1;
+
+ #
+ # Write IBM PowerPC evaluation board boot_block_t header
+ #
+
+ $header = pack("H8N7", "0052504f", $text_addr, $num_blocks, 0,
+ $text_addr, 0, 0, 0);
+
+ $bytes = length($header);
+
+ if (($resid = syswrite(BOOT, $header, $bytes)) != $bytes) {
+ die("Could not write boot image header to output file.");
+ }
+
+ printf("Entry point = 0x%08x\n", $text_addr);
+ printf("Image size = 0x%08x (%d bytes) (%d blocks).\n",
+ $output_size, $output_size, $num_blocks);
+
+ #
+ # Write image starting after ELF and program headers and
+ # continuing to beginning of bss
+ #
+
+ $bytes = $bss_offset - $text_offset + $bss_size;
+
+ if (($resid = syswrite(BOOT, $ibuf, $bytes, $text_offset)) != $bytes) {
+ die("Could not write boot image to output file.\n");
+ }
+
+ #
+ # If configured, write out the image and initrd sections as well
+ #
+
+ if ($linux) {
+ if ($image_found) {
+ $bytes = $image_size;
+ if (($resid = syswrite(BOOT, $ibuf, $bytes, $image_offset)) != $bytes) {
+ die("Could not write boot image to output file.\n");
+ }
+ }
+
+ if ($initrd_found) {
+ $bytes = $initrd_size;
+ if (($resid = syswrite(BOOT, $ibuf, $bytes, $initrd_offset)) != $bytes) {
+ die("Could not write boot image to output file.\n");
+ }
+ }
+ }
+
+ #
+ # Pad to a multiple of 512 bytes
+ #
+
+ $pad_size = 512 - (length($header) + $output_size) % 512;
+
+ if ($verbose) {
+ print("Padding boot image by an additional $pad_size bytes.\n");
+ }
+
+ $pad_string = pack(("H8","deadbeef") x 128);
+
+ syswrite(BOOT, $pad_string, $pad_size) or
+ die "Could not pad boot image in output file.\n";
+
+ #
+ # Clean-up and leave
+ #
+
+ close(BOOT);
+
+ print("\nBoot image file \"$ofile\" built successfuly.\n\n");
+
+ exit(0);
+}
diff --git a/arch/ppc/treeboot/mkirimg b/arch/ppc/treeboot/mkirimg
new file mode 100644
index 000000000..e8aa24e3d
--- /dev/null
+++ b/arch/ppc/treeboot/mkirimg
@@ -0,0 +1,367 @@
+#!/usr/local/bin/perl
+#
+# Copyright (c) 1998-1999 TiVo, Inc.
+# Original ELF parsing code.
+#
+# Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+# Original code from 'mkevimg'.
+#
+# Module name: mkirimg
+#
+# Description:
+# Reads an ELF file and assigns global variables 'imageSect_start',
+# 'imageSect_size', 'initrdSect_start', and 'initrdSect_size' from
+# the "image" and "initrd" section header information. It then
+# rewrites the input ELF file with assigned globals to an output
+# file.
+#
+# An input file, "irSectStart.txt" has the memory address of
+# 'irSectStart'. The irSectStart memory address is used to find
+# the global variables in the ".data" section of the ELF file.
+# The 'irSectStart' and the above global variables are defined
+# in "irSect.c".
+#
+#
+
+use File::Basename;
+use Getopt::Std;
+
+#
+# usage()
+#
+# Description:
+# This routine prints out the proper command line usage for this program
+#
+# Input(s):
+# status - Flag determining what usage information will be printed and what
+# the exit status of the program will be after the information is
+# printed.
+#
+# Output(s):
+# N/A
+#
+# Returns:
+# This subroutine does not return.
+#
+
+sub usage {
+ my($status);
+ $status = $_[0];
+
+ printf("Usage: %s [-hvV] <ELF input file> <Evaluation board output file> <irSectStart.txt file>\n",
+ $program);
+
+ if ($status != 0) {
+ printf("Try `%s -h' for more information.\n", $program);
+ }
+
+ if ($status != 1) {
+ print(" -h Print out this message and exit.\n");
+ print(" -v Verbose. Print out lots of ELF information.\n");
+ print(" -V Print out version information and exit.\n");
+ }
+
+ exit($status);
+}
+
+#
+# version()
+#
+# Description:
+# This routine prints out program version information
+#
+# Input(s):
+# N/A
+#
+# Output(s):
+# N/A
+#
+# Returns:
+# This subroutine does not return.
+#
+
+sub version {
+ print("mkirimg Version 1.1.0\n");
+ print("Copyright (c) 1998-1999 TiVo, Inc.\n");
+ print("Copyright (c) 1999 Grant Erickson <grant\@lcse.umn.edu>\n");
+
+ exit (0);
+}
+
+#
+# file_check()
+#
+# Description:
+# This routine checks an input file to ensure that it exists, is a
+# regular file, and is readable.
+#
+# Input(s):
+# file - Input file to be checked.
+#
+# Output(s):
+# N/A
+#
+# Returns:
+# 0 if the file exists, is a regular file, and is readable, otherwise -1.
+#
+
+sub file_check {
+ my($file);
+ $file = $_[0];
+
+ if (!(-e $file)) {
+ printf("The file \"%s\" does not exist.\n", $file);
+ return (-1);
+ } elsif (!(-f $file)) {
+ printf("The file \"%s\" is not a regular file.\n", $file);
+ return (-1);
+ } elsif (!(-r $file)) {
+ printf("The file \"%s\" is not readable.\n", $file);
+ return (-1);
+ }
+
+ return (0);
+}
+
+#
+# decode_options()
+#
+# Description:
+# This routine steps through the command-line arguments, parsing out
+# recognzied options.
+#
+# Input(s):
+# N/A
+#
+# Output(s):
+# N/A
+#
+# Returns:
+# N/A
+#
+
+sub decode_options {
+
+ if (!getopts("hvV")) {
+ usage(1);
+ }
+
+ if ($opt_h) {
+ usage(0);
+ }
+
+ if ($opt_V) {
+ version();
+ exit (0);
+ }
+
+ if ($opt_v) {
+ $verbose = 1;
+ }
+
+ if (!($ElfFile = shift(@ARGV))) {
+ usage(1);
+ }
+
+ if (!($OutputFile = shift(@ARGV))) {
+ usage (1);
+ }
+
+ if (!($IrFile = shift(@ARGV))) {
+ usage (1);
+ }
+
+ if (file_check($ElfFile)) {
+ exit(1);
+ }
+
+ if (file_check($IrFile)) {
+ exit(1);
+ }
+}
+
+#
+# ELF file and section header field numbers
+#
+
+require 'elf.pl';
+
+#
+# Main program body
+#
+
+{
+ $program = basename($0);
+ decode_options();
+
+ open(ELF, "<$ElfFile") || die "Cannot open input file";
+ open(OUTPUT, ">$OutputFile") || die "Cannot open output file";
+ open(IR, "$IrFile") || die "Cannot open input file";
+
+ $ElfFilesize = (-s $ElfFile);
+
+ if (read(ELF, $ibuf, $ElfFilesize) != $ElfFilesize) {
+ print("Failed to read ELF input file!\n");
+ exit(1);
+ }
+
+ if (read(IR, $irbuf, 8) != 8) {
+ print("Failed to read Ir input file!\n");
+ exit(1);
+ }
+
+ #
+ # Parse ELF header
+ #
+
+ @eh = unpack("a16n2N5n6", $ibuf);
+
+ #
+ # Make sure this is actually a PowerPC ELF file.
+ #
+
+ if (substr($eh[$e_ident], 0, 4) ne "\177ELF") {
+ printf("The file \"%s\" is not an ELF file.\n", $ElfFile);
+ exit (1);
+ } elsif ($eh[$e_machine] != 20) {
+ printf("The file \"%s\" is not a PowerPC ELF file.\n", $ElfFile);
+ exit (1);
+ }
+
+ #
+ # Find the section header for the string table.
+ #
+
+ $strtable_section_offset = $eh[$e_shoff] +
+
+ $eh[$e_shstrndx] * $eh[$e_shentsize];
+
+ if ($verbose) {
+ printf("String table section header offset: 0x%x\n",
+ $strtable_section_offset);
+ }
+
+ #
+ # Find the start of the string table.
+ #
+
+ @strh = unpack("N10", substr($ibuf, $strtable_section_offset,
+ $eh[$e_shentsize]));
+
+ if ($verbose) {
+ printf("Section name strings start at: 0x%x, %d bytes.\n",
+ $strh[$sh_offset], $strh[$sh_size]);
+ }
+
+ $names = substr($ibuf, $strh[$sh_offset], $strh[$sh_size]);
+
+ # Grab each section header and find '.data', 'image', and
+ # 'initrd' sections in particular.
+
+ $off = $eh[$e_shoff];
+ $imageFound = 0;
+ $initrdFound = 0;
+
+ for($i = 0; $i < $eh[$e_shnum]; $i++, $off += $eh[$e_shentsize]) {
+ @sh = unpack("N10", substr($ibuf, $off, $eh[$e_shentsize]));
+
+ # Take the first section name from the array returned by split.
+
+ ($name) = split(/\000/, substr($names, $sh[$sh_name]));
+
+ # Attempt to find the .data, image, and initrd sections
+
+ if ($name =~ /^\image$/) {
+ ($image_addr, $image_offset, $image_size) =
+ ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]);
+ $imageFound = 1;
+
+ } elsif ($name =~ /^\initrd$/) {
+ ($initrd_addr, $initrd_offset, $initrd_size) =
+ ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]);
+ $initrdFound = 1;
+
+ } elsif ($name =~ /^\.data$/) {
+ ($data_addr, $data_offset, $data_size) =
+ ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]);
+
+ } elsif ($name =~ /^\.bss$/) {
+ ($bss_addr, $bss_offset, $bss_size) =
+ ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]);
+
+ }
+ }
+
+ if ($verbose) {
+ printf("Data section - Address: 0x%08x, Size: 0x%08x, File Offset 0x%08x\n",
+ $data_addr, $data_size, $data_offset);
+ printf("Bss section - Address: 0x%08x, Size: 0x%08x, File Offset 0x%08x\n",
+ $bss_addr, $bss_size, $bss_offset);
+ }
+
+ if ($verbose) {
+ if ($imageFound) {
+ printf("Image section - Address: 0x%08x, Size: 0x%08x\n",
+ $image_addr, $image_size);
+ } else {
+ printf("Image section not found in file: $ElfFile\n");
+ }
+
+ if ($initrdFound) {
+ printf("Initrd section - Address: 0x%08x, Size: 0x%08x\n",
+ $initrd_addr, $initrd_size);
+ } else {
+ printf("Initrd section not found in file: $ElfFile\n");
+ }
+ }
+
+ # get file offset of irSectStart
+
+ $irSectStartoffset = hex ($irbuf);
+
+ if ($verbose) {
+ printf("irSectStartOffset Address: 0x%08x\n", $irSectStartoffset);
+ }
+
+ # get the offset of global variables
+
+ $initialOffset = ($irSectStartoffset - $data_addr) + $data_offset + 4;
+
+ # write modified values to OUTPUT file
+
+ syswrite(OUTPUT, $ibuf, $initialOffset);
+
+ if ($imageFound) {
+ $testN = pack ("I2", $bss_addr + $bss_size, $image_size);
+ syswrite(OUTPUT, $testN, length($testN));
+ printf("Updated symbol \"imageSect_start\" to 0x%08x\n",
+ $bss_addr + $bss_size);
+ printf("Updated symbol \"imageSect_size\" to 0x%08x\n", $image_size);
+ } else {
+ syswrite(OUTPUT, $ibuf, 8, $initialOffset);
+ }
+
+ if ($initrdFound) {
+ $testN = pack ("I2", $bss_addr + $bss_size + $image_size, $initrd_size);
+ syswrite(OUTPUT, $testN, length($testN));
+ printf("Updated symbol \"initrdSect_start\" to 0x%08x\n",
+ $bss_addr + $bss_size + $image_size);
+ printf("Updated symbol \"initrdSect_size\" to 0x%08x\n", $initrd_size);
+ } else {
+ syswrite(OUTPUT, $ibuf,8, $initialOffset + 8);
+ }
+
+ syswrite(OUTPUT, $ibuf, $ElfFilesize - ($initialOffset + 16),
+ $initialOffset + 16);
+
+ #
+ # Clean-up and leave
+ #
+
+ close (ELF);
+ close (OUTPUT);
+ close (IR);
+
+ exit (0);
+}
+