commit 2fef6bd704004dbe8b54a25f7ef31c1eb518a01e Author: Maschell Date: Sun Dec 26 10:20:12 2021 +0100 first commit diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..d524b74 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,57 @@ +name: CI-Release + +on: + push: + branches: + - main + +jobs: + build-binary: + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v2 + - name: build binary + run: | + docker build . -t builder + docker run --rm -v ${PWD}:/project builder make + - uses: actions/upload-artifact@master + with: + name: binary + path: "*.rpx" + deploy-binary: + needs: build-binary + runs-on: ubuntu-18.04 + steps: + - name: Get environment variables + id: get_repository_name + run: | + echo REPOSITORY_NAME=$(echo "$GITHUB_REPOSITORY" | awk -F / '{print $2}' | sed -e "s/:refs//") >> $GITHUB_ENV + echo DATETIME=$(echo $(date '+%Y%m%d-%H%M%S')) >> $GITHUB_ENV + - uses: actions/download-artifact@master + with: + name: binary + - name: zip artifact + run: zip -r ${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip *.rpx + - name: Create Release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ env.REPOSITORY_NAME }}-${{ env.DATETIME }} + release_name: Nightly-${{ env.REPOSITORY_NAME }}-${{ env.DATETIME }} + draft: false + prerelease: true + body: | + Not a stable release: + ${{ github.event.head_commit.message }} + - name: Upload Release Asset + id: upload-release-asset + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip + asset_name: ${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip + asset_content_type: application/unknown \ No newline at end of file diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml new file mode 100644 index 0000000..f907f7e --- /dev/null +++ b/.github/workflows/pr.yml @@ -0,0 +1,17 @@ +name: CI-PR + +on: [pull_request] + +jobs: + build-binary: + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v2 + - name: build binary + run: | + docker build . -t builder + docker run --rm -v ${PWD}:/project builder make + - uses: actions/upload-artifact@master + with: + name: binary + path: "*.rpx" \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7432917 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +*.elf +*.rpx +build/ +*.cbp +*.layout +*_syms.h +cmake-build-debug/ +.idea/ +CMakeLists.txt diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..1fcc684 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,3 @@ +FROM wiiuenv/devkitppc:20211106 + +WORKDIR project \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9b7b6a7 --- /dev/null +++ b/Makefile @@ -0,0 +1,138 @@ +#------------------------------------------------------------------------------- +.SUFFIXES: +#------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITPRO)),) +$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro") +endif + +TOPDIR ?= $(CURDIR) + +include $(DEVKITPRO)/wut/share/wut_rules + +#------------------------------------------------------------------------------- +# 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 +# DATA is a list of directories containing data files +# INCLUDES is a list of directories containing header files +#------------------------------------------------------------------------------- +TARGET := 20_usb_serial_logging +BUILD := build +SOURCES := source +DATA := data +INCLUDES := include + +#------------------------------------------------------------------------------- +# options for code generation +#------------------------------------------------------------------------------- +CFLAGS := -g -Wall -O2 -ffunction-sections \ + $(MACHDEP) + +CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ + +CXXFLAGS := $(CFLAGS) + +ASFLAGS := -g $(ARCH) -mregnames +LDFLAGS = -g $(ARCH) $(RPXSPECS) --entry=_start -Wl,-Map,$(notdir $*.map) + +LIBS := -lwut + +#------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level +# containing include and lib +#------------------------------------------------------------------------------- +LIBDIRS := $(PORTLIBS) $(WUT_ROOT) $(WUT_ROOT)/usr + + +#------------------------------------------------------------------------------- +# 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 TOPDIR := $(CURDIR) + +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_BIN := $(addsuffix .o,$(BINFILES)) +export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +export OFILES := $(OFILES_BIN) $(OFILES_SRC) +export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) + +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 all + +#------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) -j1 --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(TARGET).rpx $(TARGET).elf + +#------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#------------------------------------------------------------------------------- +# main targets +#------------------------------------------------------------------------------- +all : $(OUTPUT).rpx + +$(OUTPUT).rpx : $(OUTPUT).elf +$(OUTPUT).elf : $(OFILES) + +$(OFILES_SRC) : $(HFILES_BIN) + +#------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#------------------------------------------------------------------------------- +%.bin.o %_bin.h : %.bin +#------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +#--------------------------------------------------------------------------------- +%.o: %.s + @echo $(notdir $<) + @$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@ $(ERROR_FILTER) + +-include $(DEPENDS) + +#------------------------------------------------------------------------------- +endif +#------------------------------------------------------------------------------- diff --git a/README.md b/README.md new file mode 100644 index 0000000..70fb841 --- /dev/null +++ b/README.md @@ -0,0 +1,40 @@ +# USB Serial Logging + +## Usage +Place the `20_usb_serial_logging.rpx` in the `[ENVIROMENT]/modules/setup` folder and run the [EnvironmentLoader](https://github.com/wiiu-env/EnvironmentLoader). +Requires [MochaPayload](https://github.com/wiiu-env/MochaPayload) as a setup module in `[ENVIROMENT]/modules/setup`. + +Requires a USB serial cable with FTDI FT232 chipset (e.g. Digitus DA-70156) and [TeraTerm](https://ttssh2.osdn.jp/index.html.en), or similar serial terminal program. + +Settings: + - Speed: 57600 + - Data: 8 bit + - Parity: none + - Stop bits: 1 bit + - Flow control: none + - New-line Receive: CR+LF + - New-line Transmit: CR+LF + +The IOP-Shell is not supported. + +## Building + +For building you just need [wut](https://github.com/devkitPro/wut/) installed, then use the `make` command. + +## Building using the Dockerfile + +It's possible to use a docker image for building. This way you don't need anything installed on your host system. + +``` +# Build docker image (only needed once) +docker build . -t usb_serial_logging-builder + +# make +docker run -it --rm -v ${PWD}:/project usb_serial_logging-builder make + +# make clean +docker run -it --rm -v ${PWD}:/project usb_serial_logging-builder make clean +``` + +## Credits +Maschell \ No newline at end of file diff --git a/source/crt.c b/source/crt.c new file mode 100644 index 0000000..2fcd925 --- /dev/null +++ b/source/crt.c @@ -0,0 +1,36 @@ +void __init_wut_malloc(); + +void __init_wut_newlib(); + +void __init_wut_stdcpp(); + +void __init_wut_devoptab(); + +void __attribute__((weak)) __init_wut_socket(); + +void __fini_wut_malloc(); + +void __fini_wut_newlib(); + +void __fini_wut_stdcpp(); + +void __fini_wut_devoptab(); + +void __attribute__((weak)) __fini_wut_socket(); + +void __attribute__((weak)) +__init_wut_() { + __init_wut_malloc(); + __init_wut_newlib(); + __init_wut_stdcpp(); + __init_wut_devoptab(); + if (&__init_wut_socket) __init_wut_socket(); +} + +void __attribute__((weak)) +__fini_wut_() { + __fini_wut_devoptab(); + __fini_wut_stdcpp(); + __fini_wut_newlib(); + __fini_wut_malloc(); +} diff --git a/source/crt0.s b/source/crt0.s new file mode 100644 index 0000000..318de30 --- /dev/null +++ b/source/crt0.s @@ -0,0 +1,29 @@ +.extern main +.extern exit +.extern __init_wut_ +.extern __fini_wut_ + +.global _start +_start: + stwu 1, -0x28(1) + mflr 0 + stw 0, 0x2C(1) + stw 31, 0x24(1) + or 31, 1, 1 + stw 3, 0x18(31) + stw 4, 0x1C(31) + bl __init_wut_ + lwz 4, 0x1C(31) + lwz 3, 0x18(31) + bl main + or 9, 3, 3 + stw 9, 0x8(31) + bl __fini_wut_ + lwz 9, 0x8(31) + or 3, 9, 9 + addi 11, 31, 0x28 + lwz 0, 0x4(11) + mtlr 0 + lwz 31, -0x4(11) + or 1, 11, 11 + blr \ No newline at end of file diff --git a/source/kernel.s b/source/kernel.s new file mode 100644 index 0000000..563e7f0 --- /dev/null +++ b/source/kernel.s @@ -0,0 +1,27 @@ +.global SCKernelCopyData +SCKernelCopyData: + // Disable data address translation + mfmsr %r6 + li %r7, 0x10 + andc %r6, %r6, %r7 + mtmsr %r6 + + // Copy data + addi %r3, %r3, -1 + addi %r4, %r4, -1 + mtctr %r5 +SCKernelCopyData_loop: + lbzu %r5, 1(%r4) + stbu %r5, 1(%r3) + bdnz SCKernelCopyData_loop + + // Enable data address translation + ori %r6, %r6, 0x10 + mtmsr %r6 + blr + +.global KernelCopyDataInternal +KernelCopyDataInternal: + li %r0, 0x2500 + sc + blr \ No newline at end of file diff --git a/source/main.cpp b/source/main.cpp new file mode 100644 index 0000000..fbde281 --- /dev/null +++ b/source/main.cpp @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" void SCKernelCopyData(uint32_t dst, uint32_t src, uint32_t len); +extern "C" void KernelCopyDataInternal(uint32_t dst, uint32_t src, uint32_t len); + +#define KERN_SYSCALL_TBL1 0xFFE84C70 //Unknown +#define KERN_SYSCALL_TBL2 0xFFE85070 //Games +#define KERN_SYSCALL_TBL3 0xFFE85470 //Loader +#define KERN_SYSCALL_TBL4 0xFFEAAA60 //Home menu +#define KERN_SYSCALL_TBL5 0xFFEAAE60 //Browser + +void KernelNOPAtPhysicalAddress(uint32_t addr) { + uint32_t dst = 0x60000000; + ICInvalidateRange(&dst, 4); + DCFlushRange(&dst, 4); + KernelCopyDataInternal(addr, (uint32_t) OSEffectiveToPhysical((uint32_t) &dst), 4); +} + +/* Write a 32-bit word with kernel permissions */ +void __attribute__ ((noinline)) kern_write(void *addr, uint32_t value) { + asm volatile ( + "li 3,1\n" + "li 4,0\n" + "mr 5,%1\n" + "li 6,0\n" + "li 7,0\n" + "lis 8,1\n" + "mr 9,%0\n" + "mr %1,1\n" + "li 0,0x3500\n" + "sc\n" + "nop\n" + "mr 1,%1\n" + : + : "r"(addr), "r"(value) + : "memory", "ctr", "lr", "0", "3", "4", "5", "6", "7", "8", "9", "10", + "11", "12" + ); +} + +int main(int argc, char **argv) { + // Start syslogging on iosu side + int mcpFd = IOS_Open("/dev/mcp", (IOSOpenMode) 0); + if (mcpFd >= 0) { + int in = 0xFA; // IPC_CUSTOM_START_USB_LOGGING + int out = 0; + IOS_Ioctl(mcpFd, 100, &in, sizeof(in), &out, sizeof(out)); + IOS_Close(mcpFd); + } + + kern_write((void *) (KERN_SYSCALL_TBL1 + 0x25 * 4), (uint32_t) SCKernelCopyData); + kern_write((void *) (KERN_SYSCALL_TBL2 + 0x25 * 4), (uint32_t) SCKernelCopyData); + kern_write((void *) (KERN_SYSCALL_TBL3 + 0x25 * 4), (uint32_t) SCKernelCopyData); + kern_write((void *) (KERN_SYSCALL_TBL4 + 0x25 * 4), (uint32_t) SCKernelCopyData); + kern_write((void *) (KERN_SYSCALL_TBL5 + 0x25 * 4), (uint32_t) SCKernelCopyData); + + // Patch loader.elf to spit out less warnings when loading .rpx built with wut + KernelNOPAtPhysicalAddress(0x0100b770 - 0x01000000 + 0x32000000); + KernelNOPAtPhysicalAddress(0x0100b800 - 0x01000000 + 0x32000000); + KernelNOPAtPhysicalAddress(0x0100b7b8 - 0x01000000 + 0x32000000); + ICInvalidateRange(reinterpret_cast(0x0100b770), 0x04); + ICInvalidateRange(reinterpret_cast(0x0100b800), 0x04); + ICInvalidateRange(reinterpret_cast(0x0100b7b8), 0x04); + + return 0; +}