From d1e063beb43e595680c65e3804d1f8ddff53373b Mon Sep 17 00:00:00 2001 From: Guido Guenther Date: Sat, 18 Nov 2006 23:48:07 +0100 Subject: Imported Debian version 0.3.8.8 --- tip22/.cvsignore | 6 + tip22/Makefile | 73 +++++ tip22/README | 32 ++ tip22/kernel/parse_rd_cmd_line-2.4-2002-05-09.diff | 88 +++++ tip22/kernel/parse_rd_cmd_line-2.6-2004-11-17.diff | 172 ++++++++++ tip22/ld.kernel.script.in | 11 + tip22/ld.ramdisk.script.in | 11 + tip22/ld.script.in | 78 +++++ tip22/tftpload.c | 353 +++++++++++++++++++++ tip22/tip22 | 51 +++ tip22/tip32 | 51 +++ 11 files changed, 926 insertions(+) create mode 100644 tip22/.cvsignore create mode 100644 tip22/Makefile create mode 100644 tip22/README create mode 100644 tip22/kernel/parse_rd_cmd_line-2.4-2002-05-09.diff create mode 100644 tip22/kernel/parse_rd_cmd_line-2.6-2004-11-17.diff create mode 100644 tip22/ld.kernel.script.in create mode 100644 tip22/ld.ramdisk.script.in create mode 100644 tip22/ld.script.in create mode 100644 tip22/tftpload.c create mode 100644 tip22/tip22 create mode 100755 tip22/tip32 (limited to 'tip22') diff --git a/tip22/.cvsignore b/tip22/.cvsignore new file mode 100644 index 0000000..c5aacb9 --- /dev/null +++ b/tip22/.cvsignore @@ -0,0 +1,6 @@ +ld.kernel.script.IP22 +ld.kernel.script.IP32 +ld.ramdisk.script.IP22 +ld.ramdisk.script.IP32 +ld.script.IP22 +ld.script.IP32 diff --git a/tip22/Makefile b/tip22/Makefile new file mode 100644 index 0000000..2efe8ae --- /dev/null +++ b/tip22/Makefile @@ -0,0 +1,73 @@ +# +# Copyright 2002-2004 Guido Guenther +# + +ARCLIBDIR = ../arclib +ARCLIB = $(ARCLIBDIR)/libarc.a + +COMMONDIR = ../common +PRINT_LOADADDR = $(COMMONDIR)/print_loadaddr +PRINT_OUTPUTFORMAT = $(COMMONDIR)/print_outputformat + +CFLAGS += -O2 -I$(COMMONDIR) -I$(ARCLIBDIR) -Wall -mno-abicalls -G 0 \ + -fno-pic -DSUBARCH=${SUBARCH} + +ASFLAGS = -O2 -mno-abicalls -G 0 -fno-pic + +LIBDIR ?= /usr/lib/tip22 +BINDIR ?= /usr/sbin + +LIBS=${ARCLIB} +BINS=tip22 tip32 +LD_SCRIPTS = ld.kernel.script.$(SUBARCH) ld.ramdisk.script.$(SUBARCH) ld.script.$(SUBARCH) +OBJECTS = tftpload.$(SUBARCH).o +TARGETS = $(OBJECTS) $(LD_SCRIPTS) + +# uncomment for debugging +#CFLAGS+=-DDEBUG + + +all: ${LIBS} ${BINS} + @$(MAKE) SUBARCH=IP32 archall + @$(MAKE) SUBARCH=IP22 archall + +archall: $(TARGETS) + + +$(ARCLIB): + @$(MAKE) -C $(ARCLIBDIR) + +$(PRINT_LOADADDR): + @$(MAKE) -C $(COMMONDIR) SUBARCH=$(SUBARCH) + + +%.$(SUBARCH).o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +%.script.$(SUBARCH): %.script.in $(PRINT_LOADADDR) $(PRINT_OUTPUTFORMAT) + LOADADDR=$$($(PRINT_LOADADDR) $(SUBARCH)); \ + OUTPUTFORMAT=$$($(PRINT_OUTPUTFORMAT) $(SUBARCH)); \ + sed -e "s/@@LOADADDR@@/$$LOADADDR/" \ + -e "s/@@OUTPUTFORMAT@@/$$OUTPUTFORMAT/" <$< >$@ + +clean: + @$(MAKE) SUBARCH=IP32 archclean + @$(MAKE) SUBARCH=IP22 archclean + rm -f tags *~ + +archclean: + @$(MAKE) -C $(ARCLIBDIR) clean + @$(MAKE) -C $(COMMONDIR) clean + rm -f $(TARGETS) + +install: all + install -d ${PREFIX}/${BINDIR} + install -m 755 ${BINS} ${PREFIX}/${BINDIR} + @$(MAKE) SUBARCH=IP32 archinstall + @$(MAKE) SUBARCH=IP22 archinstall + +archinstall: + $(foreach tg,$(TARGETS),install -m 644 $(tg) ${PREFIX}/${LIBDIR};) + + +.PHONY: all archall clean archclean install archinstall diff --git a/tip22/README b/tip22/README new file mode 100644 index 0000000..becc313 --- /dev/null +++ b/tip22/README @@ -0,0 +1,32 @@ +How to create the boot image: +----------------------------------- + +tip22 +tip32 + +- vmlinux is an ELF Linux kernel. For versions before 2.6.9 you need to + apply an extra patch for correct commandline parsing, see + /usr/share/doc/tip22/examples. +- initrd is the gzip compressed initial ramdisk you want add +- outputfile is the bootimage. It is in ECOFF format for ip22 and in + ELF format for ip32. You can for example tfpboot this image on an SGI + Indy using the bootp(): command in the prom. + +it basically works like this: +----------------------------- +- tftpload.o is a relocatable object created during package build time +- the tip22 script converts the ramdisk and vmlinux to relocatable + objects using linker scripts including symbols that mark the begin + and the end of kernel and ramdisk +- those are linked together into the output file using yet another + linker script +- when executed by the prom the embedded loader: + - memcopies the kernel to its loadaddress + - memcopies the initrd after the kernel to a page boundary + - parses the command line and everything within an append="..." + statement is passed on to the kernel, e.g. + 'bootp(): append="console=ttyS0"' + - jumps into the kernel passing the start address and size of the + initrd on the command line + + -- Thu, 15 May 2002 23:07:18 +0200 Guido Guenther diff --git a/tip22/kernel/parse_rd_cmd_line-2.4-2002-05-09.diff b/tip22/kernel/parse_rd_cmd_line-2.4-2002-05-09.diff new file mode 100644 index 0000000..c1bd785 --- /dev/null +++ b/tip22/kernel/parse_rd_cmd_line-2.4-2002-05-09.diff @@ -0,0 +1,88 @@ +Index: arch/mips/kernel/setup.c +=================================================================== +RCS file: /cvs/linux/arch/mips/kernel/setup.c,v +retrieving revision 1.96.2.12 +diff -u -u -r1.96.2.12 setup.c +--- arch/mips/kernel/setup.c 2002/02/15 21:05:48 1.96.2.12 ++++ arch/mips/kernel/setup.c 2002/05/09 17:17:59 +@@ -650,6 +650,38 @@ + } + } + ++static inline void parse_rd_cmdline(unsigned long* rd_start, unsigned long* rd_end) ++{ ++ char c = ' ', *to = command_line, *from = saved_command_line; ++ int len = 0; ++ unsigned long rd_size = 0; ++ ++ for (;;) { ++ /* ++ * "rd_start=0xNNNNNNNN" defines the memory address of an initrd ++ * "rd_size=0xNN" it's size ++ */ ++ if (c == ' ' && !memcmp(from, "rd_start=", 9)) { ++ if (to != command_line) ++ to--; ++ (*rd_start) = memparse(from + 9, &from); ++ } ++ if (c == ' ' && !memcmp(from, "rd_size=", 8)) { ++ if (to != command_line) ++ to--; ++ rd_size = memparse(from + 8, &from); ++ } ++ c = *(from++); ++ if (!c) ++ break; ++ if (CL_SIZE <= ++len) ++ break; ++ *(to++) = c; ++ } ++ *to = '\0'; ++ (*rd_end) = (*rd_start) + rd_size; ++} ++ + void __init setup_arch(char **cmdline_p) + { + void atlas_setup(void); +@@ -674,10 +706,7 @@ + + unsigned long bootmap_size; + unsigned long start_pfn, max_pfn, max_low_pfn, first_usable_pfn; +-#ifdef CONFIG_BLK_DEV_INITRD +- unsigned long tmp; +- unsigned long* initrd_header; +-#endif ++ unsigned long end = &_end; + + int i; + +@@ -828,22 +857,18 @@ + #define MAXMEM_PFN PFN_DOWN(MAXMEM) + + #ifdef CONFIG_BLK_DEV_INITRD +- tmp = (((unsigned long)&_end + PAGE_SIZE-1) & PAGE_MASK) - 8; +- if (tmp < (unsigned long)&_end) +- tmp += PAGE_SIZE; +- initrd_header = (unsigned long *)tmp; +- if (initrd_header[0] == 0x494E5244) { +- initrd_start = (unsigned long)&initrd_header[2]; +- initrd_end = initrd_start + initrd_header[1]; ++ parse_rd_cmdline(&initrd_start, &initrd_end); ++ if(initrd_start && initrd_end) ++ end = initrd_end; ++ else { ++ initrd_start = initrd_end = 0; + } +- start_pfn = PFN_UP(__pa((&_end)+(initrd_end - initrd_start) + PAGE_SIZE)); +-#else ++#endif /* CONFIG_BLK_DEV_INITRD */ + /* + * Partially used pages are not usable - thus + * we are rounding upwards. + */ +- start_pfn = PFN_UP(__pa(&_end)); +-#endif /* CONFIG_BLK_DEV_INITRD */ ++ start_pfn = PFN_UP(__pa(end)); + + /* Find the highest page frame number we have available. */ + max_pfn = 0; diff --git a/tip22/kernel/parse_rd_cmd_line-2.6-2004-11-17.diff b/tip22/kernel/parse_rd_cmd_line-2.6-2004-11-17.diff new file mode 100644 index 0000000..504dd66 --- /dev/null +++ b/tip22/kernel/parse_rd_cmd_line-2.6-2004-11-17.diff @@ -0,0 +1,172 @@ +Index: arch/mips/kernel/setup.c +=================================================================== +RCS file: /home/cvs/linux/arch/mips/kernel/setup.c,v +retrieving revision 1.171 +diff -u -p -r1.171 setup.c +--- arch/mips/kernel/setup.c 28 Jun 2004 21:04:12 -0000 1.171 ++++ arch/mips/kernel/setup.c 19 Nov 2004 00:45:23 -0000 +@@ -194,6 +194,68 @@ static inline void parse_cmdline_early(v + } + } + ++static inline int parse_rd_cmdline(unsigned long* rd_start, unsigned long* rd_end) ++{ ++ /* ++ * "rd_start=0xNNNNNNNN" defines the memory address of an initrd ++ * "rd_size=0xNN" it's size ++ */ ++ unsigned long start = 0; ++ unsigned long size = 0; ++ unsigned long end; ++ char cmd_line[CL_SIZE]; ++ char *start_str; ++ char *size_str; ++ char *tmp; ++ ++ strcpy(cmd_line, command_line); ++ *command_line = 0; ++ tmp = cmd_line; ++ /* Ignore "rd_start=" strings in other parameters. */ ++ start_str = strstr(cmd_line, "rd_start="); ++ if (start_str && start_str != cmd_line && *(start_str - 1) != ' ') ++ start_str = strstr(start_str, " rd_start="); ++ while (start_str) { ++ if (start_str != cmd_line) ++ strncat(command_line, tmp, start_str - tmp); ++ start = memparse(start_str + 9, &start_str); ++ tmp = start_str + 1; ++ start_str = strstr(start_str, " rd_start="); ++ } ++ if (*tmp) ++ strcat(command_line, tmp); ++ ++ strcpy(cmd_line, command_line); ++ *command_line = 0; ++ tmp = cmd_line; ++ /* Ignore "rd_size" strings in other parameters. */ ++ size_str = strstr(cmd_line, "rd_size="); ++ if (size_str && size_str != cmd_line && *(size_str - 1) != ' ') ++ size_str = strstr(size_str, " rd_size="); ++ while (size_str) { ++ if (size_str != cmd_line) ++ strncat(command_line, tmp, size_str - tmp); ++ size = memparse(size_str + 8, &size_str); ++ tmp = size_str + 1; ++ size_str = strstr(size_str, " rd_size="); ++ } ++ if (*tmp) ++ strcat(command_line, tmp); ++ ++#ifdef CONFIG_MIPS64 ++ /* HACK: Guess if the sign extension was forgotten */ ++ if (start > 0x0000000080000000 && start < 0x00000000ffffffff) ++ start |= 0xffffffff00000000; ++#endif ++ ++ end = start + size; ++ if (start && end) { ++ *rd_start = start; ++ *rd_end = end; ++ return 1; ++ } ++ return 0; ++} + + #define PFN_UP(x) (((x) + PAGE_SIZE - 1) >> PAGE_SHIFT) + #define PFN_DOWN(x) ((x) >> PAGE_SHIFT) +@@ -205,30 +267,45 @@ static inline void parse_cmdline_early(v + static inline void bootmem_init(void) + { + unsigned long start_pfn; ++ unsigned long reserved_end = (unsigned long)&_end; + #ifndef CONFIG_SGI_IP27 +- unsigned long bootmap_size, max_low_pfn, first_usable_pfn; ++ unsigned long first_usable_pfn; ++ unsigned long bootmap_size; + int i; + #endif + #ifdef CONFIG_BLK_DEV_INITRD +- unsigned long tmp; +- unsigned long *initrd_header; ++ int initrd_reserve_bootmem = 0; + +- tmp = (((unsigned long)&_end + PAGE_SIZE-1) & PAGE_MASK) - 8; +- if (tmp < (unsigned long)&_end) +- tmp += PAGE_SIZE; +- initrd_header = (unsigned long *)tmp; +- if (initrd_header[0] == 0x494E5244) { +- initrd_start = (unsigned long)&initrd_header[2]; +- initrd_end = initrd_start + initrd_header[1]; ++ /* Board specific code should have set up initrd_start and initrd_end */ ++ ROOT_DEV = Root_RAM0; ++ if (&__rd_start != &__rd_end) { ++ initrd_start = (unsigned long)&__rd_start; ++ initrd_end = (unsigned long)&__rd_end; ++ } else if (parse_rd_cmdline(&initrd_start, &initrd_end)) { ++ reserved_end = max(reserved_end, initrd_end); ++ initrd_reserve_bootmem = 1; ++ } else { ++ unsigned long tmp; ++ unsigned long *initrd_header; ++ ++ tmp = ((reserved_end + PAGE_SIZE-1) & PAGE_MASK) - 8; ++ if (tmp < reserved_end) ++ tmp += PAGE_SIZE; ++ initrd_header = (unsigned long *)tmp; ++ if (initrd_header[0] == 0x494E5244) { ++ initrd_start = (unsigned long)&initrd_header[2]; ++ initrd_end = initrd_start + initrd_header[1]; ++ reserved_end = max(reserved_end, initrd_end); ++ initrd_reserve_bootmem = 1; ++ } + } +- start_pfn = PFN_UP(CPHYSADDR((&_end)+(initrd_end - initrd_start) + PAGE_SIZE)); +-#else ++#endif /* CONFIG_BLK_DEV_INITRD */ ++ + /* + * Partially used pages are not usable - thus + * we are rounding upwards. + */ +- start_pfn = PFN_UP(CPHYSADDR(&_end)); +-#endif /* CONFIG_BLK_DEV_INITRD */ ++ start_pfn = PFN_UP(CPHYSADDR(reserved_end)); + + #ifndef CONFIG_SGI_IP27 + /* Find the highest page frame number we have available. */ +@@ -341,21 +418,14 @@ static inline void bootmem_init(void) + + /* Reserve the bootmap memory. */ + reserve_bootmem(PFN_PHYS(first_usable_pfn), bootmap_size); +-#endif ++#endif /* CONFIG_SGI_IP27 */ + + #ifdef CONFIG_BLK_DEV_INITRD +- /* Board specific code should have set up initrd_start and initrd_end */ +- ROOT_DEV = Root_RAM0; +- if (&__rd_start != &__rd_end) { +- initrd_start = (unsigned long)&__rd_start; +- initrd_end = (unsigned long)&__rd_end; +- } + initrd_below_start_ok = 1; + if (initrd_start) { + unsigned long initrd_size = ((unsigned char *)initrd_end) - ((unsigned char *)initrd_start); + printk("Initial ramdisk at: 0x%p (%lu bytes)\n", +- (void *)initrd_start, +- initrd_size); ++ (void *)initrd_start, initrd_size); + + if (CPHYSADDR(initrd_end) > PFN_PHYS(max_low_pfn)) { + printk("initrd extends beyond end of memory " +@@ -363,7 +433,11 @@ static inline void bootmem_init(void) + sizeof(long) * 2, CPHYSADDR(initrd_end), + sizeof(long) * 2, PFN_PHYS(max_low_pfn)); + initrd_start = initrd_end = 0; ++ initrd_reserve_bootmem = 0; + } ++ ++ if (initrd_reserve_bootmem) ++ reserve_bootmem(CPHYSADDR(initrd_start), initrd_size); + } + #endif /* CONFIG_BLK_DEV_INITRD */ + } diff --git a/tip22/ld.kernel.script.in b/tip22/ld.kernel.script.in new file mode 100644 index 0000000..df01e37 --- /dev/null +++ b/tip22/ld.kernel.script.in @@ -0,0 +1,11 @@ +OUTPUT_FORMAT("@@OUTPUTFORMAT@@") +OUTPUT_ARCH(mips) +SECTIONS +{ + .data : + { + __kernel_start = .; + *(.data) + __kernel_end = .; + } +} diff --git a/tip22/ld.ramdisk.script.in b/tip22/ld.ramdisk.script.in new file mode 100644 index 0000000..38f11d2 --- /dev/null +++ b/tip22/ld.ramdisk.script.in @@ -0,0 +1,11 @@ +OUTPUT_FORMAT("@@OUTPUTFORMAT@@") +OUTPUT_ARCH(mips) +SECTIONS +{ + .data : + { + __rd_start = .; + *(.data) + __rd_end = .; + } +} diff --git a/tip22/ld.script.in b/tip22/ld.script.in new file mode 100644 index 0000000..4f5597c --- /dev/null +++ b/tip22/ld.script.in @@ -0,0 +1,78 @@ +OUTPUT_FORMAT("@@OUTPUTFORMAT@@") +OUTPUT_ARCH(mips) +ENTRY(_start) +SECTIONS +{ + /* XXX: place the loader after the kernel */ + . = @@LOADADDR@@; + + /* read-only */ + _text = .; /* Text and read-only data */ + .text : { + _ftext = .; + *(.text .text.*) + *(.rodata*) + } =0 + + _etext = .; /* End of text section */ + PROVIDE (etext = .); + + . = ALIGN(16); + + /* writeable */ + .data : { + _fdata = .; + *(.data .data.*) + } =0 + + _gp = ALIGN(16) + 0x7ff0; + .lit8 : { *(.lit8) } + .lit4 : { *(.lit4) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + + _edata = .; + PROVIDE (edata = .); + + __bss_start = .; + .sbss : { + *(.sbss) + *(.scommon) + } + .bss : { + _fbss = .; + *(.dynbss) + *(.bss .bss.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(32 / 8); + } + . = ALIGN(32 / 8); + __bss_stop = .; + _end = .; + PROVIDE (end = .); + + /* Sections to be discarded */ + /DISCARD/ : { + *(.text.exit) + *(.data.exit) + *(.exitcall.exit) + *(.stab) + *(.stabstr) + *(.pdr) + *(.note) + *(.reginfo) + *(.options) + *(.MIPS.options) + *(.debug*) + *(.line) + *(.mdebug*) + *(.comment*) + *(.gptab*) + *(.note) + } +} diff --git a/tip22/tftpload.c b/tip22/tftpload.c new file mode 100644 index 0000000..c0bf0a2 --- /dev/null +++ b/tip22/tftpload.c @@ -0,0 +1,353 @@ +/* + * Copyright 2002-04 Guido Guenther + * + * based on arcboot/ext2load/loader.c + * + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#define KSEG0ADDR(addr) (((addr) & 0x1fffffff) | 0x80000000) + +#define ANSI_CLEAR "\033[2J" + +typedef enum { False = 0, True } Boolean; + +extern void* __kernel_start; +extern void* __kernel_end; +extern void* __rd_start; +extern void* __rd_end; + +static void Wait(const char *prompt) +{ + int ch; + + if (prompt != NULL) + puts(prompt); + + do { + ch = getchar(); + } while ((ch != EOF) && (((char) ch) != ' ')); +} + + +static void Fatal(const CHAR * message, ...) +{ + va_list ap; + + if (message != NULL) { + printf("FATAL ERROR: "); + va_start(ap, message); + vprintf(message, ap); + va_end(ap); + } + + Wait("\n\r--- Press to enter ARC interactive mode ---"); + ArcEnterInteractiveMode(); +} + + +static void InitMalloc(void) +{ + MEMORYDESCRIPTOR *current = NULL; + ULONG stack = (ULONG) & current; +#ifdef DEBUG + printf("stack starts at: 0x%lx\n\r", stack); +#endif + + current = ArcGetMemoryDescriptor(current); + if(! current ) { + Fatal("Can't find any valid memory descriptors!\n\r"); + } + while (current != NULL) { + /* + * The spec says we should have an adjacent FreeContiguous + * memory area that includes our stack. It would be much + * easier to just look for that and give it to malloc, but + * the Indy only shows FreeMemory areas, no FreeContiguous. + * Oh well. + */ + if (current->Type == FreeMemory) { + ULONG start = KSEG0ADDR(current->BasePage * PAGE_SIZE); + ULONG end = + start + (current->PageCount * PAGE_SIZE); +#if DEBUG + printf("Free Memory(%u) segment found at (0x%lx,0x%lx).\n\r", + current->Type, start, end); +#endif + + /* Leave some space for our stack */ + if ((stack >= start) && (stack < end)) + end = + (stack - + (STACK_PAGES * + PAGE_SIZE)) & ~(PAGE_SIZE - 1); + /* Don't use memory from reserved region */ + if ((start >= kernel_load[SUBARCH].base ) + && (start < (kernel_load[SUBARCH].base + + kernel_load[SUBARCH].reserved ))) + start = kernel_load[SUBARCH].base + + kernel_load[SUBARCH].reserved; + if ((end > kernel_load[SUBARCH].base) + && (end <= (kernel_load[SUBARCH].base + + kernel_load[SUBARCH].reserved ))) + end = kernel_load[SUBARCH].base; + if (end > start) { +#ifdef DEBUG + printf("Adding %lu bytes at 0x%lx to the list of available memory\n\r", + end-start, start); +#endif + arclib_malloc_add(start, end - start); + } + } + current = ArcGetMemoryDescriptor(current); + } +} + +/* convert an offset in the kernel image to an address in the loaded tftpboot image */ +static void* offset2addr(unsigned long offset) +{ + void* address = (void*)((ULONG)&(__kernel_start) + offset); + return address; +} + +/* copy program segments to the locations the kernel expects */ +static ULONG CopyProgramSegments32(Elf32_Ehdr * header) +{ + int idx; + Boolean loaded = False; + Elf32_Phdr *segment, *segments; + size_t size = header->e_phentsize * header->e_phnum; + ULONG kernel_end=0L; + + if (size <= 0) + Fatal("No program segments\n\r"); + + segments = malloc(size); + if (segments == NULL) + Fatal("Cannot allocate memory for segment headers\n\r"); + + segments = (Elf32_Phdr*)offset2addr(header->e_phoff); + + segment = segments; + for (idx = 0; idx < header->e_phnum; idx++) { + if (segment->p_type == PT_LOAD) { + printf + ("Loading program segment %u at 0x%x, size = 0x%x\n\r", + idx + 1, KSEG0ADDR(segment->p_vaddr), segment->p_filesz); + + memcpy((void *)segment->p_vaddr, offset2addr(segment->p_offset), segment->p_filesz); + /* determine the highest address used by the kernel's memory image */ + if( kernel_end < segment->p_vaddr + segment->p_memsz ) { + kernel_end = segment->p_vaddr + segment->p_memsz; + } + + size = segment->p_memsz - segment->p_filesz; + if (size > 0) { + printf + ("Zeroing memory at 0x%x, size = 0x%x\n\r", + (KSEG0ADDR(segment->p_vaddr + + segment->p_filesz)), size); + memset((void *) + (KSEG0ADDR(segment-> + p_vaddr + segment->p_filesz)), 0, size); + } + loaded = True; + } + segment = + (Elf32_Phdr *) (((char *) segment) + + header->e_phentsize); + } + + if (!loaded) + Fatal("No loadable program segments found\n\r"); + + free(segments); + return kernel_end; +} + +static ULONG CopyProgramSegments64(Elf64_Ehdr * header) +{ + int idx; + Boolean loaded = False; + Elf64_Phdr *segment, *segments; + size_t size = header->e_phentsize * header->e_phnum; + ULONG kernel_end=0L; + + if (size <= 0) + Fatal("No program segments\n\r"); + + segments = malloc(size); + if (segments == NULL) + Fatal("Cannot allocate memory for segment headers\n\r"); + + segments = (Elf64_Phdr*)offset2addr(header->e_phoff); + + segment = segments; + for (idx = 0; idx < header->e_phnum; idx++) { + if (segment->p_type == PT_LOAD) { + printf("Loading program segment %u at 0x%x, size = 0x%llx\n\r", + idx + 1, KSEG0ADDR(segment->p_vaddr), segment->p_filesz); + + memcpy((void *)(long)(segment->p_vaddr), offset2addr(segment->p_offset), segment->p_filesz); + /* determine the highest address used by the kernel's memory image */ + if( kernel_end < segment->p_vaddr + segment->p_memsz ) { + kernel_end = segment->p_vaddr + segment->p_memsz; + } + + size = segment->p_memsz - segment->p_filesz; + if (size > 0) { + printf + ("Zeroing memory at 0x%x, size = 0x%x\n\r", + (KSEG0ADDR(segment->p_vaddr + + segment->p_filesz)), size); + memset((void *) + (KSEG0ADDR(segment-> + p_vaddr + segment->p_filesz)), 0, size); + } + loaded = True; + } + segment = + (Elf64_Phdr *) (((char *) segment) + + header->e_phentsize); + } + + if (!loaded) + Fatal("No loadable program segments found\n\r"); + + free(segments); + return kernel_end; +} + +static ULONG CopyKernel(ULONG* kernel_end) +{ + Elf32_Ehdr *header = (Elf32_Ehdr*)offset2addr(0L); + Elf64_Ehdr *header64 = (Elf64_Ehdr*)header; + + if (memcmp(&(header->e_ident[EI_MAG0]), ELFMAG, SELFMAG) != 0) + Fatal("Not an ELF file\n\r"); + + if (header->e_ident[EI_CLASS] == ELFCLASS32) { + if (header->e_ident[EI_DATA] != ELFDATA2MSB) + Fatal("Not a big-endian file\n\r"); + if (header->e_ident[EI_VERSION] != EV_CURRENT) + Fatal("Wrong ELF version\n\r"); + if (header->e_type != ET_EXEC) + Fatal("Not an executable file\n\r"); + if (header->e_machine != EM_MIPS) + Fatal("Unsupported machine type\n\r"); + if (header->e_version != EV_CURRENT) + Fatal("Wrong ELF version\n\r"); + + (*kernel_end) = CopyProgramSegments32(header); + + printf("Starting kernel; entry point = 0x%lx\n\r", + ((ULONG) KSEG0ADDR(header->e_entry))); + return KSEG0ADDR(header->e_entry); + } else if (header->e_ident[EI_CLASS] == ELFCLASS64) { + if (header64->e_ident[EI_DATA] != ELFDATA2MSB) + Fatal("Not a big-endian file\n\r"); + if (header64->e_ident[EI_VERSION] != EV_CURRENT) + Fatal("Wrong ELF version\n\r"); + if (header64->e_type != ET_EXEC) + Fatal("Not an executable file\n\r"); + if (header64->e_machine != EM_MIPS) + Fatal("Unsupported machine type\n\r"); + if (header64->e_version != EV_CURRENT) + Fatal("Wrong ELF version\n\r"); + + (*kernel_end) = CopyProgramSegments64(header64); + + printf("Starting kernel; entry point = 0x%lx\n\r", + ((ULONG) KSEG0ADDR(header64->e_entry))); + return KSEG0ADDR(header64->e_entry); + } else + Fatal("Neither an ELF32 nor an ELF64 kernel\n\r"); + + return 0L; +} + +static void copyRamdisk(void* rd_vaddr, void* rd_start, ULONG rd_size) +{ + memcpy(rd_vaddr, rd_start, rd_size); + printf("Copied initrd from 0x%p to 0x%p (0x%lx bytes)\n\r", + rd_start, rd_vaddr, rd_size); +} + +void _start(LONG argc, CHAR * argv[], CHAR * envp[]) +{ + char* nargv[3]; + int nargc,i; + char argv_rd[128]; /* passed to the kernel on its commandline */ + ULONG kernel_end = 0L; + ULONG rd_size= ((char*)&__rd_end) - ((char*)&__rd_start); + char* rd_vaddr=NULL; + void (*kernel_entry)(int argc, CHAR * argv[], CHAR * envp[]); + + /* Print identification */ +#if (SUBARCH == IP22) + printf(ANSI_CLEAR "\n\rtip22: IP22 Linux tftpboot loader " __ARCSBOOT_VERSION__ "\n\r"); +#elif (SUBARCH == IP32) + printf(ANSI_CLEAR "\n\rtip32: IP32 Linux tftpboot loader " __ARCSBOOT_VERSION__ "\n\r"); +#endif + + InitMalloc(); + + /* copy the kernel to its load address */ +#ifdef DEBUG + printf("Embedded kernel image starts 0x%p, ends 0x%p\n\r", + &__kernel_start, &__kernel_end); + printf("Embedded ramdisk image starts 0x%p, ends 0x%p\n\r", + &__rd_start, &__rd_end); +#endif + kernel_entry = (void (*)(int, CHAR *[], CHAR *[]))CopyKernel(&kernel_end); + + /* align to page boundary */ + rd_vaddr = (char*)(((kernel_end + PAGE_SIZE) / PAGE_SIZE ) * PAGE_SIZE); + copyRamdisk( rd_vaddr, (char*)&__rd_start, rd_size); + + /* tell the kernel about the ramdisk */ + sprintf(argv_rd, "rd_start=0x%p rd_size=0x%lx", rd_vaddr, rd_size); + + nargv[0] = argv[0]; + nargv[1] = argv_rd; + nargc=2; + for(i=1; i < argc; i++) { + if( !memcmp(argv[i],"append=",7) ) + break; + } + if( i < argc ) { /* we're asked to pass s.th. to the kernel */ + nargv[2] = argv[i]+7; + nargc++; + } + +#ifdef DEBUG + printf("Arguments passed to kernel:\n\r"); + for(i = 0; i < nargc; i++ ) + printf("%u: %s\n\r", i, nargv[i]); + Wait("\n\r--- Debug: press to boot kernel ---"); +#endif + /* Finally jump into the kernel */ + ArcFlushAllCaches(); + if( kernel_entry ) + (*kernel_entry)(nargc ,nargv, envp); + else + printf("Invalid kernel entry NULL\n\r"); + + /* Not likely to get back here in a functional state, + * but what the heck */ + Wait("\n\r--- Press to restart ---"); + ArcRestart(); +} diff --git a/tip22/tip22 b/tip22/tip22 new file mode 100644 index 0000000..86a5eb9 --- /dev/null +++ b/tip22/tip22 @@ -0,0 +1,51 @@ +#! /bin/sh -e +# +# Merges kernel and ramdisk into one ECOFF bootimage + +SUBARCH=IP22 + +LIBDIR=/usr/lib/tip22 +TIP22=$LIBDIR/tftpload.$SUBARCH.o +ARCLIB=$LIBDIR/libarc.a +LD_KERNEL=$LIBDIR/ld.kernel.script.$SUBARCH +LD_RAMDISK=$LIBDIR/ld.ramdisk.script.$SUBARCH +LD_SCRIPT=$LIBDIR/ld.script.$SUBARCH +LDFLAGS="-N" +LD=/usr/bin/ld +MKTEMP=/bin/mktemp + +usage() { + echo "`basename $0` vmlinux initrd outfile" + exit 1 +} + +if [ "$#" != "3" ]; then + usage +fi + +if ! file $2 | grep 'gzip compressed data' > /dev/null 2>&1; then + echo "$2 is no gzip compressed ramdisk". + usage +fi + +if ! file $1 | grep 'ELF .* MIPS' > /dev/null 2>&1; then + echo "$1 is no ELF kernel". + usage +fi + +if [ ! -x $MKTEMP ]; then + echo "Need mktemp." + exit 1 +fi + +if ! TMPDIR=`mktemp -d`; then + echo "mktemp failed." + exit 1 +fi + +echo -n "Merging kernel \"$1\" and ramdisk \"$2\" into bootimage \"$3\"..." +${LD} -T $LD_KERNEL -b binary -o $TMPDIR/kernel.o $1 +${LD} -T $LD_RAMDISK -b binary -o $TMPDIR/ramdisk.o $2 +${LD} -T $LD_SCRIPT ${LDFLAGS} -o $3 ${TIP22} ${ARCLIB} $TMPDIR/kernel.o $TMPDIR/ramdisk.o +rm -rf $TMPDIR +echo "done." diff --git a/tip22/tip32 b/tip22/tip32 new file mode 100755 index 0000000..0e91bb2 --- /dev/null +++ b/tip22/tip32 @@ -0,0 +1,51 @@ +#! /bin/sh -e +# +# Merges kernel and ramdisk into one ELF bootimage + +SUBARCH=IP32 + +LIBDIR=/usr/lib/tip22 +TIP22=$LIBDIR/tftpload.$SUBARCH.o +ARCLIB=$LIBDIR/libarc.a +LD_KERNEL=$LIBDIR/ld.kernel.script.$SUBARCH +LD_RAMDISK=$LIBDIR/ld.ramdisk.script.$SUBARCH +LD_SCRIPT=$LIBDIR/ld.script.$SUBARCH +LDFLAGS="-n" +LD=/usr/bin/ld +MKTEMP=/bin/mktemp + +usage() { + echo "`basename $0` vmlinux initrd outfile" + exit 1 +} + +if [ "$#" != "3" ]; then + usage +fi + +if ! file $2 | grep 'gzip compressed data' > /dev/null 2>&1; then + echo "$2 is no gzip compressed ramdisk". + usage +fi + +if ! file $1 | grep 'ELF .* MIPS' > /dev/null 2>&1; then + echo "$1 is no ELF kernel". + usage +fi + +if [ ! -x $MKTEMP ]; then + echo "Need mktemp." + exit 1 +fi + +if ! TMPDIR=`mktemp -d`; then + echo "mktemp failed." + exit 1 +fi + +echo -n "Merging kernel \"$1\" and ramdisk \"$2\" into bootimage \"$3\"..." +${LD} -T $LD_KERNEL -b binary -o $TMPDIR/kernel.o $1 +${LD} -T $LD_RAMDISK -b binary -o $TMPDIR/ramdisk.o $2 +${LD} -T $LD_SCRIPT ${LDFLAGS} -o $3 ${TIP22} ${ARCLIB} $TMPDIR/kernel.o $TMPDIR/ramdisk.o +rm -rf $TMPDIR +echo "done." -- cgit v1.2.3