*.o
.version
-
-rzd?-?.?.bin
-rzd?.data
-
-rzd??.elf
-rzd??.slot
-
-title.bin
-
-zero16k
-FAILURE
endif
-targets := rzde-3.2.bin rzde-3.3.bin rzde-3.4.bin
-targets += rzdj-3.2.bin rzdj-3.3.bin rzdj-3.4.bin
-targets += rzdp-3.2.bin rzdp-3.3.bin rzdp-3.4.bin
-targets-short := rzde rzdj rzdp
-
-objs := twilight.o
-
-ppms := $(targets-short:%=%-icon.ppm) generic-banner.ppm
-assets := title.bin $(ppms)
-
-loader := loader/loader.bin
-
-
-titleid = $(shell perl titleid.pl $(1))
-
-
-# System menu 3.3 checks for the exploit, when a) you copy a save from SD,
-# and b) when the menu starts up; but for a) it only looks at the first
-# zeldaTp.dat file, and for b) it allows any file of non-aligned length.
-#
-# System menu 3.4 only looks at the last file in the wad when installing.
-#
-# System menu 4.0 finally avoids such silly bugs.
-
-define twintig
- D=$(call titleid,$(1)); \
- $(TOOLS)/twintig $$D $@ toc-$1
-endef
-
-
-all: $(targets)
-
-$(filter %-3.2.bin,$(targets)): %-3.2.bin: %.data
-$(filter %-3.3.bin,$(targets)): %-3.3.bin: %.data zero16k
-$(filter %-3.4.bin,$(targets)): %-3.4.bin: %.data FAILURE
-$(targets): %.bin: toc-% $(assets)
- @echo " TWINTIG $@"
- $(Q)$(call twintig,$*)
-
-saves := $(targets-short:%=%.data)
-
-rzde.data: rzde0.slot rzde2.slot
-rzdp.data: rzdp0.slot
-rzdj.data: rzdj0.slot
-$(saves): $(loader)
- @echo " ZELDAPACK $@"
- $(Q)./pack.sh $@ $(filter %.slot,$^)
- $(Q)$(TOOLS)/zelda-cksum $@
- $(Q)cat $(loader) >> $@
- $(Q)printf '\0' >> $@
-
-slots := rzde0.slot rzde2.slot rzdj0.slot rzdp0.slot
-
-$(slots): %.slot: %.elf
- @echo " OBJCOPY $@"
- $(Q)$(OBJCOPY) -Obinary $< $@
-
-elfs := $(slots:.slot=.elf)
-
-rzde0.elf: baddr := 0x8046a3e0+0
-rzde2.elf: baddr := 0x804519e0+0x0a94
-rzdj0.elf: baddr := 0x8044f860+0
-rzdp0.elf: baddr := 0x804522e0+0
-$(elfs): %.elf: twilight.lds %.o $(objs)
- @echo " LINK $@"
- $(Q)$(LD) --defsym baddr=$(baddr) -T $^ -o $@
-
-exploit-objs := $(elfs:.elf=.o)
-
-$(exploit-objs): slot-name := Twilight Hack
-rzde0.o: slot-name := TwilightHack0
-rzde2.o: slot-name := TwilightHack2
-$(exploit-objs): %.o: start.S head.b
- @echo " ASSEMBLE $@"
- $(Q)$(CC) $(CFLAGS) -D NAME="$(slot-name)" -c $< -o $@
-
-%.o: %.c
- @echo " COMPILE $@"
- $(Q)$(CC) $(CFLAGS) -c $< -o $@
-
-title.bin: .version
- @echo " TITLEBIN $@"
- $(Q)perl make-title-bin.pl > $@
+all:
.version: FORCE
$(Q)./describe.sh > .$@-tmp
$(Q)cmp -s $@ .$@-tmp || cp .$@-tmp $@
$(Q)rm .$@-tmp
-$(ppms): %.ppm: %.png
- @echo " PPM $@"
- $(Q)convert $< $@
-
-zero16k:
- $(Q)dd if=/dev/zero bs=16384 count=1 2>/dev/null > $@
-
-FAILURE:
- $(Q)echo FAILURE > $@
-
-$(loader): FORCE .version
+all: FORCE .version
$(Q)$(MAKE) -C loader
+ $(Q)$(MAKE) -C twilight
+ $(Q)$(MAKE) -C lego
FORCE:
clean:
- -rm -f $(targets) $(saves) $(elfs) $(exploit-objs) $(objs) $(slots)
- -rm -f .version title.bin zero16k FAILURE
+ -rm -f .version
$(MAKE) -C loader clean
+ $(MAKE) -C twilight clean
+ $(MAKE) -C lego clean
--- /dev/null
+rli?.bin
+FILE_V28
+exploit.bin
+exploit.elf
+title.bin
--- /dev/null
+# Copyright 2008-2009 Segher Boessenkool <segher@kernel.crashing.org>
+# This code is licensed to you under the terms of the GNU GPL, version 2;
+# see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+
+
+# Configuration:
+
+# What toolchain prefix should we use
+CROSS ?= broadway-
+
+# Where are the tools (http://git.infradead.org/users/segher/wii.git)
+TOOLS ?= $(HOME)/wii/segher
+
+# End of configuration.
+
+
+
+# Set CC, LD, OBJCOPY based on CROSS, unless they are set already
+
+ifeq ($(origin CC), default)
+ CC := $(CROSS)gcc -m32
+endif
+ifeq ($(origin LD), default)
+ LD := $(CROSS)ld
+endif
+OBJCOPY ?= $(CROSS)objcopy
+
+
+# The compiler flags we need.
+
+CFLAGS := -Wall -W -Os -ffreestanding -mno-eabi -mno-sdata -mcpu=750
+
+
+# Build with "V=1" to see the commands executed; be quiet otherwise.
+
+ifeq ($(V),1)
+ Q :=
+else
+ Q := @
+ MAKEFLAGS += --no-print-directory
+endif
+
+
+targets := rlie.bin rlij.bin rlip.bin
+
+ppms := $(targets:%.bin=%-icon.ppm) rli-banner.ppm
+assets := title.bin $(ppms)
+
+loader := ../loader/loader.bin
+
+
+titleid = $(shell perl titleid.pl $(1))
+
+
+define twintig
+ D=$(call titleid,$(1)); \
+ $(TOOLS)/twintig $$D $@ toc-$1
+endef
+
+
+all: $(targets)
+
+$(targets): %.bin: toc-% FILE_V28 $(assets)
+ @echo " TWINTIG $@"
+ $(Q)$(call twintig,$*)
+
+FILE_V28: head.bin exploit.bin $(loader)
+ @echo " LEGOSTACK $@"
+ $(Q)./pack.sh $@ $^
+ $(Q)$(TOOLS)/lego-cksum $@ 32688
+
+head.bin: head.elf
+ @echo " OBJCOPY $@"
+ $(Q)$(OBJCOPY) -Obinary $< $@
+
+exploit.bin: exploit.elf
+ @echo " OBJCOPY $@"
+ $(Q)$(OBJCOPY) -Obinary $< $@
+
+exploit.elf: baddr := 0x903b0780
+exploit.elf: lego.lds exploit.o
+ @echo " LINK $@"
+ $(Q)$(LD) --defsym baddr=$(baddr) -T $^ -o $@
+
+head.elf: head.lds head.o
+ @echo " LINK $@"
+ $(Q)$(LD) -T $^ -o $@
+
+exploit.o: exploit.s
+ @echo " ASSEMBLE $@"
+ $(Q)$(CC) $(CFLAGS) -c $< -o $@
+
+head.o: head.s head.b
+ @echo " ASSEMBLE $@"
+ $(Q)$(CC) $(CFLAGS) -c $< -o $@
+
+title.bin: ../.version
+ @echo " TITLEBIN $@"
+ $(Q)perl make-title-bin.pl > $@
+
+../.version: FORCE
+ $(Q)$(MAKE) -C .. .version
+
+$(ppms): %.ppm: %.png
+ @echo " PPM $@"
+ $(Q)convert $< $@
+
+$(loader): FORCE
+ $(Q)$(MAKE) -C ../loader
+
+FORCE:
+
+clean:
+ -rm -f $(targets) FILE_V28
+ -rm -f exploit.bin exploit.elf exploit.o
+ -rm -f head.bin head.elf head.o
+ -rm -f title.bin
--- /dev/null
+Extremely short instructions: put this savegame on your Wii (if you have
+one on there already that you want to keep, back it up first!), start the
+game, walk to the "art room" (find some walkthrough on the intertubes if
+you cannot find it), look at the second character, enjoy!
+
+Kudos to "roto" for finding the original buffer overflow, and many thanks
+for doing lots of testing!
--- /dev/null
+# Copyright 2008-2009 Segher Boessenkool <segher@kernel.crashing.org>
+# This code is licensed to you under the terms of the GNU GPL, version 2;
+# see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+
+ .section .start,"ax"
+
+start:
+ # Set up a stack frame.
+ lis 1,0x8080 ; li 0,0 ; stwu 0,-64(1)
+
+ # Stop audio and video.
+ lis 0,audio_stop@h ; ori 0,0,audio_stop@l ; mtctr 0 ; bctrl
+ lis 0,video_stop@h ; ori 0,0,video_stop@l ; mtctr 0 ; bctrl
+
+ # Move code into place; a generous 32kB, starting at 64kB in
+ # the save file.
+
+ lis 3,main@h ; ori 3,3,main@l ; addi 5,3,-4
+ lis 4,0x806c ; lwz 4,0xdc48-0x10000(4) ; addi 4,4,-4
+ addis 4,4,1 ; addi 4,4,end-start
+ li 0,0x2000 ; mtctr 0
+0: lwzu 0,4(4) ; stwu 0,4(5) ; bdnz 0b
+
+ # Sync caches on it.
+ li 0,0x0400 ; mtctr 0 ; mr 5,3
+0: dcbst 0,5 ; sync ; icbi 0,5 ; addi 5,5,0x20 ; bdnz 0b
+ sync ; isync
+
+ # Go for it!
+ mtctr 3 ; bctr
+end:
--- /dev/null
+/* Copyright 2008-2009 Segher Boessenkool <segher@kernel.crashing.org>
+ This code is licensed to you under the terms of the GNU GPL, version 2;
+ see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt */
+
+OUTPUT_FORMAT("elf32-powerpc")
+OUTPUT_ARCH(powerpc:common)
+
+SECTIONS {
+/* audio_stop = 0x800a3e80;
+ video_stop = 0x800b2120;
+
+ main = 0x90000020; */
+
+ .head 0x805a909c :
+ {
+ head.o(.start)
+ *(.text)
+ *(.rodata .rodata.*)
+ *(.data)
+ *(.bss)
+ }
+}
--- /dev/null
+ .section ".start", "ax"
+
+ # FIXME
+ bptr = 0x806bdc48
+
+0:
+ .incbin "head.b"
+
+ # Smack the stack.
+ .long 0x11111111, 0x11111111, 0x11111111, 0x11111111
+ .long 0x11111111, 0x11111111, 0x11111111, 0x11111111
+ .long 0x11111111, 0x11111111, 0x11111111, 0x11111111
+ .long 0x11111111, 0x11111111, 0x11111111, 0x11111111
+ .long 0x11111111, 0x11111111, 0x11111111, 0x11111111
+ .long 0x11111111, 0x11111111, 0x11111111, 0x11111111
+ .long 0x11111111, 0x11111111, 0x11111111, 0x11111111
+ .long 0x11111111, 0x11111111, 0x11111111, 0x11111111
+ .long 0x11111111
+
+ # Return address; namely...
+ .long 0x805b0f30, 0x11111111, 0x11111111, 0x11111111
+
+ # Here.
+ lis 3,bptr@ha ; lwz 3,bptr@l(3) ; addis 3,3,1 ; mtctr 3 ; bctr
+
+ .fill 0x10000 - (. - 0b)
--- /dev/null
+/* Copyright 2008-2009 Segher Boessenkool <segher@kernel.crashing.org>
+ This code is licensed to you under the terms of the GNU GPL, version 2;
+ see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt */
+
+OUTPUT_FORMAT("elf32-powerpc")
+OUTPUT_ARCH(powerpc:common)
+
+SECTIONS {
+ audio_stop = 0x800a3e80;
+ video_stop = 0x800b2120;
+
+ main = 0x90000020;
+
+ .twilight baddr :
+ {
+ rli*.o(.start)
+ *(.text)
+ *(.rodata .rodata.*)
+ *(.data)
+ *(.bss)
+ }
+}
--- /dev/null
+#!/usr/bin/perl
+sub printline {
+ my $x = shift;
+ chomp $x;
+ $x .= "\0" x 32;
+ $x = substr $x, 0, 32;
+ $x =~ s/(.)/\0$1/g;
+
+ print $x;
+}
+
+$name = "Indiana Pwns, by Team Twiizers";
+$version = `cat ../.version`;
+
+printline $name;
+printline $version;
--- /dev/null
+#!/bin/bash
+TARGET=$1; shift
+cat $* /dev/zero | dd bs=1024 count=128 2>/dev/null > $TARGET
--- /dev/null
+#!/usr/bin/perl
+print "00010000", map { sprintf "%02x", ord uc } split //, $ARGV[0];
--- /dev/null
+title.bin
+rli-banner.ppm
+rlie-icon.ppm
+FILE_V28 FILE_V28
--- /dev/null
+title.bin
+rli-banner.ppm
+rlij-icon.ppm
+FILE_V28 FILE_V28
--- /dev/null
+title.bin
+rli-banner.ppm
+rlip-icon.ppm
+FILE_V28 FILE_V28
#include "loader.h"
-u8 *code_buffer = (u8 *)0x90100000;
-u8 *trampoline_buffer = (u8 *)0x80001800;
+static u8 *const code_buffer = (u8 *)0x90100000;
+static u8 *const trampoline_buffer = (u8 *)0x80001800;
static void dsp_reset(void)
{
video_init();
usbgecko_init();
- printf("Twilight Hack %s\n", version);
+ printf("savezelda %s\n", version);
printf("\n");
printf("Copyright 2008,2009 Segher Boessenkool\n");
printf("Copyright 2008 Haxx Enterprises\n");
+++ /dev/null
-#!/usr/bin/perl
-sub printline {
- my $x = shift;
- chomp $x;
- $x .= "\0" x 32;
- $x = substr $x, 0, 32;
- $x =~ s/(.)/\0$1/g;
-
- print $x;
-}
-
-$name = "Twilight Hack by Team Twiizers";
-$version = `cat .version`;
-
-printline $name;
-printline $version;
+++ /dev/null
-#!/bin/bash
-out=$1; shift
-dd if=/dev/zero bs=1 count=$((0x4000)) of=$out 2>/dev/null
-start=0
-for save in $@; do
- dd if=$save of=$out bs=1 seek=$start conv=notrunc 2>/dev/null
- start=$((start+0xa94))
-done
+++ /dev/null
-// Copyright 2008-2009 Segher Boessenkool <segher@kernel.crashing.org>
-// This code is licensed to you under the terms of the GNU GPL, version 2;
-// see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
-
-#define XSTR(x) #x
-#define ISTR(x) XSTR(x)
-
- .section .start,"ax"
-
- // Uninteresting stuff.
- .incbin "head.b"
-
- // "Link". This is displayed on the load menu, so make it nice.
-0: .ascii ISTR(NAME)
- .fill 17 - (. - 0b)
-
- // "Epona". Hungry horse eats the stack.
- .fill 0xe8,1,'3'
-
- // The return address on the stack.
- .long start
-
- // Align things properly -- there's code after this.
- .fill 7,1,'S'
- .balign 4,0
-
-start:
- // Set up a stack frame.
- lis 1,0x8080 ; li 0,0 ; stwu 0,-64(1)
-
- // Pass the address we are called from, to determine region.
- mflr 3
-
- // Go for it!
- b main
+++ /dev/null
-#!/usr/bin/perl
-print "00010000", map { sprintf "%02x", ord uc } split //, $ARGV[0];
+++ /dev/null
-title.bin
-generic-banner.ppm
-rzde-icon.ppm
-rzde.data zeldaTp.dat
+++ /dev/null
-title.bin
-generic-banner.ppm
-rzde-icon.ppm
-zero16k zeldaTp.dat
-rzde.data zeldaTp.dat
+++ /dev/null
-title.bin
-generic-banner.ppm
-rzde-icon.ppm
-rzde.data zeldaTp.dat
-FAILURE FAILURE
+++ /dev/null
-title.bin
-generic-banner.ppm
-rzdj-icon.ppm
-rzdj.data zeldaTp.dat
+++ /dev/null
-title.bin
-generic-banner.ppm
-rzdj-icon.ppm
-zero16k zeldaTp.dat
-rzdj.data zeldaTp.dat
+++ /dev/null
-title.bin
-generic-banner.ppm
-rzdj-icon.ppm
-rzdj.data zeldaTp.dat
-FAILURE FAILURE
+++ /dev/null
-title.bin
-generic-banner.ppm
-rzdp-icon.ppm
-rzdp.data zeldaTp.dat
+++ /dev/null
-title.bin
-generic-banner.ppm
-rzdp-icon.ppm
-zero16k zeldaTp.dat
-rzdp.data zeldaTp.dat
+++ /dev/null
-title.bin
-generic-banner.ppm
-rzdp-icon.ppm
-rzdp.data zeldaTp.dat
-FAILURE FAILURE
+++ /dev/null
-// Copyright 2008-2009 Segher Boessenkool <segher@kernel.crashing.org>
-// This code is licensed to you under the terms of the GNU GPL, version 2;
-// see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
-
-#undef DEBUG_GECKO
-#undef DEBUG_BLINK
-
-typedef unsigned int u32;
-typedef unsigned char u8;
-
-int nand_open_E0(const char *path, void *buf, u32 mode);
-int nand_open_E2(const char *path, void *buf, u32 mode);
-int nand_open_J0(const char *path, void *buf, u32 mode);
-int nand_open_P0(const char *path, void *buf, u32 mode);
-
-int nand_read_E0(void *buf, void *dest, u32 len);
-int nand_read_E2(void *buf, void *dest, u32 len);
-int nand_read_J0(void *buf, void *dest, u32 len);
-int nand_read_P0(void *buf, void *dest, u32 len);
-
-void audio_stop_E0(void);
-void audio_stop_E2(void);
-void audio_stop_J0(void);
-void audio_stop_P0(void);
-
-void graphics_stop_E0(void);
-void graphics_stop_E2(void);
-void graphics_stop_J0(void);
-void graphics_stop_P0(void);
-
-static u8 nand_buf[0x100] __attribute__ ((aligned(0x40)));
-
-#ifdef DEBUG_GECKO
-void gecko_print(void *, const char *);
-
-#define PRINT(x) gecko_print(0, x)
-#define HEX(x) hex(x)
-
-static void hex(u32 x)
-{
- u32 i;
- u32 digit;
- char s[10];
-
- for (i = 0; i < 8; i++) {
- digit = x >> 28;
- x <<= 4;
- s[i] = digit + '0' + (digit < 10 ? 0 : 'a' - 10 - '0');
- }
- s[8] = '\n';
- s[9] = 0;
- PRINT(s);
-}
-#else
-#define PRINT(x) do { } while (0)
-#define HEX(x) do { } while (0)
-#endif
-
-static void sync_cache(void *p, u32 n)
-{
- u32 start, end;
-
- start = (u32)p & ~31;
- end = ((u32)p + n + 31) & ~31;
- n = (end - start) >> 5;
-
- while (n--) {
- asm("dcbst 0,%0 ; icbi 0,%0" : : "b"(p));
- p += 32;
- }
- asm("sync ; isync");
-}
-
-static void sync_before_read(void *p, u32 n)
-{
- u32 start, end;
-
- start = (u32)p & ~31;
- end = ((u32)p + n + 31) & ~31;
- n = (end - start) >> 5;
-
- while (n--) {
- asm("dcbf 0,%0" : : "b"(p));
- p += 32;
- }
- asm("sync");
-}
-
-static void jump(void *p, u32 arg)
-{
- PRINT("taking the plunge...\n");
-
- asm("mr 3,%1 ; mtctr %0 ; bctrl" : : "r"(p), "r"(arg) : "r3");
-
- PRINT("whoops, payload returned to us\n");
-}
-
-#ifdef DEBUG_BLINK
-static u32 read32(u32 addr)
-{
- u32 x;
-
- asm volatile("lwz %0,0(%1) ; sync" : "=r"(x) : "b"(0xc0000000 | addr));
-
- return x;
-}
-
-static void write32(u32 addr, u32 x)
-{
- asm("stw %0,0(%1) ; eieio" : : "r"(x), "b"(0xc0000000 | addr));
-}
-
-static void blink(u32 colour)
-{
- u32 *fb = (u32 *)0xC0F00000;
- u32 i;
-
- // blink tray led
- write32(0x0d8000c0, read32(0x0d8000c0) ^ 0x20);
-
- for (i = 0; i < 640*576/2; i++)
- fb[i] = colour;
-}
-#else
-#define blink(x) do { } while(0)
-#endif
-
-void __attribute__ ((noreturn)) main(u32 baddr)
-{
- int ret, i, len;
- char *area;
- char *gameid = (char *)0x80000000;
- int (*nand_open)(const char *path, void *buf, u32 mode);
- int (*nand_read)(void *buf, void *dest, u32 len);
- void (*audio_stop)(void);
- void (*graphics_stop)(void);
-
- PRINT("Hello, Brave New World!\n");
-
- baddr -= 0x2c0;
-
- switch (gameid[3]) {
- case 'E':
- if ((baddr>>16) == 0x8045) {
- nand_open = nand_open_E2;
- nand_read = nand_read_E2;
- audio_stop = audio_stop_E2;
- graphics_stop = graphics_stop_E2;
- } else {
- nand_open = nand_open_E0;
- nand_read = nand_read_E0;
- audio_stop = audio_stop_E0;
- graphics_stop = graphics_stop_E0;
- }
- break;
- case 'P':
- nand_open = nand_open_P0;
- nand_read = nand_read_P0;
- audio_stop = audio_stop_P0;
- graphics_stop = graphics_stop_P0;
- break;
- case 'J':
- nand_open = nand_open_J0;
- nand_read = nand_read_J0;
- audio_stop = audio_stop_J0;
- graphics_stop = graphics_stop_J0;
- break;
- default:
- PRINT("unsupported game region\n");
- for (;;)
- ;
- }
-
- audio_stop();
- graphics_stop();
-
- blink(0x266a26c0); // maroon
-
- ret = nand_open("zeldaTp.dat", nand_buf, 1);
-
- blink(0x7140718a); // olive
-
- PRINT("nand open --> ");
- HEX(ret);
-
- area = (void *)0x90000020;
-
- // Skip past save game, to loader.bin
- ret = nand_read(nand_buf, area, 0x4000);
-
- len = 0;
- for (i = 0; i < 0x40; i++) {
- PRINT("reading bootloader page: ");
- HEX(i);
-
- blink(0x40804080 + i*0x02000200); // grey
-
- sync_before_read(area + 0x1000*i, 0x1000);
- ret = nand_read(nand_buf, area + 0x1000*i, 0x1000);
- len += ret;
-
- blink(0x552b5515 + i*0x02000200); // lime
-
- PRINT("--> ");
- HEX(ret);
- PRINT("\n");
- }
-
- for (i = 0; i < 0x100; i++)
- HEX(((u32 *)area)[i]);
-
- blink(0xc399c36a); // sky blue
-
- sync_cache(area, len);
- jump(area, 0x123);
-
- blink(0x4c544cff); // red
-
- PRINT("(shouldn't happen)\n");
- for (;;)
- ;
-}
+++ /dev/null
-/* Copyright 2008-2009 Segher Boessenkool <segher@kernel.crashing.org>
- This code is licensed to you under the terms of the GNU GPL, version 2;
- see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt */
-
-OUTPUT_FORMAT("elf32-powerpc")
-OUTPUT_ARCH(powerpc:common)
-
-SECTIONS {
- gecko_print = 0x802facf0;
-
- nand_open_E0 = 0x80371f50;
- nand_read_E0 = 0x80371710;
- audio_stop_E0 = 0x8034607c;
- graphics_stop_E0 = 0x8035c930;
-
- nand_open_E2 = 0x8035c988;
- nand_read_E2 = 0x8035c148;
- audio_stop_E2 = 0x80330a4c;
- graphics_stop_E2 = 0x80347368;
-
- nand_open_P0 = 0x8035cdb8;
- nand_read_P0 = 0x8035c578;
- audio_stop_P0 = 0x80330e7c;
- graphics_stop_P0 = 0x80347798;
-
- nand_open_J0 = 0x8035e440;
- nand_read_J0 = 0x8035dc00;
- audio_stop_J0 = 0x8033256c;
- graphics_stop_J0 = 0x80348e20;
-
- .twilight baddr :
- {
- rzd*.o(.start)
- *(.text)
- *(.rodata .rodata.*)
- *(.data)
- *(.bss)
- . = 0x0a94;
- }
-}
--- /dev/null
+rzd?-?.?.bin
+rzd?.data
+
+rzd??.elf
+rzd??.slot
+
+title.bin
+
+zero16k
+FAILURE
--- /dev/null
+# Copyright 2008-2009 Segher Boessenkool <segher@kernel.crashing.org>
+# This code is licensed to you under the terms of the GNU GPL, version 2;
+# see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+
+
+# Configuration:
+
+# What toolchain prefix should we use
+CROSS ?= broadway-
+
+# Where are the tools (http://git.infradead.org/users/segher/wii.git)
+TOOLS ?= $(HOME)/wii/segher
+
+# End of configuration.
+
+
+
+# Set CC, LD, OBJCOPY based on CROSS, unless they are set already
+
+ifeq ($(origin CC), default)
+ CC := $(CROSS)gcc -m32
+endif
+ifeq ($(origin LD), default)
+ LD := $(CROSS)ld
+endif
+OBJCOPY ?= $(CROSS)objcopy
+
+
+# The compiler flags we need.
+
+CFLAGS := -Wall -W -Os -ffreestanding -mno-eabi -mno-sdata -mcpu=750
+
+
+# Build with "V=1" to see the commands executed; be quiet otherwise.
+
+ifeq ($(V),1)
+ Q :=
+else
+ Q := @
+ MAKEFLAGS += --no-print-directory
+endif
+
+
+targets := rzde-3.2.bin rzde-3.3.bin rzde-3.4.bin
+targets += rzdj-3.2.bin rzdj-3.3.bin rzdj-3.4.bin
+targets += rzdp-3.2.bin rzdp-3.3.bin rzdp-3.4.bin
+targets-short := rzde rzdj rzdp
+
+objs := twilight.o
+
+ppms := $(targets-short:%=%-icon.ppm) generic-banner.ppm
+assets := title.bin $(ppms)
+
+loader := ../loader/loader.bin
+
+
+titleid = $(shell perl titleid.pl $(1))
+
+
+# System menu 3.3 checks for the exploit, when a) you copy a save from SD,
+# and b) when the menu starts up; but for a) it only looks at the first
+# zeldaTp.dat file, and for b) it allows any file of non-aligned length.
+#
+# System menu 3.4 only looks at the last file in the wad when installing.
+#
+# System menu 4.0 finally avoids such silly bugs.
+
+define twintig
+ D=$(call titleid,$(1)); \
+ $(TOOLS)/twintig $$D $@ toc-$1
+endef
+
+
+all: $(targets)
+
+$(filter %-3.2.bin,$(targets)): %-3.2.bin: %.data
+$(filter %-3.3.bin,$(targets)): %-3.3.bin: %.data zero16k
+$(filter %-3.4.bin,$(targets)): %-3.4.bin: %.data FAILURE
+$(targets): %.bin: toc-% $(assets)
+ @echo " TWINTIG $@"
+ $(Q)$(call twintig,$*)
+
+saves := $(targets-short:%=%.data)
+
+rzde.data: rzde0.slot rzde2.slot
+rzdp.data: rzdp0.slot
+rzdj.data: rzdj0.slot
+$(saves): $(loader)
+ @echo " ZELDAPACK $@"
+ $(Q)./pack.sh $@ $(filter %.slot,$^)
+ $(Q)$(TOOLS)/zelda-cksum $@
+ $(Q)cat $(loader) >> $@
+ $(Q)printf '\0' >> $@
+
+slots := rzde0.slot rzde2.slot rzdj0.slot rzdp0.slot
+
+$(slots): %.slot: %.elf
+ @echo " OBJCOPY $@"
+ $(Q)$(OBJCOPY) -Obinary $< $@
+
+elfs := $(slots:.slot=.elf)
+
+rzde0.elf: baddr := 0x8046a3e0+0
+rzde2.elf: baddr := 0x804519e0+0x0a94
+rzdj0.elf: baddr := 0x8044f860+0
+rzdp0.elf: baddr := 0x804522e0+0
+$(elfs): %.elf: twilight.lds %.o $(objs)
+ @echo " LINK $@"
+ $(Q)$(LD) --defsym baddr=$(baddr) -T $^ -o $@
+
+exploit-objs := $(elfs:.elf=.o)
+
+$(exploit-objs): slot-name := Twilight Hack
+rzde0.o: slot-name := TwilightHack0
+rzde2.o: slot-name := TwilightHack2
+$(exploit-objs): %.o: start.S head.b
+ @echo " ASSEMBLE $@"
+ $(Q)$(CC) $(CFLAGS) -D NAME="$(slot-name)" -c $< -o $@
+
+%.o: %.c
+ @echo " COMPILE $@"
+ $(Q)$(CC) $(CFLAGS) -c $< -o $@
+
+title.bin: ../.version
+ @echo " TITLEBIN $@"
+ $(Q)perl make-title-bin.pl > $@
+
+../.version: FORCE
+ $(Q)$(MAKE) -C .. .version
+
+$(ppms): %.ppm: %.png
+ @echo " PPM $@"
+ $(Q)convert $< $@
+
+zero16k:
+ $(Q)dd if=/dev/zero bs=16384 count=1 2>/dev/null > $@
+
+FAILURE:
+ $(Q)echo FAILURE > $@
+
+$(loader): FORCE
+ $(Q)$(MAKE) -C ../loader
+
+FORCE:
+
+clean:
+ -rm -f $(targets) $(saves) $(elfs) $(exploit-objs) $(objs) $(slots)
+ -rm -f title.bin zero16k FAILURE
--- /dev/null
+#!/usr/bin/perl
+sub printline {
+ my $x = shift;
+ chomp $x;
+ $x .= "\0" x 32;
+ $x = substr $x, 0, 32;
+ $x =~ s/(.)/\0$1/g;
+
+ print $x;
+}
+
+$name = "Twilight Hack by Team Twiizers";
+$version = `cat ../.version`;
+
+printline $name;
+printline $version;
--- /dev/null
+#!/bin/bash
+out=$1; shift
+dd if=/dev/zero bs=1 count=$((0x4000)) of=$out 2>/dev/null
+start=0
+for save in $@; do
+ dd if=$save of=$out bs=1 seek=$start conv=notrunc 2>/dev/null
+ start=$((start+0xa94))
+done
--- /dev/null
+// Copyright 2008-2009 Segher Boessenkool <segher@kernel.crashing.org>
+// This code is licensed to you under the terms of the GNU GPL, version 2;
+// see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+
+#define XSTR(x) #x
+#define ISTR(x) XSTR(x)
+
+ .section .start,"ax"
+
+ // Uninteresting stuff.
+ .incbin "head.b"
+
+ // "Link". This is displayed on the load menu, so make it nice.
+0: .ascii ISTR(NAME)
+ .fill 17 - (. - 0b)
+
+ // "Epona". Hungry horse eats the stack.
+ .fill 0xe8,1,'3'
+
+ // The return address on the stack.
+ .long start
+
+ // Align things properly -- there's code after this.
+ .fill 7,1,'S'
+ .balign 4,0
+
+start:
+ // Set up a stack frame.
+ lis 1,0x8080 ; li 0,0 ; stwu 0,-64(1)
+
+ // Pass the address we are called from, to determine region.
+ mflr 3
+
+ // Go for it!
+ b main
--- /dev/null
+#!/usr/bin/perl
+print "00010000", map { sprintf "%02x", ord uc } split //, $ARGV[0];
--- /dev/null
+title.bin
+generic-banner.ppm
+rzde-icon.ppm
+rzde.data zeldaTp.dat
--- /dev/null
+title.bin
+generic-banner.ppm
+rzde-icon.ppm
+zero16k zeldaTp.dat
+rzde.data zeldaTp.dat
--- /dev/null
+title.bin
+generic-banner.ppm
+rzde-icon.ppm
+rzde.data zeldaTp.dat
+FAILURE FAILURE
--- /dev/null
+title.bin
+generic-banner.ppm
+rzdj-icon.ppm
+rzdj.data zeldaTp.dat
--- /dev/null
+title.bin
+generic-banner.ppm
+rzdj-icon.ppm
+zero16k zeldaTp.dat
+rzdj.data zeldaTp.dat
--- /dev/null
+title.bin
+generic-banner.ppm
+rzdj-icon.ppm
+rzdj.data zeldaTp.dat
+FAILURE FAILURE
--- /dev/null
+title.bin
+generic-banner.ppm
+rzdp-icon.ppm
+rzdp.data zeldaTp.dat
--- /dev/null
+title.bin
+generic-banner.ppm
+rzdp-icon.ppm
+zero16k zeldaTp.dat
+rzdp.data zeldaTp.dat
--- /dev/null
+title.bin
+generic-banner.ppm
+rzdp-icon.ppm
+rzdp.data zeldaTp.dat
+FAILURE FAILURE
--- /dev/null
+// Copyright 2008-2009 Segher Boessenkool <segher@kernel.crashing.org>
+// This code is licensed to you under the terms of the GNU GPL, version 2;
+// see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+
+#undef DEBUG_GECKO
+#undef DEBUG_BLINK
+
+typedef unsigned int u32;
+typedef unsigned char u8;
+
+int nand_open_E0(const char *path, void *buf, u32 mode);
+int nand_open_E2(const char *path, void *buf, u32 mode);
+int nand_open_J0(const char *path, void *buf, u32 mode);
+int nand_open_P0(const char *path, void *buf, u32 mode);
+
+int nand_read_E0(void *buf, void *dest, u32 len);
+int nand_read_E2(void *buf, void *dest, u32 len);
+int nand_read_J0(void *buf, void *dest, u32 len);
+int nand_read_P0(void *buf, void *dest, u32 len);
+
+void audio_stop_E0(void);
+void audio_stop_E2(void);
+void audio_stop_J0(void);
+void audio_stop_P0(void);
+
+void graphics_stop_E0(void);
+void graphics_stop_E2(void);
+void graphics_stop_J0(void);
+void graphics_stop_P0(void);
+
+static u8 nand_buf[0x100] __attribute__ ((aligned(0x40)));
+
+#ifdef DEBUG_GECKO
+void gecko_print(void *, const char *);
+
+#define PRINT(x) gecko_print(0, x)
+#define HEX(x) hex(x)
+
+static void hex(u32 x)
+{
+ u32 i;
+ u32 digit;
+ char s[10];
+
+ for (i = 0; i < 8; i++) {
+ digit = x >> 28;
+ x <<= 4;
+ s[i] = digit + '0' + (digit < 10 ? 0 : 'a' - 10 - '0');
+ }
+ s[8] = '\n';
+ s[9] = 0;
+ PRINT(s);
+}
+#else
+#define PRINT(x) do { } while (0)
+#define HEX(x) do { } while (0)
+#endif
+
+static void sync_cache(void *p, u32 n)
+{
+ u32 start, end;
+
+ start = (u32)p & ~31;
+ end = ((u32)p + n + 31) & ~31;
+ n = (end - start) >> 5;
+
+ while (n--) {
+ asm("dcbst 0,%0 ; icbi 0,%0" : : "b"(p));
+ p += 32;
+ }
+ asm("sync ; isync");
+}
+
+static void sync_before_read(void *p, u32 n)
+{
+ u32 start, end;
+
+ start = (u32)p & ~31;
+ end = ((u32)p + n + 31) & ~31;
+ n = (end - start) >> 5;
+
+ while (n--) {
+ asm("dcbf 0,%0" : : "b"(p));
+ p += 32;
+ }
+ asm("sync");
+}
+
+static void jump(void *p, u32 arg)
+{
+ PRINT("taking the plunge...\n");
+
+ asm("mr 3,%1 ; mtctr %0 ; bctrl" : : "r"(p), "r"(arg) : "r3");
+
+ PRINT("whoops, payload returned to us\n");
+}
+
+#ifdef DEBUG_BLINK
+static u32 read32(u32 addr)
+{
+ u32 x;
+
+ asm volatile("lwz %0,0(%1) ; sync" : "=r"(x) : "b"(0xc0000000 | addr));
+
+ return x;
+}
+
+static void write32(u32 addr, u32 x)
+{
+ asm("stw %0,0(%1) ; eieio" : : "r"(x), "b"(0xc0000000 | addr));
+}
+
+static void blink(u32 colour)
+{
+ u32 *fb = (u32 *)0xC0F00000;
+ u32 i;
+
+ // blink tray led
+ write32(0x0d8000c0, read32(0x0d8000c0) ^ 0x20);
+
+ for (i = 0; i < 640*576/2; i++)
+ fb[i] = colour;
+}
+#else
+#define blink(x) do { } while(0)
+#endif
+
+void __attribute__ ((noreturn)) main(u32 baddr)
+{
+ int ret, i, len;
+ char *area;
+ char *gameid = (char *)0x80000000;
+ int (*nand_open)(const char *path, void *buf, u32 mode);
+ int (*nand_read)(void *buf, void *dest, u32 len);
+ void (*audio_stop)(void);
+ void (*graphics_stop)(void);
+
+ PRINT("Hello, Brave New World!\n");
+
+ baddr -= 0x2c0;
+
+ switch (gameid[3]) {
+ case 'E':
+ if ((baddr>>16) == 0x8045) {
+ nand_open = nand_open_E2;
+ nand_read = nand_read_E2;
+ audio_stop = audio_stop_E2;
+ graphics_stop = graphics_stop_E2;
+ } else {
+ nand_open = nand_open_E0;
+ nand_read = nand_read_E0;
+ audio_stop = audio_stop_E0;
+ graphics_stop = graphics_stop_E0;
+ }
+ break;
+ case 'P':
+ nand_open = nand_open_P0;
+ nand_read = nand_read_P0;
+ audio_stop = audio_stop_P0;
+ graphics_stop = graphics_stop_P0;
+ break;
+ case 'J':
+ nand_open = nand_open_J0;
+ nand_read = nand_read_J0;
+ audio_stop = audio_stop_J0;
+ graphics_stop = graphics_stop_J0;
+ break;
+ default:
+ PRINT("unsupported game region\n");
+ for (;;)
+ ;
+ }
+
+ audio_stop();
+ graphics_stop();
+
+ blink(0x266a26c0); // maroon
+
+ ret = nand_open("zeldaTp.dat", nand_buf, 1);
+
+ blink(0x7140718a); // olive
+
+ PRINT("nand open --> ");
+ HEX(ret);
+
+ area = (void *)0x90000020;
+
+ // Skip past save game, to loader.bin
+ ret = nand_read(nand_buf, area, 0x4000);
+
+ len = 0;
+ for (i = 0; i < 0x40; i++) {
+ PRINT("reading bootloader page: ");
+ HEX(i);
+
+ blink(0x40804080 + i*0x02000200); // grey
+
+ sync_before_read(area + 0x1000*i, 0x1000);
+ ret = nand_read(nand_buf, area + 0x1000*i, 0x1000);
+ len += ret;
+
+ blink(0x552b5515 + i*0x02000200); // lime
+
+ PRINT("--> ");
+ HEX(ret);
+ PRINT("\n");
+ }
+
+ for (i = 0; i < 0x100; i++)
+ HEX(((u32 *)area)[i]);
+
+ blink(0xc399c36a); // sky blue
+
+ sync_cache(area, len);
+ jump(area, 0x123);
+
+ blink(0x4c544cff); // red
+
+ PRINT("(shouldn't happen)\n");
+ for (;;)
+ ;
+}
--- /dev/null
+/* Copyright 2008-2009 Segher Boessenkool <segher@kernel.crashing.org>
+ This code is licensed to you under the terms of the GNU GPL, version 2;
+ see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt */
+
+OUTPUT_FORMAT("elf32-powerpc")
+OUTPUT_ARCH(powerpc:common)
+
+SECTIONS {
+ gecko_print = 0x802facf0;
+
+ nand_open_E0 = 0x80371f50;
+ nand_read_E0 = 0x80371710;
+ audio_stop_E0 = 0x8034607c;
+ graphics_stop_E0 = 0x8035c930;
+
+ nand_open_E2 = 0x8035c988;
+ nand_read_E2 = 0x8035c148;
+ audio_stop_E2 = 0x80330a4c;
+ graphics_stop_E2 = 0x80347368;
+
+ nand_open_P0 = 0x8035cdb8;
+ nand_read_P0 = 0x8035c578;
+ audio_stop_P0 = 0x80330e7c;
+ graphics_stop_P0 = 0x80347798;
+
+ nand_open_J0 = 0x8035e440;
+ nand_read_J0 = 0x8035dc00;
+ audio_stop_J0 = 0x8033256c;
+ graphics_stop_J0 = 0x80348e20;
+
+ .twilight baddr :
+ {
+ rzd*.o(.start)
+ *(.text)
+ *(.rodata .rodata.*)
+ *(.data)
+ *(.bss)
+ . = 0x0a94;
+ }
+}