diff --git a/.gitignore b/.gitignore index 0d602a0..fb52dbb 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ git_version.h *.bin *.elf *.map +*~ diff --git a/Makefile b/Makefile index b5296d7..263841c 100644 --- a/Makefile +++ b/Makefile @@ -5,8 +5,8 @@ CFLAGS += -DCAN_HAZ_IRQ -DCAN_HAZ_IPC LDSCRIPT = mini.ld LIBS = -lgcc -ELFLOADER = ../elfloader/elfloader.bin -MAKEBIN = python ../makebin.py +ELFLOADER = elfloader/elfloader.bin +MAKEBIN = python makebin.py TARGET = armboot.elf TARGET_BIN = armboot.bin @@ -34,6 +34,10 @@ git_version.h: clean: myclean +$(ELFLOADER): + make -C elfloader + myclean: -rm -f $(TARGET_BIN) git_version.h + $(MAKE) -C elfloader clean diff --git a/elfloader/.gitignore b/elfloader/.gitignore new file mode 100644 index 0000000..bfbdbf1 --- /dev/null +++ b/elfloader/.gitignore @@ -0,0 +1,6 @@ +*.d +*.bin +*.elf +*.o +*.map + diff --git a/elfloader/Makefile b/elfloader/Makefile new file mode 100644 index 0000000..d4ff498 --- /dev/null +++ b/elfloader/Makefile @@ -0,0 +1,23 @@ +include ../starlet.mk + +CFLAGS += -fpic +LDSCRIPT = stub.ld +LIBS = -lgcc + +TARGET = elfloader.elf +TARGET_BIN = elfloader.bin +OBJS = start.o stub.o string.o utils.o + +include ../common.mk + +all: $(TARGET_BIN) + +$(TARGET_BIN): $(TARGET) + @echo " OBJCPY $@" + @$(OBJCOPY) -O binary $< $@ + +clean: myclean + +myclean: + -rm -f $(TARGET_BIN) + diff --git a/elfloader/elf.h b/elfloader/elf.h new file mode 100644 index 0000000..88ab2b7 --- /dev/null +++ b/elfloader/elf.h @@ -0,0 +1,66 @@ +/* + mini - a Free Software replacement for the Nintendo/BroadOn IOS. + + ELF loader: ELF structures + +Copyright (C) 2008, 2009 Hector Martin "marcan" + +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, version 2. + +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 + +*/ +#ifndef __ELF_H__ +#define __ELF_H__ + +#include "types.h" + +#define EI_NIDENT 16 + +typedef struct { + unsigned char e_ident[EI_NIDENT]; + u16 e_type; + u16 e_machine; + u32 e_version; + void *e_entry; + u32 e_phoff; + u32 e_shoff; + u32 e_flags; + u16 e_ehsize; + u16 e_phentsize; + u16 e_phnum; + u16 e_shentsize; + u16 e_shnum; + u16 e_shtrndx; +} Elf32_Ehdr; + +typedef struct { + u32 p_type; + u32 p_offset; + void *p_vaddr; + void *p_paddr; + u32 p_filesz; + u32 p_memsz; + u32 p_flags; + u32 p_align; +} Elf32_Phdr; + +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 + +#endif + diff --git a/elfloader/hollywood.h b/elfloader/hollywood.h new file mode 100644 index 0000000..ce8e908 --- /dev/null +++ b/elfloader/hollywood.h @@ -0,0 +1,31 @@ +/* + mini - a Free Software replacement for the Nintendo/BroadOn IOS. + + ELF loader: Hollywood register definitions + +Copyright (C) 2008, 2009 Hector Martin "marcan" + +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, version 2. + +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 + +*/ +#ifndef __HOLLYWOOD_H__ +#define __HOLLYWOOD_H__ + +#define HW_REG_BASE 0xd800000 +#define HW_TIMER (HW_REG_BASE + 0x010) +#define HW_MEMMIRR (HW_REG_BASE + 0x060) +#define HW_BOOT0 (HW_REG_BASE + 0x18c) + +#endif + diff --git a/elfloader/start.S b/elfloader/start.S new file mode 100644 index 0000000..8b9a7d6 --- /dev/null +++ b/elfloader/start.S @@ -0,0 +1,113 @@ +/* + mini - a Free Software replacement for the Nintendo/BroadOn IOS. + + ELF loader: system startup + +Copyright (C) 2008, 2009 Hector Martin "marcan" + +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, version 2. + +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 + +*/ +.arm + +.extern _main +.extern __got_start +.extern __got_end +.extern __bss_start +.extern __bss_end +.extern __stack_addr +.extern delay +.globl _start +.globl debug_output + +.section .init + +_start: + @ Get real address of _start + sub r4, pc, #8 + @ Subtract offset to get the address that we were loaded at + ldr r0, =_start + sub r4, r4, r0 + @ Output 0x42 to the debug port + mov r0, #0x42 + bl debug_output + + @ Set up a stack + ldr sp, =__stack_addr + add sp, r4 + + @ Output 0x43 to the debug port + mov r0, #0x43 + bl debug_output + + @ relocate the GOT entries + ldr r1, =__got_start + add r1, r4 + ldr r2, =__got_end + add r2, r4 +got_loop: + @ check for the end + cmp r1, r2 + beq done_got + @ read the GOT entry + ldr r3, [r1] + @ add our base address + add r3, r4 + str r3, [r1] + @ move on + add r1, r1, #4 + b got_loop + +done_got: + @ clear BSS + ldr r1, =__bss_start + add r1, r4 + ldr r2, =__bss_end + add r2, r4 + mov r3, #0 +bss_loop: + @ check for the end + cmp r1, r2 + beq done_bss + @ clear the word and move on + str r3, [r1] + add r1, r1, #4 + b bss_loop + +done_bss: + mov r0, #0x44 + bl debug_output + @ take the plunge + mov r0, r4 + bl _main + @ _main returned! Go to whatever address it returned... + mov r1, r0 + mov r0, r4 + mov pc, r1 + +.pool + +debug_output: + @ load address of port + mov r3, #0xd800000 + @ load old value + ldr r2, [r3, #0xe0] + @ clear debug byte + bic r2, r2, #0xFF0000 + @ insert new value + and r0, r0, #0xFF + orr r2, r2, r0, LSL #16 + @ store back + str r2, [r3, #0xe0] + mov pc, lr diff --git a/elfloader/start.h b/elfloader/start.h new file mode 100644 index 0000000..a3458b1 --- /dev/null +++ b/elfloader/start.h @@ -0,0 +1,30 @@ +/* + mini - a Free Software replacement for the Nintendo/BroadOn IOS. + + ELF loader: system startup + +Copyright (C) 2008, 2009 Hector Martin "marcan" + +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, version 2. + +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 + +*/ +#ifndef __START_H__ +#define __START_H__ + +#include "types.h" + +void debug_output(u8 byte); + +#endif + diff --git a/elfloader/string.c b/elfloader/string.c new file mode 120000 index 0000000..5ea3579 --- /dev/null +++ b/elfloader/string.c @@ -0,0 +1 @@ +../string.c \ No newline at end of file diff --git a/elfloader/string.h b/elfloader/string.h new file mode 120000 index 0000000..5904b45 --- /dev/null +++ b/elfloader/string.h @@ -0,0 +1 @@ +../string.h \ No newline at end of file diff --git a/elfloader/stub.c b/elfloader/stub.c new file mode 100644 index 0000000..4a849d8 --- /dev/null +++ b/elfloader/stub.c @@ -0,0 +1,86 @@ +/* + mini - a Free Software replacement for the Nintendo/BroadOn IOS. + + ELF loader + +Copyright (C) 2008, 2009 Hector Martin "marcan" + +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, version 2. + +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 "types.h" +#include "utils.h" +#include "start.h" +#include "hollywood.h" +#include "string.h" +#include "elf.h" + +typedef struct { + u32 hdrsize; + u32 loadersize; + u32 elfsize; + u32 argument; +} ioshdr; + +void *loadelf(const u8 *elf) { + if(memcmp("\x7F" "ELF\x01\x02\x01",elf,7)) { + panic(0xE3); + } + + Elf32_Ehdr *ehdr = (Elf32_Ehdr*)elf; + if(ehdr->e_phoff == 0) { + panic(0xE4); + } + int count = ehdr->e_phnum; + Elf32_Phdr *phdr = (Elf32_Phdr*)(elf + ehdr->e_phoff); + while(count--) + { + if(phdr->p_type == PT_LOAD) { + const void *src = elf + phdr->p_offset; + memcpy(phdr->p_paddr, src, phdr->p_filesz); + } + phdr++; + } + return ehdr->e_entry; +} + +static inline void disable_boot0() +{ + set32(HW_BOOT0, 0x1000); +} + +static inline void mem_setswap() +{ + set32(HW_MEMMIRR, 0x20); +} + +void *_main(void *base) +{ + ioshdr *hdr = (ioshdr*)base; + u8 *elf; + void *entry; + + elf = (u8*) base; + elf += hdr->hdrsize + hdr->loadersize; + + debug_output(0xF1); + mem_setswap(1); + disable_boot0(1); + + entry = loadelf(elf); + debug_output(0xC1); + return entry; + +} + diff --git a/elfloader/stub.ld b/elfloader/stub.ld new file mode 100644 index 0000000..11d8b4f --- /dev/null +++ b/elfloader/stub.ld @@ -0,0 +1,117 @@ +/* + elfloader - a Free Software replacement for the Nintendo/BroadOn IOS. + +Copyright (C) 2008, 2009 Hector Martin "marcan" + +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, version 2. + +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 + +*/ +OUTPUT_FORMAT("elf32-bigarm") +OUTPUT_ARCH(arm) +EXTERN(_start) +ENTRY(_start) + +__base_addr = 0; + +SECTIONS +{ + . = __base_addr; + .header : + { + __header = .; + /* Entry point (offset) */ + LONG(__code_start); + /* Loader size */ + LONG(__loader_size); + /* ELF size */ + LONG(0); + /* Boot argument? */ + LONG(0); + . = ALIGN(16); + } + + __code_start = .; + + .init : + { + *(.init) + . = ALIGN(4); + } + + .got : + { + __got_start = .; + *(.got.*) + *(.got) + . = ALIGN(4); + __got_end = . ; + } + + .text : + { + *(.text.*) + *(.gnu.warning) + *(.gnu.linkonce.t*) + *(.glue_7) + *(.glue_7t) + . = ALIGN(4); + } + + __text_end = . ; + + .rodata : + { + *(.rodata) + *all.rodata*(*) + *(.roda) + *(.rodata.*) + *(.gnu.linkonce.r*) + . = ALIGN(4); + } + + .data : + { + *(.data) + *(.data.*) + *(.gnu.linkonce.d*) + . = ALIGN(4); + } + + .bss : + { + __bss_start = . ; + *(.dynbss) + *(.gnu.linkonce.b*) + *(.bss*) + *(.sbss*) + *(COMMON) + . = ALIGN(32); + __bss_end = . ; + } + +} + +__stack_end = (__bss_end); +__stack_addr = (__bss_end + 0x100); + +__end = __stack_addr ; +__loader_size = __end - __code_start; + +PROVIDE (__stack_end = __stack_end); +PROVIDE (__stack_addr = __stack_addr); +PROVIDE (__got_start = __got_start); +PROVIDE (__got_end = __got_end); +PROVIDE (__bss_start = __bss_start); +PROVIDE (__bss_end = __bss_end); + diff --git a/elfloader/types.h b/elfloader/types.h new file mode 100644 index 0000000..837d854 --- /dev/null +++ b/elfloader/types.h @@ -0,0 +1,50 @@ +/* + mini - a Free Software replacement for the Nintendo/BroadOn IOS. + + ELF loader: types + +Copyright (C) 2008, 2009 Hector Martin "marcan" + +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, version 2. + +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 + +*/ +#ifndef __TYPES_H__ +#define __TYPES_H__ + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +typedef signed char s8; +typedef signed short s16; +typedef signed int s32; +typedef signed long long s64; + +typedef volatile unsigned char vu8; +typedef volatile unsigned short vu16; +typedef volatile unsigned int vu32; +typedef volatile unsigned long long vu64; + +typedef volatile signed char vs8; +typedef volatile signed short vs16; +typedef volatile signed int vs32; +typedef volatile signed long long vs64; + +typedef s32 size_t; + +#define NULL ((void *)0) + +#endif + diff --git a/elfloader/utils.c b/elfloader/utils.c new file mode 100644 index 0000000..df3426b --- /dev/null +++ b/elfloader/utils.c @@ -0,0 +1,45 @@ +/* + mini - a Free Software replacement for the Nintendo/BroadOn IOS. + + ELF loader: random utilities + +Copyright (C) 2008, 2009 Hector Martin "marcan" + +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, version 2. + +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 "types.h" +#include "utils.h" +#include "hollywood.h" +#include "start.h" + +void udelay(u32 d) +{ + // should be good to max .2% error + u32 ticks = d * 19 / 10; + + write32(HW_TIMER, 0); + while(read32(HW_TIMER) < ticks); +} + +void panic(u8 v) +{ + while(1) { + debug_output(v); + udelay(500000); + debug_output(0); + udelay(500000); + } +} + diff --git a/elfloader/utils.h b/elfloader/utils.h new file mode 100644 index 0000000..698c95b --- /dev/null +++ b/elfloader/utils.h @@ -0,0 +1,188 @@ +/* + mini - a Free Software replacement for the Nintendo/BroadOn IOS. + + ELF loader: random utilities + +Copyright (C) 2008, 2009 Hector Martin "marcan" + +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, version 2. + +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 + +*/ +#ifndef __UTILS_H__ +#define __UTILS_H__ + +static inline u32 read32(u32 addr) +{ + u32 data; + __asm__ volatile ("ldr\t%0, [%1]" : "=r" (data) : "r" (addr)); + return data; +} + +static inline void write32(u32 addr, u32 data) +{ + __asm__ volatile ("str\t%0, [%1]" : : "r" (data), "r" (addr)); +} + +static inline u32 set32(u32 addr, u32 set) +{ + u32 data; + __asm__ volatile ( + "ldr\t%0, [%1]\n" + "\torr\t%0, %2\n" + "\tstr\t%0, [%1]" + : "=&r" (data) + : "r" (addr), "r" (set) + ); + return data; +} + +static inline u32 clear32(u32 addr, u32 clear) +{ + u32 data; + __asm__ volatile ( + "ldr\t%0, [%1]\n" + "\tbic\t%0, %2\n" + "\tstr\t%0, [%1]" + : "=&r" (data) + : "r" (addr), "r" (clear) + ); + return data; +} + + +static inline u32 mask32(u32 addr, u32 clear, u32 set) +{ + u32 data; + __asm__ volatile ( + "ldr\t%0, [%1]\n" + "\tbic\t%0, %3\n" + "\torr\t%0, %2\n" + "\tstr\t%0, [%1]" + : "=&r" (data) + : "r" (addr), "r" (set), "r" (clear) + ); + return data; +} + +static inline u16 read16(u32 addr) +{ + u32 data; + __asm__ volatile ("ldrh\t%0, [%1]" : "=r" (data) : "r" (addr)); + return data; +} + +static inline void write16(u32 addr, u16 data) +{ + __asm__ volatile ("strh\t%0, [%1]" : : "r" (data), "r" (addr)); +} + +static inline u16 set16(u32 addr, u16 set) +{ + u16 data; + __asm__ volatile ( + "ldrh\t%0, [%1]\n" + "\torr\t%0, %2\n" + "\tstrh\t%0, [%1]" + : "=&r" (data) + : "r" (addr), "r" (set) + ); + return data; +} + +static inline u16 clear16(u32 addr, u16 clear) +{ + u16 data; + __asm__ volatile ( + "ldrh\t%0, [%1]\n" + "\tbic\t%0, %2\n" + "\tstrh\t%0, [%1]" + : "=&r" (data) + : "r" (addr), "r" (clear) + ); + return data; +} + + +static inline u16 mask16(u32 addr, u16 clear, u16 set) +{ + u16 data; + __asm__ volatile ( + "ldrh\t%0, [%1]\n" + "\tbic\t%0, %3\n" + "\torr\t%0, %2\n" + "\tstrh\t%0, [%1]" + : "=&r" (data) + : "r" (addr), "r" (set), "r" (clear) + ); + return data; +} + +static inline u8 read8(u32 addr) +{ + u32 data; + __asm__ volatile ("ldrb\t%0, [%1]" : "=r" (data) : "r" (addr)); + return data; +} + +static inline void write8(u32 addr, u8 data) +{ + __asm__ volatile ("strb\t%0, [%1]" : : "r" (data), "r" (addr)); +} + +static inline u8 set8(u32 addr, u8 set) +{ + u8 data; + __asm__ volatile ( + "ldrb\t%0, [%1]\n" + "\torr\t%0, %2\n" + "\tstrb\t%0, [%1]" + : "=&r" (data) + : "r" (addr), "r" (set) + ); + return data; +} + +static inline u8 clear8(u32 addr, u8 clear) +{ + u8 data; + __asm__ volatile ( + "ldrb\t%0, [%1]\n" + "\tbic\t%0, %2\n" + "\tstrb\t%0, [%1]" + : "=&r" (data) + : "r" (addr), "r" (clear) + ); + return data; +} + + +static inline u8 mask8(u32 addr, u8 clear, u8 set) +{ + u8 data; + __asm__ volatile ( + "ldrb\t%0, [%1]\n" + "\tbic\t%0, %3\n" + "\torr\t%0, %2\n" + "\tstrb\t%0, [%1]" + : "=&r" (data) + : "r" (addr), "r" (set), "r" (clear) + ); + return data; +} + +void udelay(u32 d); +void panic(u8 v); + +#endif + diff --git a/makebin.py b/makebin.py new file mode 100644 index 0000000..ce048a4 --- /dev/null +++ b/makebin.py @@ -0,0 +1,49 @@ +#!/bin/env python + +import sys, os, struct, sha + +loaderfile = sys.argv[1] +elffile = sys.argv[2] +outfile = sys.argv[3] + +data = open(loaderfile,"rb").read() + +hdrlen, loaderlen, elflen, arg = struct.unpack(">IIII",data[:16]) + +if hdrlen < 0x10: + print "ERROR: header length is 0x%x, expected at least 0x10"%hdrlen + sys.exit(1) + +loaderoff = hdrlen +elfoff = loaderoff + loaderlen +elfend = elfoff + elflen + +hdr = data[:hdrlen] +loader = data[loaderoff:elfoff] + +elf = open(elffile,"rb").read() + +if elflen > 0: + print "WARNING: loader already contains ELF, will replace" + +elflen = len(elf) + +if loaderlen < len(loader): + print "ERROR: loader is larger than its reported length" + sys.exit(1) + +if loaderlen > len(loader): + print "Padding loader with 0x%x zeroes"%(loaderlen-len(loader)) + loader += "\x00"*(loaderlen-len(loader)) + +newdata = struct.pack(">IIII", hdrlen, loaderlen, elflen, 0) + hdr[16:] +newdata += loader +newdata += elf + +print "Header: 0x%x bytes"%(hdrlen) +print "Loader: 0x%x bytes"%(loaderlen) +print "ELF: 0x%x bytes"%(elflen) + +f = open(outfile,"wb") +f.write(newdata) +f.close()