diff --git a/Makefile.wiiu b/Makefile.wiiu index 90ff8d0619..2d89412de7 100644 --- a/Makefile.wiiu +++ b/Makefile.wiiu @@ -78,11 +78,6 @@ ifeq ($(strip $(DEVKITPRO)),) $(error "Please set DEVKITPRO in your environment. export DEVKITPRO=devkitPRO") endif -ifeq ($(strip $(WUT_ROOT)),) -$(error "Please set WUT_ROOT in your environment. export WUT_ROOT=WUT") -endif - - export PATH := $(PATH):$(DEVKITPPC)/bin PREFIX := powerpc-eabi- @@ -96,9 +91,9 @@ STRIP := $(PREFIX)strip NM := $(PREFIX)nm LD := $(CXX) -ELF2RPL := $(WUT_ROOT)/tools/bin/elf2rpl +ELF2RPL := wiiu/wut/elf2rpl/elf2rpl -INCDIRS := -I. -Ideps/zlib -Ideps/7zip -Ilibretro-common/include -Iwiiu -I$(WUT_ROOT)/include -I$(DEVKITPRO)/portlibs/ppc/include +INCDIRS := -I. -Ideps/zlib -Ideps/7zip -Ilibretro-common/include -Iwiiu -Iwiiu/wut/include -I$(DEVKITPRO)/portlibs/ppc/include LIBDIRS := -L. -L$(DEVKITPRO)/portlibs/ppc/lib CFLAGS := -mrvl -mcpu=750 -meabi -mhard-float @@ -144,8 +139,7 @@ LIBS := $(WHOLE_START) -lretro_wiiu $(WHOLE_END) -lm -lfat -liosuhax RPX_OBJ = wiiu/system/stubs_rpl.o HBL_ELF_OBJ = wiiu/system/dynamic.o wiiu/system/stubs_elf.o -RPX_LDFLAGS := -L$(WUT_ROOT)/lib -L$(DEVKITPPC)/lib -RPX_LDFLAGS += -pie -fPIE +RPX_LDFLAGS := -pie -fPIE RPX_LDFLAGS += -z common-page-size=64 -z max-page-size=64 RPX_LDFLAGS += -T wiiu/link_rpl.ld RPX_LDFLAGS += -nostartfiles @@ -193,14 +187,17 @@ all: $(TARGETS) %.depend: ; +$(ELF2RPL): + $(MAKE) -C wiiu/wut/elf2rpl/ + $(TARGET).elf: $(OBJ) $(HBL_ELF_OBJ) libretro_wiiu.a wiiu/link_elf.ld $(LD) $(OBJ) $(HBL_ELF_OBJ) $(LDFLAGS) $(HBL_ELF_LDFLAGS) $(LIBDIRS) $(LIBS) -o $@ $(TARGET).rpx.elf: $(OBJ) $(RPX_OBJ) libretro_wiiu.a wiiu/link_elf.ld $(LD) $(OBJ) $(RPX_OBJ) $(LDFLAGS) $(RPX_LDFLAGS) $(LIBDIRS) $(LIBS) -o $@ -$(TARGET).rpx: $(TARGET).rpx.elf - -$(ELF2RPL) $(notdir $<) $@ +$(TARGET).rpx: $(TARGET).rpx.elf $(ELF2RPL) + -$(ELF2RPL) $(TARGET).rpx.elf $@ clean: rm -f $(OBJ) $(RPX_OBJ) $(HBL_ELF_OBJ) $(TARGET).elf $(TARGET).rpx.elf $(TARGET).rpx diff --git a/frontend/drivers/platform_wiiu.c b/frontend/drivers/platform_wiiu.c index 10f4ccc161..be097a0eaf 100644 --- a/frontend/drivers/platform_wiiu.c +++ b/frontend/drivers/platform_wiiu.c @@ -213,7 +213,7 @@ void log_deinit(void) log_socket = -1; } } -static int log_write(struct _reent *r, int fd, const char *ptr, size_t len) +static ssize_t log_write(struct _reent *r, void* fd, const char *ptr, size_t len) { if(log_socket < 0) return len; diff --git a/wiiu/fs/sd_fat_devoptab.c b/wiiu/fs/sd_fat_devoptab.c index 7805e05135..b6d27d5f5b 100644 --- a/wiiu/fs/sd_fat_devoptab.c +++ b/wiiu/fs/sd_fat_devoptab.c @@ -204,7 +204,7 @@ static int sd_fat_open_r (struct _reent *r, void *fileStruct, const char *path, } -static int sd_fat_close_r (struct _reent *r, int fd) +static int sd_fat_close_r (struct _reent *r, void* fd) { sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; if(!file->dev) { @@ -226,7 +226,7 @@ static int sd_fat_close_r (struct _reent *r, int fd) return 0; } -static off_t sd_fat_seek_r (struct _reent *r, int fd, off_t pos, int dir) +static off_t sd_fat_seek_r (struct _reent *r, void* fd, off_t pos, int dir) { sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; if(!file->dev) { @@ -264,7 +264,7 @@ static off_t sd_fat_seek_r (struct _reent *r, int fd, off_t pos, int dir) return result; } -static ssize_t sd_fat_write_r (struct _reent *r, int fd, const char *ptr, size_t len) +static ssize_t sd_fat_write_r (struct _reent *r, void* fd, const char *ptr, size_t len) { sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; if(!file->dev) { @@ -325,7 +325,7 @@ static ssize_t sd_fat_write_r (struct _reent *r, int fd, const char *ptr, size_t return done; } -static ssize_t sd_fat_read_r (struct _reent *r, int fd, char *ptr, size_t len) +static ssize_t sd_fat_read_r (struct _reent *r, void* fd, char *ptr, size_t len) { sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; if(!file->dev) { @@ -384,7 +384,7 @@ static ssize_t sd_fat_read_r (struct _reent *r, int fd, char *ptr, size_t len) } -static int sd_fat_fstat_r (struct _reent *r, int fd, struct stat *st) +static int sd_fat_fstat_r (struct _reent *r, void* fd, struct stat *st) { sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; if(!file->dev) { @@ -422,7 +422,7 @@ static int sd_fat_fstat_r (struct _reent *r, int fd, struct stat *st) return 0; } -static int sd_fat_ftruncate_r (struct _reent *r, int fd, off_t len) +static int sd_fat_ftruncate_r (struct _reent *r, void* fd, off_t len) { sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; if(!file->dev) { @@ -444,7 +444,7 @@ static int sd_fat_ftruncate_r (struct _reent *r, int fd, off_t len) return 0; } -static int sd_fat_fsync_r (struct _reent *r, int fd) +static int sd_fat_fsync_r (struct _reent *r, void* fd) { sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; if(!file->dev) { diff --git a/wiiu/wut/elf2rpl/Makefile b/wiiu/wut/elf2rpl/Makefile new file mode 100644 index 0000000000..3597b6a9eb --- /dev/null +++ b/wiiu/wut/elf2rpl/Makefile @@ -0,0 +1,21 @@ +TARGET := elf2rpl + +CXX := g++ +LD := g++ + +OBJS := main.o +INCLUDES := -I. + +CFLAGS := -O2 -Wall --std=c++14 +LDFLAGS := -lz + +all: $(TARGET) + +clean: + @rm -rf $(TARGET) $(OBJS) + +%.o: %.cpp + $(CXX) -c -o $@ $< $(CFLAGS) $(INCLUDES) + +$(TARGET): $(OBJS) + $(LD) $(OBJS) $(CFLAGS) $(LDFLAGS) -o $@ diff --git a/wiiu/wut/elf2rpl/be_val.h b/wiiu/wut/elf2rpl/be_val.h new file mode 100644 index 0000000000..846807b4f3 --- /dev/null +++ b/wiiu/wut/elf2rpl/be_val.h @@ -0,0 +1,72 @@ +#pragma once +#include +#include +#include "utils.h" + +template +class be_val +{ +public: + static_assert(!std::is_array::value, "be_val invalid type: array"); + static_assert(!std::is_pointer::value, "be_val invalid type: pointer"); + static_assert(sizeof(Type) == 1 || sizeof(Type) == 2 || sizeof(Type) == 4 || sizeof(Type) == 8, "be_val invalid type size"); + + be_val() + { + } + + be_val(Type value) + { + *this = value; + } + + Type value() const + { + return byte_swap(mValue); + } + + operator Type() const + { + return value(); + } + + template std::enable_if_t::value, be_val&> + operator =(const Other &rhs) + { + mValue = byte_swap(static_cast(rhs)); + return *this; + } + + be_val &operator++() { *this = value() + 1; return *this; } + be_val &operator--() { *this = value() - 1; return *this; } + be_val operator--(int) { auto old = *this; *this = value() - 1; return old; } + be_val operator++(int) { auto old = *this; *this = value() + 1; return old; } + + template bool operator == (const Other &rhs) const { return value() == static_cast(rhs); } + template bool operator != (const Other &rhs) const { return value() != static_cast(rhs); } + template bool operator >= (const Other &rhs) const { return value() >= static_cast(rhs); } + template bool operator <= (const Other &rhs) const { return value() <= static_cast(rhs); } + template bool operator > (const Other &rhs) const { return value() > static_cast(rhs); } + template bool operator < (const Other &rhs) const { return value() < static_cast(rhs); } + + template be_val &operator+=(const Other &rhs) { *this = static_cast(value() + rhs); return *this; } + template be_val &operator-=(const Other &rhs) { *this = static_cast(value() - rhs); return *this; } + template be_val &operator*=(const Other &rhs) { *this = static_cast(value() * rhs); return *this; } + template be_val &operator/=(const Other &rhs) { *this = static_cast(value() / rhs); return *this; } + template be_val &operator%=(const Other &rhs) { *this = static_cast(value() % rhs); return *this; } + template be_val &operator|=(const Other &rhs) { *this = static_cast(value() | rhs); return *this; } + template be_val &operator&=(const Other &rhs) { *this = static_cast(value() & rhs); return *this; } + template be_val &operator^=(const Other &rhs) { *this = static_cast(value() ^ rhs); return *this; } + + template Type operator+(const Other &rhs) const { return static_cast(value() + rhs); } + template Type operator-(const Other &rhs) const { return static_cast(value() - rhs); } + template Type operator*(const Other &rhs) const { return static_cast(value() * rhs); } + template Type operator/(const Other &rhs) const { return static_cast(value() / rhs); } + template Type operator%(const Other &rhs) const { return static_cast(value() % rhs); } + template Type operator|(const Other &rhs) const { return static_cast(value() | rhs); } + template Type operator&(const Other &rhs) const { return static_cast(value() & rhs); } + template Type operator^(const Other &rhs) const { return static_cast(value() ^ rhs); } + +protected: + Type mValue {}; +}; diff --git a/wiiu/wut/elf2rpl/elf.h b/wiiu/wut/elf2rpl/elf.h new file mode 100644 index 0000000000..17a77b70e3 --- /dev/null +++ b/wiiu/wut/elf2rpl/elf.h @@ -0,0 +1,314 @@ +#pragma once +#include +#include "be_val.h" + +#pragma pack(push, 1) + +namespace elf +{ + +enum Machine : uint32_t // e_machine +{ + EM_PPC = 20 // PowerPC +}; + +enum Encoding : uint32_t // e_encoding +{ + ELFDATANONE = 0, + ELFDATA2LSB = 1, + ELFDATA2MSB = 2 +}; + +enum Class : uint32_t // e_class +{ + ELFCLASSNONE = 0, + ELFCLASS32 = 1, + ELFCLASS64 = 2 +}; + +enum Version : uint32_t // e_elf_version +{ + EV_NONE = 0, + EV_CURRENT = 1, +}; + +enum FileType : uint32_t // e_type +{ + ET_NONE = 0, // No file type + ET_REL = 1, // Relocatable file + ET_EXEC = 2, // Executable file + ET_DYN = 3, // Shared object file + ET_CORE = 4, // Core file + ET_LOPROC = 0xff00, // Beginning of processor-specific codes + ET_CAFE_RPL = 0xff01, // Cafe RPL file + ET_HIPROC = 0xffff // Processor-specific +}; + +enum EABI : uint32_t // e_abi +{ + EABI_CAFE = 0xcafe // WiiU CafeOS +}; + +enum SectionFlags : uint32_t // sh_flags +{ + SHF_WRITE = 0x1, + SHF_ALLOC = 0x2, + SHF_EXECINSTR = 0x4, + SHF_DEFLATED = 0x08000000, + SHF_MASKPROC = 0xF0000000, +}; + +enum SectionType : uint32_t // sh_type +{ + SHT_NULL = 0, // No associated section (inactive entry). + SHT_PROGBITS = 1, // Program-defined contents. + SHT_SYMTAB = 2, // Symbol table. + SHT_STRTAB = 3, // String table. + SHT_RELA = 4, // Relocation entries; explicit addends. + SHT_HASH = 5, // Symbol hash table. + SHT_DYNAMIC = 6, // Information for dynamic linking. + SHT_NOTE = 7, // Information about the file. + SHT_NOBITS = 8, // Data occupies no space in the file. + SHT_REL = 9, // Relocation entries; no explicit addends. + SHT_SHLIB = 10, // Reserved. + SHT_DYNSYM = 11, // Symbol table. + SHT_INIT_ARRAY = 14, // Pointers to initialization functions. + SHT_FINI_ARRAY = 15, // Pointers to termination functions. + SHT_PREINIT_ARRAY = 16, // Pointers to pre-init functions. + SHT_GROUP = 17, // Section group. + SHT_SYMTAB_SHNDX = 18, // Indices for SHN_XINDEX entries. + SHT_LOPROC = 0x70000000, // Lowest processor arch-specific type. + SHT_HIPROC = 0x7fffffff, // Highest processor arch-specific type. + SHT_LOUSER = 0x80000000, // Lowest type reserved for applications. + SHT_RPL_EXPORTS = 0x80000001, // RPL Exports + SHT_RPL_IMPORTS = 0x80000002, // RPL Imports + SHT_RPL_CRCS = 0x80000003, // RPL CRCs + SHT_RPL_FILEINFO = 0x80000004,// RPL FileInfo + SHT_HIUSER = 0xffffffff // Highest type reserved for applications. +}; + +enum SymbolBinding : uint32_t // st_info >> 4 +{ + STB_LOCAL = 0, // Local symbol, not visible outside obj file containing def + STB_GLOBAL = 1, // Global symbol, visible to all object files being combined + STB_WEAK = 2, // Weak symbol, like global but lower-precedence + STB_GNU_UNIQUE = 10, + STB_LOOS = 10, // Lowest operating system-specific binding type + STB_HIOS = 12, // Highest operating system-specific binding type + STB_LOPROC = 13, // Lowest processor-specific binding type + STB_HIPROC = 15 // Highest processor-specific binding type +}; + +enum SymbolType : uint32_t // st_info & f +{ + STT_NOTYPE = 0, // Symbol's type is not specified + STT_OBJECT = 1, // Symbol is a data object (variable, array, etc.) + STT_FUNC = 2, // Symbol is executable code (function, etc.) + STT_SECTION = 3, // Symbol refers to a section + STT_FILE = 4, // Local, absolute symbol that refers to a file + STT_COMMON = 5, // An uninitialized common block + STT_TLS = 6, // Thread local data object + STT_LOOS = 7, // Lowest operating system-specific symbol type + STT_HIOS = 8, // Highest operating system-specific symbol type + STT_GNU_IFUNC = 10, // GNU indirect function + STT_LOPROC = 13, // Lowest processor-specific symbol type + STT_HIPROC = 15 // Highest processor-specific symbol type +}; + +enum SectionIndex : uint16_t // st_shndx +{ + SHN_UNDEF = 0, // Undefined + SHN_LORESERVE = 0xff00, // Reserved range + SHN_ABS = 0xfff1, // Absolute symbols + SHN_COMMON = 0xfff2, // Common symbols + SHN_XINDEX = 0xffff, // Escape -- index stored elsewhere + SHN_HIRESERVE = 0xffff +}; + +enum RelocationType : uint32_t // r_info & 0xff +{ + R_PPC_NONE = 0, + R_PPC_ADDR32 = 1, + R_PPC_ADDR24 = 2, + R_PPC_ADDR16 = 3, + R_PPC_ADDR16_LO = 4, + R_PPC_ADDR16_HI = 5, + R_PPC_ADDR16_HA = 6, + R_PPC_ADDR14 = 7, + R_PPC_ADDR14_BRTAKEN = 8, + R_PPC_ADDR14_BRNTAKEN = 9, + R_PPC_REL24 = 10, + R_PPC_REL14 = 11, + R_PPC_REL14_BRTAKEN = 12, + R_PPC_REL14_BRNTAKEN = 13, + R_PPC_GOT16 = 14, + R_PPC_GOT16_LO = 15, + R_PPC_GOT16_HI = 16, + R_PPC_GOT16_HA = 17, + R_PPC_PLTREL24 = 18, + R_PPC_JMP_SLOT = 21, + R_PPC_RELATIVE = 22, + R_PPC_LOCAL24PC = 23, + R_PPC_REL32 = 26, + R_PPC_TLS = 67, + R_PPC_DTPMOD32 = 68, + R_PPC_TPREL16 = 69, + R_PPC_TPREL16_LO = 70, + R_PPC_TPREL16_HI = 71, + R_PPC_TPREL16_HA = 72, + R_PPC_TPREL32 = 73, + R_PPC_DTPREL16 = 74, + R_PPC_DTPREL16_LO = 75, + R_PPC_DTPREL16_HI = 76, + R_PPC_DTPREL16_HA = 77, + R_PPC_DTPREL32 = 78, + R_PPC_GOT_TLSGD16 = 79, + R_PPC_GOT_TLSGD16_LO = 80, + R_PPC_GOT_TLSGD16_HI = 81, + R_PPC_GOT_TLSGD16_HA = 82, + R_PPC_GOT_TLSLD16 = 83, + R_PPC_GOT_TLSLD16_LO = 84, + R_PPC_GOT_TLSLD16_HI = 85, + R_PPC_GOT_TLSLD16_HA = 86, + R_PPC_GOT_TPREL16 = 87, + R_PPC_GOT_TPREL16_LO = 88, + R_PPC_GOT_TPREL16_HI = 89, + R_PPC_GOT_TPREL16_HA = 90, + R_PPC_GOT_DTPREL16 = 91, + R_PPC_GOT_DTPREL16_LO = 92, + R_PPC_GOT_DTPREL16_HI = 93, + R_PPC_GOT_DTPREL16_HA = 94, + R_PPC_TLSGD = 95, + R_PPC_TLSLD = 96, + R_PPC_EMB_SDA21 = 109, + R_PPC_REL16 = 249, + R_PPC_REL16_LO = 250, + R_PPC_REL16_HI = 251, + R_PPC_REL16_HA = 252, +}; + +enum RplFileInfoFlag : uint32_t +{ + RPL_IS_RPX = 0x2, +}; + +static const unsigned HeaderMagic = 0x7f454c46; + +struct Header +{ + be_val magic; // File identification. + be_val fileClass; // File class. + be_val encoding; // Data encoding. + be_val elfVersion; // File version. + be_val abi; // OS/ABI identification. (EABI_*) + be_val pad[7]; + + be_val type; // Type of file (ET_*) + be_val machine; // Required architecture for this file (EM_*) + be_val version; // Must be equal to 1 + be_val entry; // Address to jump to in order to start program + be_val phoff; // Program header table's file offset, in bytes + be_val shoff; // Section header table's file offset, in bytes + be_val flags; // Processor-specific flags + be_val ehsize; // Size of ELF header, in bytes + be_val phentsize; // Size of an entry in the program header table + be_val phnum; // Number of entries in the program header table + be_val shentsize; // Size of an entry in the section header table + be_val shnum; // Number of entries in the section header table + be_val shstrndx; // Sect hdr table index of sect name string table +}; +CHECK_SIZE(Header, 0x34); + +struct SectionHeader +{ + be_val name; // Section name (index into string table) + be_val type; // Section type (SHT_*) + be_val flags; // Section flags (SHF_*) + be_val addr; // Address where section is to be loaded + be_val offset; // File offset of section data, in bytes + be_val size; // Size of section, in bytes + be_val link; // Section type-specific header table index link + be_val info; // Section type-specific extra information + be_val addralign; // Section address alignment + be_val entsize; // Size of records contained within the section +}; +CHECK_SIZE(SectionHeader, 0x28); + +struct Symbol +{ + be_val name; // Symbol name (index into string table) + be_val value; // Value or address associated with the symbol + be_val size; // Size of the symbol + be_val info; // Symbol's type and binding attributes + be_val other; // Must be zero; reserved + be_val shndx; // Which section (header table index) it's defined in (SHN_*) +}; +CHECK_SIZE(Symbol, 0x10); + +struct Rela +{ + be_val offset; + be_val info; + be_val addend; +}; +CHECK_SIZE(Rela, 0x0C); + +struct RplImport +{ + be_val count; + be_val signature; + char name[1]; +}; + +struct RplExport +{ + struct Export + { + be_val value; + be_val name; + }; + + be_val count; + be_val signature; + Export exports[1]; +}; + +struct RplCrc +{ + be_val crc; +}; +CHECK_SIZE(RplCrc, 0x04); + +struct RplFileInfo +{ + be_val version; + be_val textSize; + be_val textAlign; + be_val dataSize; + be_val dataAlign; + be_val loadSize; + be_val loadAlign; + be_val tempSize; + be_val trampAdjust; + be_val sdaBase; + be_val sda2Base; + be_val stackSize; + be_val filename; + be_val flags; + be_val heapSize; + be_val tagOffset; + be_val minVersion; + be_val compressionLevel; + be_val trampAddition; + be_val fileInfoPad; + be_val cafeSdkVersion; + be_val cafeSdkRevision; + be_val tlsModuleIndex; + be_val tlsAlignShift; + be_val runtimeFileInfoSize; +}; +CHECK_SIZE(RplFileInfo, 0x60); + +} // namespace elf + +#pragma pack(pop) diff --git a/wiiu/wut/elf2rpl/elf2rpl.vcxproj b/wiiu/wut/elf2rpl/elf2rpl.vcxproj new file mode 100644 index 0000000000..d0347914f0 --- /dev/null +++ b/wiiu/wut/elf2rpl/elf2rpl.vcxproj @@ -0,0 +1,172 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {F6442B08-9323-4D98-ABA6-8856467B148B} + Win32Proj + elf2rpl + 8.1 + + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\bin\ + $(SolutionDir)\ext\zlib;$(IncludePath) + + + true + $(SolutionDir)\bin\ + $(SolutionDir)\ext\zlib;$(IncludePath) + + + false + $(SolutionDir)\bin\ + $(SolutionDir)\ext\zlib;$(IncludePath) + + + false + $(SolutionDir)\bin\ + $(SolutionDir)\ext\zlib;$(IncludePath) + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)\common;%(AdditionalIncludeDirectories) + + + Console + true + UseLinkTimeCodeGeneration + + + + + + + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)\common;%(AdditionalIncludeDirectories) + + + Console + true + UseLinkTimeCodeGeneration + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)\common;%(AdditionalIncludeDirectories) + + + Console + true + true + No + UseLinkTimeCodeGeneration + + + + + Level3 + + + MaxSpeed + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)\common;%(AdditionalIncludeDirectories) + + + Console + true + true + No + UseLinkTimeCodeGeneration + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/wiiu/wut/elf2rpl/elf2rpl.vcxproj.filters b/wiiu/wut/elf2rpl/elf2rpl.vcxproj.filters new file mode 100644 index 0000000000..bd1de7e328 --- /dev/null +++ b/wiiu/wut/elf2rpl/elf2rpl.vcxproj.filters @@ -0,0 +1,39 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {36d55ffd-f33d-437b-abc1-6e26a832efb3} + + + + + Source Files + + + Source Files\ext + + + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/wiiu/wut/elf2rpl/main.cpp b/wiiu/wut/elf2rpl/main.cpp new file mode 100644 index 0000000000..4a035984cf --- /dev/null +++ b/wiiu/wut/elf2rpl/main.cpp @@ -0,0 +1,1219 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "elf.h" + +#pragma pack(push, 1) + +struct RplLibsDef +{ + be_val name; + be_val stubStart; + be_val stubEnd; +}; + +#pragma pack(pop) + +static const uint32_t LoadAddress = 0x01000000u; +static const uint32_t CodeAddress = 0x02000000u; +static const uint32_t DataAddress = 0x10000000u; +static const uint32_t WiiuLoadAddress = 0xC0000000u; + +struct ElfFile +{ + struct Symbol + { + std::string name; + uint32_t address; + uint32_t size; + elf::SymbolType type; + elf::SymbolBinding binding; + uint32_t outNamePos; + }; + + struct Relocation + { + uint32_t target; + elf::RelocationType type; + + Symbol *symbol; + uint32_t addend; + }; + + struct DataSection + { + std::string name; + uint32_t address; + elf::SectionType type; + elf::SectionFlags flags; + + // Data used if type == SHT_PROGBITS + std::vector data; + + // Size used if type == SHT_NOBITS + uint32_t size; + }; + + struct RplImport + { + Symbol *trampSymbol; + Symbol *stubSymbol; + uint32_t stubAddr; + uint32_t trampAddr; + }; + + struct RplImportLibrary + { + std::string name; + std::vector> imports; + }; + + uint32_t entryPoint; + std::vector> dataSections; + std::vector> symbols; + std::vector> relocations; + std::vector> rplImports; +}; + +struct InputSection +{ + elf::SectionHeader header; + std::vector data; +}; + +static ElfFile::Symbol * +findSymbol(ElfFile &file, uint32_t address) +{ + for (auto &symbol : file.symbols) { + if (symbol->address == address && symbol->type != elf::STT_NOTYPE) { + return symbol.get(); + } + } + + for (auto &symbol : file.symbols) { + if (symbol->address == address) { + return symbol.get(); + } + } + + return nullptr; +} + +static ElfFile::RplImport * +findImport(ElfFile &file, uint32_t address) +{ + for (auto &lib : file.rplImports) { + for (auto &import : lib->imports) { + if (import->stubAddr == address || import->trampAddr == address) { + return import.get(); + } + } + } + + return nullptr; +} + +template +static Type * +getLoaderDataPtr(std::vector &inSections, uint32_t address) +{ + for (auto §ion : inSections) { + auto start = section.header.addr; + auto end = start + section.data.size(); + + if (start <= address && end > address) { + auto offset = address - start; + return reinterpret_cast(section.data.data() + offset); + } + } + + return nullptr; +} + +static elf::Symbol * +getSectionSymbol(InputSection §ion, size_t index) +{ + auto symbols = reinterpret_cast(section.data.data()); + return &symbols[index]; +}; + +static bool +read(ElfFile &file, const std::string &filename) +{ + std::ifstream in { filename, std::ifstream::binary }; + std::vector inSections; + + if (!in.is_open()) { + std::cout << "Could not open " << filename << " for reading" << std::endl; + return false; + } + + // Read header + elf::Header header; + in.read(reinterpret_cast(&header), sizeof(elf::Header)); + + if (header.magic != elf::HeaderMagic) { + std::cout << "Invalid ELF magic header" << std::endl; + return false; + } + + if (header.fileClass != elf::ELFCLASS32) { + std::cout << "Unexpected ELF file class" << std::endl; + return false; + } + + if (header.encoding != elf::ELFDATA2MSB) { + std::cout << "Unexpected ELF encoding" << std::endl; + return false; + } + + if (header.machine != elf::EM_PPC) { + std::cout << "Unexpected ELF machine type" << std::endl; + return false; + } + + if (header.elfVersion != elf::EV_CURRENT) { + std::cout << "Unexpected ELF version" << std::endl; + return false; + } + + file.entryPoint = header.entry; + + // Read section headers and data + in.seekg(static_cast(header.shoff)); + inSections.resize(header.shnum); + + for (auto §ion : inSections) { + in.read(reinterpret_cast(§ion.header), sizeof(elf::SectionHeader)); + + if (!section.header.size || section.header.type == elf::SHT_NOBITS) { + continue; + } + + auto pos = in.tellg(); + in.seekg(static_cast(section.header.offset)); + section.data.resize(section.header.size); + in.read(section.data.data(), section.data.size()); + in.seekg(pos); + } + + auto shStrTab = inSections[header.shstrndx].data.data(); + + // Process any loader relocations + for (auto §ion : inSections) { + if (section.header.type != elf::SHT_RELA) { + continue; + } + + auto name = std::string { shStrTab + section.header.name }; + + if (name.compare(".rela.dyn") != 0) { + continue; + } + + auto symSection = inSections[section.header.link]; + auto relas = reinterpret_cast(section.data.data()); + auto count = section.data.size() / sizeof(elf::Rela); + + for (auto i = 0u; i < count; ++i) { + auto &rela = relas[i]; + auto index = rela.info >> 8; + auto symbol = getSectionSymbol(symSection, index); + auto addr = symbol->value + rela.addend; + + auto type = rela.info & 0xff; + auto ptr = getLoaderDataPtr(inSections, rela.offset); + + if (!ptr) { + std::cout << "Unexpected relocation offset in .rela.dyn section" << std::endl; + return false; + } + + switch (type) { + case elf::R_PPC_RELATIVE: + *ptr = byte_swap(addr); + break; + case elf::R_PPC_NONE: + // ignore padding + break; + default: + std::cout << "Unexpected relocation type in .rela.dyn section" << std::endl; + return false; + } + } + } + + // Read text/data sections + for (auto §ion : inSections) { + if (section.header.addr >= LoadAddress && section.header.addr < CodeAddress) { + // Skip any load sections + continue; + } + + auto name = std::string { shStrTab + section.header.name }; + + if (section.header.type == elf::SHT_PROGBITS) { + auto data = new ElfFile::DataSection(); + data->type = elf::SHT_PROGBITS; + data->flags = static_cast(section.header.flags.value()); + data->name = shStrTab + section.header.name; + data->address = section.header.addr; + data->data = section.data; + file.dataSections.emplace_back(data); + } else if (section.header.type == elf::SHT_NOBITS) { + auto bss = new ElfFile::DataSection(); + bss->type = elf::SHT_NOBITS; + bss->flags = static_cast(section.header.flags.value()); + bss->name = shStrTab + section.header.name; + bss->address = section.header.addr; + bss->size = section.header.size; + file.dataSections.emplace_back(bss); + } + } + + // Default symbols + auto symNull = new ElfFile::Symbol(); + symNull->address = 0; + symNull->size = 0; + symNull->type = elf::STT_NOTYPE; + symNull->binding = elf::STB_LOCAL; + file.symbols.emplace_back(symNull); + + auto symText = new ElfFile::Symbol(); + symText->name = "$TEXT"; + symText->address = CodeAddress; + symText->size = 0; + symText->type = elf::STT_SECTION; + symText->binding = elf::STB_LOCAL; + file.symbols.emplace_back(symText); + + auto symData = new ElfFile::Symbol(); + symData->name = "$DATA"; + symData->address = DataAddress; + symData->size = 0; + symData->type = elf::STT_SECTION; + symData->binding = elf::STB_LOCAL; + file.symbols.emplace_back(symData); + + auto symUndef = new ElfFile::Symbol(); + symUndef->name = "$UNDEF"; + symUndef->address = 0; + symUndef->size = 0; + symUndef->type = elf::STT_OBJECT; + symUndef->binding = elf::STB_GLOBAL; + file.symbols.emplace_back(symUndef); + + // Read symbols + for (auto §ion : inSections) { + if (section.header.type != elf::SHT_SYMTAB) { + continue; + } + + auto name = std::string { shStrTab + section.header.name }; + + if (name.compare(".symtab") != 0) { + std::cout << "Unexpected symbol section " << name << std::endl; + return false; + } + + auto strTab = inSections[section.header.link].data.data(); + auto symTab = reinterpret_cast(section.data.data()); + auto count = section.data.size() / sizeof(elf::Symbol); + + for (auto i = 0u; i < count; ++i) { + auto &sym = symTab[i]; + + if (sym.value >= LoadAddress && sym.value < CodeAddress) { + // Skip any load symbols + continue; + } + + auto type = static_cast(sym.info & 0xF); + auto binding = static_cast((sym.info >> 4) & 0xF); + + if (type == elf::STT_NOTYPE && sym.value == 0) { + // Skip null symbol + continue; + } + + if (type == elf::STT_FILE || type == elf::STT_SECTION) { + // Skip file, section symbols + continue; + } + + auto symbol = new ElfFile::Symbol(); + symbol->name = strTab + sym.name; + symbol->address = sym.value; + symbol->size = sym.size; + symbol->type = type; + symbol->binding = binding; + file.symbols.emplace_back(symbol); + } + } + + // Read RPL imports + for (auto §ion : inSections) { + auto name = std::string { shStrTab + section.header.name }; + + if (name.compare(".lib.rplLibs") != 0) { + continue; + } + + auto rplTab = reinterpret_cast(section.data.data()); + auto count = section.data.size() / sizeof(RplLibsDef); + + for (auto i = 0u; i < count; ++i) { + auto &rpl = rplTab[i]; + auto lib = new ElfFile::RplImportLibrary(); + lib->name = getLoaderDataPtr(inSections, rpl.name); + + for (auto stubAddr = rpl.stubStart; stubAddr < rpl.stubEnd; stubAddr += 4) { + auto import = new ElfFile::RplImport(); + import->trampAddr = byte_swap(*getLoaderDataPtr(inSections, stubAddr)); + import->stubAddr = stubAddr; + + // Get the tramp symbol + import->trampSymbol = findSymbol(file, import->trampAddr); + + // Create a new symbol to use for the import + auto stubSymbol = new ElfFile::Symbol(); + import->stubSymbol = stubSymbol; + stubSymbol->name = import->trampSymbol->name; + stubSymbol->address = 0; + stubSymbol->size = 0; + stubSymbol->binding = elf::STB_GLOBAL; + stubSymbol->type = elf::STT_FUNC; + file.symbols.emplace_back(stubSymbol); + + // Rename tramp symbol + import->trampSymbol->name += "_tramp"; + + lib->imports.emplace_back(import); + } + + file.rplImports.emplace_back(lib); + } + } + + // Read relocations + for (auto §ion : inSections) { + if (section.header.type != elf::SHT_RELA) { + continue; + } + + auto name = std::string { shStrTab + section.header.name }; + + if (name.compare(".rela.dyn") == 0) { + // Skip dyn relocations + continue; + } + + auto symTab = reinterpret_cast(inSections[section.header.link].data.data()); + auto relTab = reinterpret_cast(section.data.data()); + auto count = section.data.size() / sizeof(elf::Rela); + + for (auto i = 0u; i < count; ++i) { + auto relocation = new ElfFile::Relocation(); + auto &rela = relTab[i]; + + auto type = rela.info & 0xff; + auto index = rela.info >> 8; + auto &sym = symTab[index]; + auto symType = sym.info & 0xf; + + if (symType == elf::STT_SECTION && sym.value == CodeAddress) { + if (rela.offset < CodeAddress || rela.offset >= DataAddress) { + std::cout << "Unexpected symbol referenced in relocation section " << name << std::endl; + return false; + } + } + + auto addend = static_cast(rela.addend); + + if (auto import = findImport(file, addend)) { + relocation->symbol = import->stubSymbol; + relocation->addend = 0; + } else if (auto symbol = findSymbol(file, addend)) { + relocation->symbol = symbol; + relocation->addend = 0; + } else if (addend >= DataAddress && addend < WiiuLoadAddress) { + relocation->symbol = findSymbol(file, DataAddress); + relocation->addend = addend - DataAddress; + } else if (addend >= CodeAddress && addend < DataAddress) { + relocation->symbol = findSymbol(file, CodeAddress); + relocation->addend = addend - CodeAddress; + } else { + // If we can't find a proper symbol, write the addend in and hope for the best + auto ptr = getLoaderDataPtr(inSections, rela.offset); + *ptr = addend; + + std::cout << "Unexpected addend " << std::hex << addend << " referenced in relocation section " << name << ", continuing." << std::endl; + continue; + } + + relocation->target = rela.offset; + relocation->type = static_cast(type); + file.relocations.emplace_back(relocation); + } + } + + // Read dyn relocations + for (auto §ion : inSections) { + if (section.header.type != elf::SHT_RELA) { + continue; + } + + auto name = std::string { shStrTab + section.header.name }; + + if (name.compare(".rela.dyn") != 0) { + continue; + } + + auto symSection = inSections[section.header.link]; + auto relas = reinterpret_cast(section.data.data()); + auto count = section.data.size() / sizeof(elf::Rela); + + for (auto i = 0u; i < count; ++i) { + auto relocation = new ElfFile::Relocation(); + auto &rela = relas[i]; + + auto type = rela.info & 0xff; + auto index = rela.info >> 8; + auto symbol = getSectionSymbol(symSection, index); + auto addr = symbol->value + rela.addend; + + if(type == elf::R_PPC_NONE) + { + // ignore padding + continue; + } + + if(index == 0) + { + auto addend = static_cast(rela.addend); + + if (auto import = findImport(file, addend)) { + relocation->symbol = import->stubSymbol; + relocation->addend = 0; + } else if (auto symbol = findSymbol(file, addend)) { + relocation->symbol = symbol; + relocation->addend = 0; + } else if (addr >= CodeAddress && addr < DataAddress) { + index = 1; + relocation->symbol = findSymbol(file, CodeAddress); + relocation->addend = rela.addend - CodeAddress; + } else if (addr >= DataAddress && addr < WiiuLoadAddress) { + index = 2; + relocation->symbol = findSymbol(file, DataAddress); + relocation->addend = rela.addend - DataAddress; + } else { + std::cout << "Unexpected symbol address in .rela.dyn section" << std::endl; + return false; + } + } + + switch (type) { + case elf::R_PPC_RELATIVE: + type = elf::R_PPC_ADDR32; + break; + default: + std::cout << "Unexpected relocation type in .rela.dyn section" << std::endl; + return false; + } + + relocation->target = rela.offset; + relocation->type = static_cast(type); + + // Scrap any compiler/linker garbage + if(relocation->target >= CodeAddress && relocation->target < WiiuLoadAddress) + file.relocations.emplace_back(relocation); + } + } + + return true; +} + +struct OutputSection +{ + std::string name; + elf::SectionHeader header; + std::vector data; + OutputSection *relocationSection = nullptr; + ElfFile::Symbol *sectionSymbol = nullptr; +}; + +template +SymbolIterator addSection(ElfFile &file, std::vector &outSections, SymbolIterator symbolIterator, OutputSection *section) +{ + auto sectionSymbol = new ElfFile::Symbol(); + sectionSymbol->name = section->name; + sectionSymbol->address = section->header.addr; + sectionSymbol->size = -1; + sectionSymbol->type = elf::STT_SECTION; + sectionSymbol->binding = elf::STB_LOCAL; + section->sectionSymbol = sectionSymbol; + outSections.push_back(section); + return file.symbols.insert(symbolIterator, std::unique_ptr { sectionSymbol }) + 1; +}; + +static uint32_t +getSectionIndex(std::vector &outSections, uint32_t address) +{ + for (auto i = 0u; i < outSections.size(); ++i) { + auto §ion = outSections[i]; + auto start = section->header.addr; + auto end = start + section->header.size; + + if (address >= start && address < end) { + return i; + } + } + + return -1; +} + +static uint32_t +getSectionIndex(std::vector &outSections, const std::string &name) +{ + for (auto i = 0u; i < outSections.size(); ++i) { + auto §ion = outSections[i]; + + if (section->name.compare(name) == 0) { + return i; + } + } + + return -1; +} + +static bool +write(ElfFile &file, const std::string &filename) +{ + std::vector outSections; + auto sectionSymbolItr = file.symbols.begin() + 4; + + // Create NULL section + auto nullSection = new OutputSection(); + memset(&nullSection->header, 0, sizeof(elf::SectionHeader)); + outSections.push_back(nullSection); + + // Create text/data sections + for (auto §ion : file.dataSections) { + auto out = new OutputSection(); + out->header.name = -1; + out->header.type = section->type; + out->header.flags = section->flags; + out->header.addr = section->address; + out->header.offset = -1; + + if (section->type == elf::SHT_NOBITS) { + out->header.size = section->size; + } else { + out->header.size = section->data.size(); + } + + out->header.link = 0; + out->header.info = 0; + + if (section->address == DataAddress) { + out->header.addralign = 4096; + out->header.flags |= elf::SHF_WRITE; // .rodata needs to be writable? + } else { + out->header.addralign = 256; + } + + out->header.entsize = 0; + + // Add section + out->name = section->name; + out->data = section->data; + sectionSymbolItr = addSection(file, outSections, sectionSymbolItr, out); + } + + // Create relocation sections + for (auto &relocation : file.relocations) { + OutputSection *targetSection = nullptr; + + for (auto §ion : outSections) { + auto start = section->header.addr; + auto end = start + section->header.size; + + if (relocation->target >= start && relocation->target < end) { + targetSection = section; + break; + } + } + + if (!targetSection) { + std::cout << "Error could not find section for relocation" << std::endl; + return false; + } + + if (!targetSection->relocationSection) { + // Create new relocation section + auto out = new OutputSection(); + out->header.name = -1; + out->header.type = elf::SHT_RELA; + out->header.flags = 0; + out->header.addr = 0; + out->header.offset = -1; + out->header.size = -1; + out->header.link = -1; + out->header.info = getSectionIndex(outSections, targetSection->header.addr); + out->header.addralign = 4; + out->header.entsize = sizeof(elf::Rela); + + // Add section + out->name = ".rela" + targetSection->name; + sectionSymbolItr = addSection(file, outSections, sectionSymbolItr, out); + targetSection->relocationSection = out; + } + } + + // Calculate sizes of symbol/string tables so RPL imports are placed after them + auto loadAddress = 0xC0000000; + auto predictStrTabSize = 1; + auto predictSymTabSize = 1; + auto predictShstrTabSize = 1; + + for (auto &symbol : file.symbols) { + predictStrTabSize += symbol->name.size() + 1; + predictSymTabSize += sizeof(elf::Symbol); + } + + for (auto §ion : outSections) { + predictShstrTabSize += section->name.size() + 1; + } + + predictStrTabSize = align_up(predictStrTabSize, 0x10); + predictSymTabSize = align_up(predictSymTabSize, 0x10); + predictShstrTabSize = align_up(predictShstrTabSize, 0x10); + loadAddress += predictStrTabSize + predictSymTabSize + predictShstrTabSize; + + // Create RPL import sections, .fimport_*, .dimport_* + for (auto &lib : file.rplImports) { + auto out = new OutputSection(); + out->header.name = -1; + out->header.type = elf::SHT_RPL_IMPORTS; + out->header.flags = elf::SHF_ALLOC | elf::SHF_EXECINSTR; + out->header.addr = loadAddress; + out->header.offset = -1; + out->header.link = 0; + out->header.info = 0; + out->header.addralign = 4; + out->header.entsize = 0; + out->name = ".fimport_" + lib->name; + + // Calculate size + auto nameSize = align_up(8 + lib->name.size(), 8); + auto stubSize = 8 + 8 * lib->imports.size(); + out->header.size = std::max(nameSize, stubSize); + out->data.resize(out->header.size); + + // Setup data + auto imports = reinterpret_cast(out->data.data()); + imports->count = lib->imports.size(); + imports->signature = crc32(0, Z_NULL, 0); + memcpy(imports->name, lib->name.data(), lib->name.size()); + imports->name[lib->name.size()] = 0; + + // Update address of import symbols + for (auto i = 0u; i < lib->imports.size(); ++i) { + lib->imports[i]->stubSymbol->address = loadAddress + 8 + i * 8; + } + + loadAddress = align_up(loadAddress + out->header.size, 4); + + // Add section + sectionSymbolItr = addSection(file, outSections, sectionSymbolItr, out); + } + + // Prune out unneeded symbols + for (auto i = 0u; i < file.symbols.size(); ++i) { + if (!file.symbols[i]->name.empty() && file.symbols[i]->type == elf::STT_NOTYPE && file.symbols[i]->size == 0) { + file.symbols.erase(file.symbols.begin() + i); + i--; + } + } + + // NOTICE: FROM NOW ON DO NOT MODIFY mSymbols + + // Convert relocations + for (auto &relocation : file.relocations) { + OutputSection *targetSection = nullptr; + + for (auto §ion : outSections) { + auto start = section->header.addr; + auto end = start + section->header.size; + + if (relocation->target >= start && relocation->target < end) { + targetSection = section; + break; + } + } + + if (!targetSection || !targetSection->relocationSection) { + std::cout << "Error could not find section for relocation" << std::endl; + return false; + } + + // Get address of relocation->target + auto relocationSection = targetSection->relocationSection; + + // Find symbol this relocation points to + auto itr = std::find_if(file.symbols.begin(), file.symbols.end(), [&relocation](auto &val) { + return val.get() == relocation->symbol; + }); + + auto idx = itr - file.symbols.begin(); + + // If the symbol doesn't exist but it is within DATA or TEXT, use those symbols + an addend + if (itr == file.symbols.end()) { + if (relocation->symbol->address >= CodeAddress && relocation->symbol->address < DataAddress) { + idx = 1; + relocation->addend = relocation->symbol->address - CodeAddress; + relocation->symbol = findSymbol(file, CodeAddress); + } else if (relocation->symbol->address >= DataAddress && relocation->symbol->address < WiiuLoadAddress) { + idx = 2; + relocation->addend = relocation->symbol->address - DataAddress; + relocation->symbol = findSymbol(file, DataAddress); + } else { + std::cout << "Could not find matching symbol for relocation" << std::endl; + return false; + } + } + + // Create relocation + elf::Rela rela; + rela.info = relocation->type | idx << 8; + + if(relocation->type == elf::R_PPC_RELATIVE) { + rela.info = elf::R_PPC_ADDR32 | idx << 8; + } + + rela.addend = relocation->addend; + rela.offset = relocation->target; + + // Append to relocation section data + char *relaData = reinterpret_cast(&rela); + relocationSection->data.insert(relocationSection->data.end(), relaData, relaData + sizeof(elf::Rela)); + } + + // String + Symbol sections + auto symTabSection = new OutputSection(); + auto strTabSection = new OutputSection(); + auto shStrTabSection = new OutputSection(); + + symTabSection->name = ".symtab"; + strTabSection->name = ".strtab"; + shStrTabSection->name = ".shstrtab"; + + auto symTabIndex = outSections.size(); + outSections.push_back(symTabSection); + + auto strTabIndex = outSections.size(); + outSections.push_back(strTabSection); + + auto shStrTabIndex = outSections.size(); + outSections.push_back(shStrTabSection); + + // Update relocation sections to link to symtab + for (auto §ion : outSections) { + if (section->header.type == elf::SHT_RELA) { + section->header.link = symTabIndex; + } + + if (section->header.type != elf::SHT_NOBITS) { + section->header.size = section->data.size(); + } + + if (section->sectionSymbol) { + section->sectionSymbol->address = section->header.addr; + section->sectionSymbol->size = section->header.size; + } + } + + // Create .strtab + strTabSection->header.name = 0; + strTabSection->header.type = elf::SHT_STRTAB; + strTabSection->header.flags = elf::SHF_ALLOC; + strTabSection->header.addr = 0; + strTabSection->header.offset = -1; + strTabSection->header.size = -1; + strTabSection->header.link = 0; + strTabSection->header.info = 0; + strTabSection->header.addralign = 1; + strTabSection->header.entsize = 0; + + // Add all symbol names to data, update symbol->outNamePos + strTabSection->data.push_back(0); + + for (auto &symbol : file.symbols) { + if (symbol->name.empty()) { + symbol->outNamePos = 0; + } else { + symbol->outNamePos = static_cast(strTabSection->data.size()); + std::copy(symbol->name.begin(), symbol->name.end(), std::back_inserter(strTabSection->data)); + strTabSection->data.push_back(0); + } + } + + // Create .symtab + symTabSection->header.name = 0; + symTabSection->header.type = elf::SHT_SYMTAB; + symTabSection->header.flags = elf::SHF_ALLOC; + symTabSection->header.addr = 0; + symTabSection->header.offset = -1; + symTabSection->header.size = -1; + symTabSection->header.link = strTabIndex; + symTabSection->header.info = 0; + symTabSection->header.addralign = 4; + symTabSection->header.entsize = sizeof(elf::Symbol); + + for (auto &symbol : file.symbols) { + elf::Symbol sym; + auto shndx = getSectionIndex(outSections, symbol->address); + + if (symbol->type == elf::STT_SECTION && symbol->address == 0) { + shndx = getSectionIndex(outSections, symbol->name); + } + + if (shndx == (uint32_t)-1) { + std::cout << "Could not find section for symbol" << std::endl; + return false; + } + + sym.name = symbol->outNamePos; + sym.value = symbol->address; + sym.size = symbol->size; + sym.info = symbol->type | (symbol->binding << 4); + sym.other = 0; + sym.shndx = shndx; + + //Compound symbol crc into section crc + auto crcSection = outSections[shndx]; + if(crcSection->header.type == elf::SHT_RPL_IMPORTS && symbol->type != elf::STT_SECTION) { + auto rplImport = reinterpret_cast(crcSection->data.data()); + rplImport->signature = crc32(rplImport->signature, reinterpret_cast(strTabSection->data.data() + sym.name),strlen(strTabSection->data.data() + sym.name)+1); + } + + // Append to symtab data + char *symData = reinterpret_cast(&sym); + symTabSection->data.insert(symTabSection->data.end(), symData, symData + sizeof(elf::Symbol)); + } + + //Finish SHT_RPL_IMPORTS signatures + Bytef *zero_buffer = reinterpret_cast(calloc(0x10, 1)); + for (auto §ion : outSections) { + if(section->header.type == elf::SHT_RPL_IMPORTS) { + auto rplImport = reinterpret_cast(section->data.data()); + rplImport->signature = crc32(rplImport->signature, zero_buffer, 0xE); + } + } + free(zero_buffer); + + // Create .shstrtab + shStrTabSection->header.name = 0; + shStrTabSection->header.type = elf::SHT_STRTAB; + shStrTabSection->header.flags = elf::SHF_ALLOC; + shStrTabSection->header.addr = 0; + shStrTabSection->header.offset = -1; + shStrTabSection->header.size = -1; + shStrTabSection->header.link = 0; + shStrTabSection->header.info = 0; + shStrTabSection->header.addralign = 1; + shStrTabSection->header.entsize = 0; + + // Add all section header names to data, update section->header.name + shStrTabSection->data.push_back(0); + + for (auto §ion : outSections) { + if (section->name.empty()) { + section->header.name = 0; + } else { + section->header.name = shStrTabSection->data.size(); + std::copy(section->name.begin(), section->name.end(), std::back_inserter(shStrTabSection->data)); + shStrTabSection->data.push_back(0); + } + } + + loadAddress = 0xC0000000; + + // Update symtab, strtab, shstrtab section addresses + symTabSection->header.addr = loadAddress; + symTabSection->header.size = symTabSection->data.size(); + + loadAddress = align_up(symTabSection->header.addr + predictSymTabSize, 16); + strTabSection->header.addr = loadAddress; + strTabSection->header.size = strTabSection->data.size(); + + loadAddress = align_up(strTabSection->header.addr + predictStrTabSize, 16); + shStrTabSection->header.addr = loadAddress; + shStrTabSection->header.size = shStrTabSection->data.size(); + + // Create SHT_RPL_FILEINFO section + auto fileInfoSection = new OutputSection(); + fileInfoSection->header.name = 0; + fileInfoSection->header.type = elf::SHT_RPL_FILEINFO; + fileInfoSection->header.flags = 0; + fileInfoSection->header.addr = 0; + fileInfoSection->header.offset = -1; + fileInfoSection->header.size = -1; + fileInfoSection->header.link = 0; + fileInfoSection->header.info = 0; + fileInfoSection->header.addralign = 4; + fileInfoSection->header.entsize = 0; + + elf::RplFileInfo fileInfo; + fileInfo.version = 0xCAFE0402; + fileInfo.textSize = 0; + fileInfo.textAlign = 32; + fileInfo.dataSize = 0; + fileInfo.dataAlign = 4096; + fileInfo.loadSize = 0; + fileInfo.loadAlign = 4; + fileInfo.tempSize = 0; + fileInfo.trampAdjust = 0; + fileInfo.trampAddition = 0; + fileInfo.sdaBase = 0; + fileInfo.sda2Base = 0; + fileInfo.stackSize = 0x10000; + fileInfo.heapSize = 0x8000; + fileInfo.filename = 0; + fileInfo.flags = elf::RPL_IS_RPX; + fileInfo.minVersion = 0x5078; + fileInfo.compressionLevel = -1; + fileInfo.fileInfoPad = 0; + fileInfo.cafeSdkVersion = 0x51BA; + fileInfo.cafeSdkRevision = 0xCCD1; + fileInfo.tlsAlignShift = 0; + fileInfo.tlsModuleIndex = 0; + fileInfo.runtimeFileInfoSize = 0; + fileInfo.tagOffset = 0; + + // Count file info textSize, dataSize, loadSize + for (auto §ion : outSections) { + auto size = section->data.size(); + + if (section->header.type == elf::SHT_NOBITS) { + size = section->header.size; + } + + if (section->header.addr >= CodeAddress && section->header.addr < DataAddress) { + auto val = section->header.addr.value() + section->header.size.value() - CodeAddress; + if(val > fileInfo.textSize) { + fileInfo.textSize = val; + } + } else if (section->header.addr >= DataAddress && section->header.addr < WiiuLoadAddress) { + auto val = section->header.addr.value() + section->header.size.value() - DataAddress; + if(val > fileInfo.dataSize) { + fileInfo.dataSize = val; + } + } else if (section->header.addr >= WiiuLoadAddress) { + auto val = section->header.addr.value() + section->header.size.value() - WiiuLoadAddress; + if(val > fileInfo.loadSize) { + fileInfo.loadSize = val; + } + } else if (section->header.addr == 0 && section->header.type != elf::SHT_RPL_CRCS && section->header.type != elf::SHT_RPL_FILEINFO) { + fileInfo.tempSize += (size + 128); + } + } + + //TODO: These were calculated based on observation, however some games differ. + fileInfo.sdaBase = align_up(DataAddress + fileInfo.dataSize + fileInfo.heapSize, 64); + fileInfo.sda2Base = align_up(DataAddress + fileInfo.heapSize, 64); + + char *fileInfoData = reinterpret_cast(&fileInfo); + fileInfoSection->data.insert(fileInfoSection->data.end(), fileInfoData, fileInfoData + sizeof(elf::RplFileInfo)); + + // Create SHT_RPL_CRCS section + auto crcSection = new OutputSection(); + crcSection->header.name = 0; + crcSection->header.type = elf::SHT_RPL_CRCS; + crcSection->header.flags = 0; + crcSection->header.addr = 0; + crcSection->header.offset = -1; + crcSection->header.size = -1; + crcSection->header.link = 0; + crcSection->header.info = 0; + crcSection->header.addralign = 4; + crcSection->header.entsize = 4; + + outSections.push_back(crcSection); + outSections.push_back(fileInfoSection); + + std::vector sectionCRCs; + + for (auto §ion : outSections) { + auto crc = 0u; + + if (!section->data.empty()) { + crc = crc32(0, Z_NULL, 0); + crc = crc32(crc, reinterpret_cast(section->data.data()), section->data.size()); + } + + sectionCRCs.push_back(byte_swap(crc)); + } + + char *crcData = reinterpret_cast(sectionCRCs.data()); + crcSection->data.insert(crcSection->data.end(), crcData, crcData + sizeof(uint32_t) * sectionCRCs.size()); + + // Update section sizes and offsets + auto shoff = align_up(sizeof(elf::Header), 64); + auto dataOffset = align_up(shoff + outSections.size() * sizeof(elf::SectionHeader), 64); + + // Add CRC and FileInfo sections first + for (auto §ion : outSections) { + if (section->header.type != elf::SHT_RPL_CRCS && section->header.type != elf::SHT_RPL_FILEINFO) { + continue; + } + + if (section->header.type != elf::SHT_NOBITS) { + section->header.size = section->data.size(); + } + + if (!section->data.empty()) { + section->header.offset = dataOffset; + dataOffset = align_up(section->header.offset + section->data.size(), 64); + } else { + section->header.offset = 0; + } + } + + // Add data sections next + for (auto §ion : outSections) { + if(section->header.offset != -1) { + continue; + } + + if (section->header.addr < DataAddress || section->header.addr >= WiiuLoadAddress) { + continue; + } + + if (section->header.type != elf::SHT_NOBITS) { + section->header.size = section->data.size(); + } + + if (!section->data.empty()) { + section->header.offset = dataOffset; + dataOffset = align_up(section->header.offset + section->data.size(), 64); + } else { + section->header.offset = 0; + } + } + + // Add load sections next + for (auto §ion : outSections) { + if(section->header.offset != -1) { + continue; + } + + if (section->header.addr < WiiuLoadAddress) { + continue; + } + + if (section->header.type != elf::SHT_NOBITS) { + section->header.size = section->data.size(); + } + + if (!section->data.empty()) { + section->header.offset = dataOffset; + dataOffset = align_up(section->header.offset + section->data.size(), 64); + } else { + section->header.offset = 0; + } + } + + // Everything else + for (auto §ion : outSections) { + if(section->header.offset != -1) { + continue; + } + + if (section->header.type != elf::SHT_NOBITS) { + section->header.size = section->data.size(); + } + + if (!section->data.empty()) { + section->header.offset = dataOffset; + dataOffset = align_up(section->header.offset + section->data.size(), 64); + } else { + section->header.offset = 0; + } + } + + // Write to file + std::ofstream out { filename, std::ofstream::binary }; + std::vector padding; + + if (!out.is_open()) { + std::cout << "Could not open " << filename << " for writing" << std::endl; + return false; + } + + elf::Header header; + header.magic = elf::HeaderMagic; + header.fileClass = 1; + header.encoding = elf::ELFDATA2MSB; + header.elfVersion = elf::EV_CURRENT; + header.abi = elf::EABI_CAFE; + memset(&header.pad, 0, 7); + header.type = 0xFE01; + header.machine = elf::EM_PPC; + header.version = 1; + header.entry = file.entryPoint; + header.phoff = 0; + header.phentsize = 0; + header.phnum = 0; + header.shoff = shoff; + header.shnum = outSections.size(); + header.shentsize = sizeof(elf::SectionHeader); + header.flags = 0; + header.ehsize = sizeof(elf::Header); + header.shstrndx = shStrTabIndex; + out.write(reinterpret_cast(&header), sizeof(elf::Header)); + + // Write section headers + out.seekp(header.shoff.value()); + + for (auto §ion : outSections) { + out.write(reinterpret_cast(§ion->header), sizeof(elf::SectionHeader)); + } + + // Write section data + for (auto §ion : outSections) { + if (!section->data.empty()) { + out.seekp(section->header.offset.value()); + out.write(section->data.data(), section->data.size()); + } + } + + return true; +} + +int main(int argc, char **argv) +{ + if (argc < 3) { + std::cout << "Usage: " << argv[0] << " " << std::endl; + return -1; + } + + ElfFile elf; + auto src = argv[1]; + auto dst = argv[2]; + + if (!read(elf, src)) { + return -1; + } + + if (!write(elf, dst)) { + return -1; + } + + return 0; +} diff --git a/wiiu/wut/elf2rpl/utils.h b/wiiu/wut/elf2rpl/utils.h new file mode 100644 index 0000000000..817dff3427 --- /dev/null +++ b/wiiu/wut/elf2rpl/utils.h @@ -0,0 +1,119 @@ +#pragma once +#include +#include + +#if defined(WIN32) || defined(_WIN32) || defined(_MSC_VER) +#define PLATFORM_WINDOWS +#elif __APPLE__ +#define PLATFORM_APPLE +#define PLATFORM_POSIX +#elif __linux__ +#define PLATFORM_LINUX +#define PLATFORM_POSIX +#endif + +#ifdef PLATFORM_LINUX +#include +#endif + +// reinterpret_cast for value types +template +inline DstType +bit_cast(const SrcType& src) +{ + static_assert(sizeof(SrcType) == sizeof(DstType), "bit_cast must be between same sized types"); + static_assert(std::is_trivially_copyable::value, "SrcType is not trivially copyable."); + static_assert(std::is_trivially_copyable::value, "DstType is not trivially copyable."); + + DstType dst; + std::memcpy(&dst, &src, sizeof(SrcType)); + return dst; +} + +// Utility class to swap endian for types of size 1, 2, 4, 8 +// other type sizes are not supported +template +struct byte_swap_t; + +template +struct byte_swap_t +{ + static Type swap(Type src) + { + return src; + } +}; + +template +struct byte_swap_t +{ + static Type swap(Type src) + { +#ifdef PLATFORM_WINDOWS + return bit_cast(_byteswap_ushort(bit_cast(src))); +#elif defined(PLATFORM_APPLE) + // Apple has no 16-bit byteswap intrinsic + const uint16_t data = bit_cast(src); + return bit_cast((uint16_t)((data >> 8) | (data << 8))); +#elif defined(PLATFORM_LINUX) + return bit_cast(bswap_16(bit_cast(src))); +#endif + } +}; + +template +struct byte_swap_t +{ + static Type swap(Type src) + { +#ifdef PLATFORM_WINDOWS + return bit_cast(_byteswap_ulong(bit_cast(src))); +#elif defined(PLATFORM_APPLE) + return bit_cast(__builtin_bswap32(bit_cast(src))); +#elif defined(PLATFORM_LINUX) + return bit_cast(bswap_32(bit_cast(src))); +#endif + } +}; + +template +struct byte_swap_t +{ + static Type swap(Type src) + { +#ifdef PLATFORM_WINDOWS + return bit_cast(_byteswap_uint64(bit_cast(src))); +#elif defined(PLATFORM_APPLE) + return bit_cast(__builtin_bswap64(bit_cast(src))); +#elif defined(PLATFORM_LINUX) + return bit_cast(bswap_64(bit_cast(src))); +#endif + } +}; + +// Swaps endian of src +template +inline Type +byte_swap(Type src) +{ + return byte_swap_t::swap(src); +} + +// Alignment helpers +template +constexpr inline Type +align_up(Type value, size_t alignment) +{ + return static_cast((static_cast(value) + (alignment - 1)) & ~(alignment - 1)); +} + +template +constexpr inline Type +align_down(Type value, size_t alignment) +{ + return static_cast(static_cast(value) & ~(alignment - 1)); +} + +#define CHECK_SIZE(Type, Size) \ + static_assert(sizeof(Type) == Size, \ + #Type " must be " #Size " bytes") diff --git a/wiiu/wut/include/coreinit/alarm.h b/wiiu/wut/include/coreinit/alarm.h new file mode 100644 index 0000000000..12426aa7d1 --- /dev/null +++ b/wiiu/wut/include/coreinit/alarm.h @@ -0,0 +1,230 @@ +#pragma once +#include +#include "thread.h" +#include "threadqueue.h" +#include "time.h" + +/** + * \defgroup coreinit_alarms Alarms + * \ingroup coreinit + * + * The alarm family of functions are used for creating alarms which call + * a callback or wake up waiting threads after a period of time. + * + * Alarms can be one shot alarms which trigger once after a period of time, + * or periodic which trigger at regular intervals until they are cancelled. + * + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OSAlarm OSAlarm; +typedef struct OSAlarmLink OSAlarmLink; +typedef struct OSAlarmQueue OSAlarmQueue; + +typedef void (*OSAlarmCallback)(OSAlarm *, OSContext *); + +#define OS_ALARM_QUEUE_TAG 0x614C6D51u + +struct OSAlarmQueue +{ + //! Should always be set to the value OS_ALARM_QUEUE_TAG. + uint32_t tag; + + //! Name set by OSInitAlarmQueueEx + const char *name; + UNKNOWN(4); + + OSThreadQueue threadQueue; + OSAlarm *head; + OSAlarm *tail; +}; +CHECK_OFFSET(OSAlarmQueue, 0x00, tag); +CHECK_OFFSET(OSAlarmQueue, 0x04, name); +CHECK_OFFSET(OSAlarmQueue, 0x0c, threadQueue); +CHECK_OFFSET(OSAlarmQueue, 0x1c, head); +CHECK_OFFSET(OSAlarmQueue, 0x20, tail); +CHECK_SIZE(OSAlarmQueue, 0x24); + +struct OSAlarmLink +{ + OSAlarm *prev; + OSAlarm *next; +}; +CHECK_OFFSET(OSAlarmLink, 0x00, prev); +CHECK_OFFSET(OSAlarmLink, 0x04, next); +CHECK_SIZE(OSAlarmLink, 0x08); + +#define OS_ALARM_TAG 0x614C724Du +struct OSAlarm +{ + //! Should always be set to the value OS_ALARM_TAG. + uint32_t tag; + + //! Name set from OSCreateAlarmEx. + const char *name; + + UNKNOWN(4); + + //! The callback to execute once the alarm is triggered. + OSAlarmCallback callback; + + //! Used with OSCancelAlarms for bulk cancellation of alarms. + uint32_t group; + + UNKNOWN(4); + + //! The time when the alarm will next be triggered. + OSTime nextFire; + + //! Link used for when this OSAlarm object is inside an OSAlarmQueue + OSAlarmLink link; + + //! The period between alarm triggers, this is only set for periodic alarms. + OSTime period; + + //! The time the alarm was started. + OSTime start; + + //! User data set with OSSetAlarmUserData and retrieved with OSGetAlarmUserData. + void *userData; + + //! The current state of the alarm, internal values. + uint32_t state; + + //! Queue of threads currently waiting for the alarm to trigger with OSWaitAlarm. + OSThreadQueue threadQueue; + + //! The queue that this alarm is currently in. + OSAlarmQueue *alarmQueue; + + //! The context the alarm was triggered on. + OSContext *context; +}; +CHECK_OFFSET(OSAlarm, 0x00, tag); +CHECK_OFFSET(OSAlarm, 0x04, name); +CHECK_OFFSET(OSAlarm, 0x0c, callback); +CHECK_OFFSET(OSAlarm, 0x10, group); +CHECK_OFFSET(OSAlarm, 0x18, nextFire); +CHECK_OFFSET(OSAlarm, 0x20, link); +CHECK_OFFSET(OSAlarm, 0x28, period); +CHECK_OFFSET(OSAlarm, 0x30, start); +CHECK_OFFSET(OSAlarm, 0x38, userData); +CHECK_OFFSET(OSAlarm, 0x3c, state); +CHECK_OFFSET(OSAlarm, 0x40, threadQueue); +CHECK_OFFSET(OSAlarm, 0x50, alarmQueue); +CHECK_OFFSET(OSAlarm, 0x54, context); +CHECK_SIZE(OSAlarm, 0x58); + + +/** + * Cancel an alarm. + */ +BOOL +OSCancelAlarm(OSAlarm *alarm); + + +/** + * Cancel all alarms which have a matching tag set by OSSetAlarmTag. + * + * \param group The alarm tag to cancel. + */ +void +OSCancelAlarms(uint32_t group); + + +/** + * Initialise an alarm structure. + */ +void +OSCreateAlarm(OSAlarm *alarm); + + +/** + * Initialise an alarm structure with a name. + */ +void +OSCreateAlarmEx(OSAlarm *alarm, + const char *name); + + +/** + * Return user data set by OSSetAlarmUserData. + */ +void * +OSGetAlarmUserData(OSAlarm *alarm); + + +/** + * Initialise an alarm queue structure. + */ +void +OSInitAlarmQueue(OSAlarmQueue *queue); + + +/** + * Initialise an alarm queue structure with a name. + */ +void +OSInitAlarmQueueEx(OSAlarmQueue *queue, + const char *name); + + +/** + * Set a one shot alarm to perform a callback after a set amount of time. + * + * \param alarm The alarm to set. + * \param time The duration until the alarm should be triggered. + * \param callback The alarm callback to call when the alarm is triggered. + */ +BOOL +OSSetAlarm(OSAlarm *alarm, + OSTime time, + OSAlarmCallback callback); + + +/** + * Set a repeated alarm to execute a callback every interval from start. + * + * \param alarm The alarm to set. + * \param start The duration until the alarm should first be triggered. + * \param interval The interval between triggers after the first trigger. + * \param callback The alarm callback to call when the alarm is triggered. + */ +BOOL +OSSetPeriodicAlarm(OSAlarm *alarm, + OSTime start, + OSTime interval, + OSAlarmCallback callback); + + +/** + * Set an alarm tag which is used in OSCancelAlarms for bulk cancellation. + */ +void +OSSetAlarmTag(OSAlarm *alarm, + uint32_t group); + + +/** + * Set alarm user data which is returned by OSGetAlarmUserData. + */ +void +OSSetAlarmUserData(OSAlarm *alarm, + void *data); + + +/** + * Sleep the current thread until the alarm has been triggered or cancelled. + */ +BOOL +OSWaitAlarm(OSAlarm *alarm); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/atomic64.h b/wiiu/wut/include/coreinit/atomic64.h new file mode 100644 index 0000000000..16d528bb1e --- /dev/null +++ b/wiiu/wut/include/coreinit/atomic64.h @@ -0,0 +1,66 @@ +#pragma once +#include + +/** + * \defgroup coreinit_atomic64 Atomic 64 bit + * \ingroup coreinit + * + * These functions are used for atomically operating on 64 bit values in memory. + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +uint64_t +OSGetAtomic64(uint64_t *ptr); + +uint64_t +OSSetAtomic64(uint64_t *ptr, + uint64_t value); + +BOOL +OSCompareAndSwapAtomic64(uint64_t *ptr, + uint64_t compare, + uint64_t value); + +BOOL +OSCompareAndSwapAtomicEx64(uint64_t *ptr, + uint64_t compare, + uint64_t value, + uint64_t *old); + +uint64_t +OSSwapAtomic64(uint64_t *ptr, + uint64_t value); + +int64_t +OSAddAtomic64(int64_t *ptr, + int64_t value); + +uint64_t +OSAndAtomic64(uint64_t *ptr, + uint64_t value); + +uint64_t +OSOrAtomic64(uint64_t *ptr, + uint64_t value); + +uint64_t +OSXorAtomic64(uint64_t *ptr, + uint64_t value); + +BOOL +OSTestAndClearAtomic64(uint64_t *ptr, + uint32_t bit); + +BOOL +OSTestAndSetAtomic64(uint64_t *ptr, + uint32_t bit); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/baseheap.h b/wiiu/wut/include/coreinit/baseheap.h new file mode 100644 index 0000000000..3993c2e5e2 --- /dev/null +++ b/wiiu/wut/include/coreinit/baseheap.h @@ -0,0 +1,46 @@ +#pragma once +#include + +/** + * \defgroup coreinit_baseheap Base Heap + * \ingroup coreinit + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void *MEMHeapHandle; + +typedef enum MEMBaseHeapType +{ + MEM_BASE_HEAP_MEM1 = 0, + MEM_BASE_HEAP_MEM2 = 1, + MEM_BASE_HEAP_FG = 8, +} MEMBaseHeapType; + +/** + * Get which memory area a heap belongs to. + */ +MEMBaseHeapType +MEMGetArena(MEMHeapHandle handle); + +/** + * Get base heap for memory area. + */ +MEMHeapHandle +MEMGetBaseHeapHandle(MEMBaseHeapType type); + +/** + * Set base heap for memory area. + */ +MEMHeapHandle +MEMSetBaseHeapHandle(MEMBaseHeapType type, + MEMHeapHandle handle); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/blockheap.h b/wiiu/wut/include/coreinit/blockheap.h new file mode 100644 index 0000000000..d4d5c33208 --- /dev/null +++ b/wiiu/wut/include/coreinit/blockheap.h @@ -0,0 +1,132 @@ +#pragma once +#include +#include "memheap.h" + +/** + * \defgroup coreinit_blockheap Block Heap + * \ingroup coreinit + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct MEMBlockHeapBlock MEMBlockHeapBlock; +typedef struct MEMBlockHeapTracking MEMBlockHeapTracking; +typedef struct MEMBlockHeap MEMBlockHeap; + +struct MEMBlockHeapTracking +{ + UNKNOWN(0x8); + + //! Pointer to first memory block + MEMBlockHeapBlock *blocks; + + //! Number of blocks in this tracking heap + uint32_t blockCount; +}; +CHECK_OFFSET(MEMBlockHeapTracking, 0x08, blocks); +CHECK_OFFSET(MEMBlockHeapTracking, 0x0C, blockCount); +CHECK_SIZE(MEMBlockHeapTracking, 0x10); + +struct MEMBlockHeapBlock +{ + //! First address of the data region this block has allocated + void *start; + + //! End address of the data region this block has allocated + void *end; + + //! TRUE if the block is free, FALSE if allocated + BOOL isFree; + + //! Link to previous block, note that this is only set for allocated blocks + MEMBlockHeapBlock *prev; + + //! Link to next block, always set + MEMBlockHeapBlock *next; +}; +CHECK_OFFSET(MEMBlockHeapBlock, 0x00, start); +CHECK_OFFSET(MEMBlockHeapBlock, 0x04, end); +CHECK_OFFSET(MEMBlockHeapBlock, 0x08, isFree); +CHECK_OFFSET(MEMBlockHeapBlock, 0x0c, prev); +CHECK_OFFSET(MEMBlockHeapBlock, 0x10, next); +CHECK_SIZE(MEMBlockHeapBlock, 0x14); + +struct MEMBlockHeap +{ + MEMHeapHeader header; + + //! Default tracking heap, tracks only defaultBlock + MEMBlockHeapTracking defaultTrack; + + //! Default block, used so we don't have an empty block list + MEMBlockHeapBlock defaultBlock; + + //! First block in this heap + MEMBlockHeapBlock *firstBlock; + + //! Last block in this heap + MEMBlockHeapBlock *lastBlock; + + //! First free block + MEMBlockHeapBlock *firstFreeBlock; + + //! Free block count + uint32_t numFreeBlocks; +}; +CHECK_OFFSET(MEMBlockHeap, 0x00, header); +CHECK_OFFSET(MEMBlockHeap, 0x40, defaultTrack); +CHECK_OFFSET(MEMBlockHeap, 0x50, defaultBlock); +CHECK_OFFSET(MEMBlockHeap, 0x64, firstBlock); +CHECK_OFFSET(MEMBlockHeap, 0x68, lastBlock); +CHECK_OFFSET(MEMBlockHeap, 0x6C, firstFreeBlock); +CHECK_OFFSET(MEMBlockHeap, 0x70, numFreeBlocks); +CHECK_SIZE(MEMBlockHeap, 0x74); + +MEMBlockHeap * +MEMInitBlockHeap(MEMBlockHeap *heap, + void *start, + void *end, + MEMBlockHeapTracking *blocks, + uint32_t size, + uint32_t flags); + +void * +MEMDestroyBlockHeap(MEMBlockHeap *heap); + +int +MEMAddBlockHeapTracking(MEMBlockHeap *heap, + MEMBlockHeapTracking *tracking, + uint32_t size); + +void * +MEMAllocFromBlockHeapAt(MEMBlockHeap *heap, + void *addr, + uint32_t size); + +void * +MEMAllocFromBlockHeapEx(MEMBlockHeap *heap, + uint32_t size, + int32_t align); + +void +MEMFreeToBlockHeap(MEMBlockHeap *heap, + void *data); + +uint32_t +MEMGetAllocatableSizeForBlockHeapEx(MEMBlockHeap *heap, + int32_t align); + +uint32_t +MEMGetTrackingLeftInBlockHeap(MEMBlockHeap *heap); + +uint32_t +MEMGetTotalFreeSizeForBlockHeap(MEMBlockHeap *heap); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/cache.h b/wiiu/wut/include/coreinit/cache.h new file mode 100644 index 0000000000..296bc44557 --- /dev/null +++ b/wiiu/wut/include/coreinit/cache.h @@ -0,0 +1,88 @@ +#pragma once +#include + +/** + * \defgroup coreinit_cache Cache + * \ingroup coreinit + * + * Cache synchronisation functions. + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * Equivalent to dcbi instruction. + */ +void +DCInvalidateRange(void *addr, + uint32_t size); + + +/** + * Equivalent to dcbf, sync, eieio. + */ +void +DCFlushRange(void *addr, + uint32_t size); + + +/** + * Equivalent to dcbst, sync, eieio. + */ +void +DCStoreRange(void *addr, + uint32_t size); + + +/** + * Equivalent to dcbf. + * + * Does not perform sync, eieio like DCFlushRange. + */ +void +DCFlushRangeNoSync(void *addr, + uint32_t size); + + +/** + * Equivalent to dcbst. + * + * Does not perform sync, eieio like DCStoreRange. + */ +void +DCStoreRangeNoSync(void *addr, + uint32_t size); + + +/** + * Equivalent to dcbz instruction. + */ +void +DCZeroRange(void *addr, + uint32_t size); + + +/** + * Equivalent to dcbt instruction. + */ +void +DCTouchRange(void *addr, + uint32_t size); + + +/** + * Equivalent to icbi instruction. + */ +void +ICInvalidateRange(void *addr, + uint32_t size); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/condition.h b/wiiu/wut/include/coreinit/condition.h new file mode 100644 index 0000000000..de2b18cb6c --- /dev/null +++ b/wiiu/wut/include/coreinit/condition.h @@ -0,0 +1,84 @@ +#pragma once +#include +#include "threadqueue.h" + +/** + * \defgroup coreinit_cond Condition Variable + * \ingroup coreinit + * + * Standard condition variable implementation. + * + * Similar to std::condition_variable. + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OSCondition OSCondition; +typedef struct OSMutex OSMutex; + +#define OS_CONDITION_TAG 0x634E6456u + +struct OSCondition +{ + //! Should always be set to the value OS_CONDITION_TAG. + uint32_t tag; + + //! Name set by OSInitCondEx. + const char *name; + + UNKNOWN(4); + + //! Queue of threads currently waiting on condition with OSWaitCond. + OSThreadQueue queue; +}; +CHECK_OFFSET(OSCondition, 0x00, tag); +CHECK_OFFSET(OSCondition, 0x04, name); +CHECK_OFFSET(OSCondition, 0x0c, queue); +CHECK_SIZE(OSCondition, 0x1c); + + +/** + * Initialise a condition variable structure. + */ +void +OSInitCond(OSCondition *condition); + + +/** + * Initialise a condition variable structure with a name. + */ +void +OSInitCondEx(OSCondition *condition, + const char *name); + + +/** + * Sleep the current thread until the condition variable has been signalled. + * + * The mutex must be locked when entering this function. + * Will unlock the mutex and then sleep, reacquiring the mutex when woken. + * + * Similar to std::condition_variable::wait. + */ +void +OSWaitCond(OSCondition *condition, + OSMutex *mutex); + + +/** + * Will wake up any threads waiting on the condition with OSWaitCond. + * + * Similar to std::condition_variable::notify_all. + */ +void +OSSignalCond(OSCondition *condition); + + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/core.h b/wiiu/wut/include/coreinit/core.h new file mode 100644 index 0000000000..f339627716 --- /dev/null +++ b/wiiu/wut/include/coreinit/core.h @@ -0,0 +1,47 @@ +#pragma once +#include + +/** + * \defgroup coreinit_core Core Identification + * \ingroup coreinit + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * Returns the number of cores, should always be 3. + */ +uint32_t +OSGetCoreCount(); + + +/** + * Returns the ID of the core currently executing this thread. + */ +uint32_t +OSGetCoreId(); + + +/** + * Returns the ID of the main core. + */ +uint32_t +OSGetMainCoreId(); + + +/** + * Returns true if the current core is the main core. + */ +BOOL +OSIsMainCore(); + + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/coroutine.h b/wiiu/wut/include/coreinit/coroutine.h new file mode 100644 index 0000000000..aa4b351fab --- /dev/null +++ b/wiiu/wut/include/coreinit/coroutine.h @@ -0,0 +1,59 @@ +#pragma once +#include + +/** + * \defgroup coreinit_coroutine Coroutines + * \ingroup coreinit + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OSCoroutine OSCoroutine; + +struct OSCoroutine +{ + uint32_t nia; + uint32_t cr; + uint32_t ugqr1; + uint32_t stack; + uint32_t sda2Base; + uint32_t sdaBase; + uint32_t gpr[18]; + double fpr[18]; + double psr[18]; +}; +CHECK_OFFSET(OSCoroutine, 0x00, nia); +CHECK_OFFSET(OSCoroutine, 0x04, cr); +CHECK_OFFSET(OSCoroutine, 0x08, ugqr1); +CHECK_OFFSET(OSCoroutine, 0x0C, stack); +CHECK_OFFSET(OSCoroutine, 0x10, sda2Base); +CHECK_OFFSET(OSCoroutine, 0x14, sdaBase); +CHECK_OFFSET(OSCoroutine, 0x18, gpr); +CHECK_OFFSET(OSCoroutine, 0x60, fpr); +CHECK_OFFSET(OSCoroutine, 0xF0, psr); +CHECK_SIZE(OSCoroutine, 0x180); + +void +OSInitCoroutine(OSCoroutine *coroutine, + void *entry, + void *stack); + +uint32_t +OSLoadCoroutine(OSCoroutine *coroutine, + uint32_t result); + +uint32_t +OSSaveCoroutine(OSCoroutine *coroutine); + +void +OSSwitchCoroutine(OSCoroutine *from, + OSCoroutine *to); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/debug.h b/wiiu/wut/include/coreinit/debug.h new file mode 100644 index 0000000000..63aa2e68ed --- /dev/null +++ b/wiiu/wut/include/coreinit/debug.h @@ -0,0 +1,38 @@ +#pragma once +#include + +/** + * \defgroup coreinit_debug Debug + * \ingroup coreinit + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + + +void +OSConsoleWrite(const char *msg, + uint32_t size); + + +void +OSReport(const char *fmt, ...); + + +void +OSPanic(const char *file, + uint32_t line, + const char *fmt, ...); + + +void +OSFatal(const char *msg); + + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/dynload.h b/wiiu/wut/include/coreinit/dynload.h new file mode 100644 index 0000000000..6550e19503 --- /dev/null +++ b/wiiu/wut/include/coreinit/dynload.h @@ -0,0 +1,74 @@ +#pragma once +#include +#include "thread.h" +#include "time.h" + +/** + * \defgroup coreinit_dynload Dynamic Loading + * \ingroup coreinit + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void *OSDynLoadModule; + +typedef int (*OSDynLoadAllocFn)(int size, int align, void **outAddr); +typedef void (*OSDynLoadFreeFn)(void *addr); + + +/** + * Set the allocator function to use for dynamic loading. + */ +int32_t +OSDynLoad_SetAllocator(OSDynLoadAllocFn allocFn, + OSDynLoadFreeFn freeFn); + + +/** + * Get the allocator function used for dynamic loading. + */ +int32_t +OSDynLoad_GetAllocator(OSDynLoadAllocFn *outAllocFn, + OSDynLoadFreeFn *outFreeFn); + + +/** + * Load a module. + * + * If the module is already loaded, increase reference count. + * Similar to LoadLibrary on Windows. + */ +int32_t +OSDynLoad_Acquire(char const *name, + OSDynLoadModule *outModule); + + +/** + * Retrieve the address of a function or data export from a module. + * + * Similar to GetProcAddress on Windows. + */ +int32_t +OSDynLoad_FindExport(OSDynLoadModule module, + int32_t isData, + char const *name, + void **outAddr); + + +/** + * Free a module handle returned from OSDynLoad_Acquire. + * + * Will decrease reference count and only unload the module if count reaches 0. + * Similar to FreeLibrary on Windows. + */ +void +OSDynLoad_Release(OSDynLoadModule module); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/event.h b/wiiu/wut/include/coreinit/event.h new file mode 100644 index 0000000000..91362af2dc --- /dev/null +++ b/wiiu/wut/include/coreinit/event.h @@ -0,0 +1,146 @@ +#pragma once +#include +#include "thread.h" +#include "threadqueue.h" + +/** + * \defgroup coreinit_event Event Object + * \ingroup coreinit + * + * Standard event object implementation. There are two supported event object modes, check OSEventMode. + * + * Similar to Windows Event Objects. + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OSEvent OSEvent; + +typedef enum OSEventMode +{ + //! A manual event will only reset when OSResetEvent is called. + OS_EVENT_MODE_MANUAL = 0, + + //! An auto event will reset everytime a thread is woken. + OS_EVENT_MODE_AUTO = 1, +} OSEventMode; + +#define OS_EVENT_TAG 0x65566E54u + +struct OSEvent +{ + //! Should always be set to the value OS_EVENT_TAG. + uint32_t tag; + + //! Name set by OSInitEventEx. + const char *name; + + UNKNOWN(4); + + //! The current value of the event object. + BOOL value; + + //! The threads currently waiting on this event object with OSWaitEvent. + OSThreadQueue queue; + + //! The mode of the event object, set by OSInitEvent. + OSEventMode mode; +}; +CHECK_OFFSET(OSEvent, 0x0, tag); +CHECK_OFFSET(OSEvent, 0x4, name); +CHECK_OFFSET(OSEvent, 0xc, value); +CHECK_OFFSET(OSEvent, 0x10, queue); +CHECK_OFFSET(OSEvent, 0x20, mode); +CHECK_SIZE(OSEvent, 0x24); + + +/** + * Initialise an event object with value and mode. + */ +void +OSInitEvent(OSEvent *event, + BOOL value, + OSEventMode mode); + + +/** + * Initialise an event object with value, mode and name. + */ +void +OSInitEventEx(OSEvent *event, + BOOL value, + OSEventMode mode, + char *name); + + +/** + * Signals the event. + * + * If no threads are waiting the event value is set. + * + * If the event mode is OS_EVENT_MODE_MANUAL this will wake all waiting threads + * and the event will remain set until OSResetEvent is called. + * + * If the event mode is OS_EVENT_MODE_AUTO this will wake only one thread + * and the event will be reset immediately. + * + * Similar to SetEvent. + */ +void +OSSignalEvent(OSEvent *event); + +/** + * Signals all threads waiting on an event. + * + * If no threads are waiting the event value is set. + * + * If the event mode is OS_EVENT_MODE_MANUAL this will wake all waiting threads + * and the event will remain set until OSResetEvent is called. + * + * If the event mode is OS_EVENT_MODE_AUTO this will wake all waiting threads + * and the event will be reset. + */ +void +OSSignalEventAll(OSEvent *event); + + +/** + * Wait until an event is signalled. + * + * If the event is already set, this returns immediately. + * + * If the event mode is OS_EVENT_MODE_AUTO the event will be reset before + * returning from this method. + * + * Similar to WaitForSingleObject. + */ +void +OSWaitEvent(OSEvent *event); + + +/** + * Resets the event object. + * + * Similar to ResetEvent. + */ +void +OSResetEvent(OSEvent *event); + + +/** + * Wait until an event is signalled or a timeout has occurred. + * + * Similar to WaitForSingleObject. + */ +BOOL +OSWaitEventWithTimeout(OSEvent *event, + OSTime timeout); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/exception.h b/wiiu/wut/include/coreinit/exception.h new file mode 100644 index 0000000000..ec5960758c --- /dev/null +++ b/wiiu/wut/include/coreinit/exception.h @@ -0,0 +1,48 @@ +#pragma once +#include + +/** + * \defgroup coreinit_exception Exception Handling + * \ingroup coreinit + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef BOOL (*OSExceptionCallbackFn)(OSContext *context); + +typedef enum OSExceptionType +{ + OS_EXCEPTION_TYPE_SYSTEM_RESET = 0, + OS_EXCEPTION_TYPE_MACHINE_CHECK = 1, + OS_EXCEPTION_TYPE_DSI = 2, + OS_EXCEPTION_TYPE_ISI = 3, + OS_EXCEPTION_TYPE_EXTERNAL_INTERRUPT = 4, + OS_EXCEPTION_TYPE_ALIGNMENT = 5, + OS_EXCEPTION_TYPE_PROGRAM = 6, + OS_EXCEPTION_TYPE_FLOATING_POINT = 7, + OS_EXCEPTION_TYPE_DECREMENTER = 8, + OS_EXCEPTION_TYPE_SYSTEM_CALL = 9, + OS_EXCEPTION_TYPE_TRACE = 10, + OS_EXCEPTION_TYPE_PERFORMANCE_MONITOR = 11, + OS_EXCEPTION_TYPE_BREAKPOINT = 12, + OS_EXCEPTION_TYPE_SYSTEM_INTERRUPT = 13, + OS_EXCEPTION_TYPE_ICI = 14, +} OSExceptionType; + +OSExceptionCallbackFn +OSSetExceptionCallback(OSExceptionType exceptionType, + OSExceptionCallbackFn callback); + +OSExceptionCallbackFn +OSSetExceptionCallbackEx(UNKNOWN_ARG, + OSExceptionType exceptionType, + OSExceptionCallbackFn callback); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/exit.h b/wiiu/wut/include/coreinit/exit.h new file mode 100644 index 0000000000..abf152b201 --- /dev/null +++ b/wiiu/wut/include/coreinit/exit.h @@ -0,0 +1,24 @@ +#pragma once +#include + +/** + * \defgroup coreinit_exit Exit + * \ingroup coreinit + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +void +exit(int code); + +void +_Exit(); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/expandedheap.h b/wiiu/wut/include/coreinit/expandedheap.h new file mode 100644 index 0000000000..2a532db51b --- /dev/null +++ b/wiiu/wut/include/coreinit/expandedheap.h @@ -0,0 +1,129 @@ +#pragma once +#include + +/** + * \defgroup coreinit_expheap Expanded Heap + * \ingroup coreinit + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct MEMExpandedHeap MEMExpandedHeap; +typedef struct MEMExpandedHeapBlock MEMExpandedHeapBlock; +typedef struct MEMExpandedHeapBlockList MEMExpandedHeapBlockList; + +typedef enum MEMExpandedHeapMode +{ + MEM_EXP_HEAP_MODE_FIRST_FREE = 0, + MEM_EXP_HEAP_MODE_NEAREST_SIZE = 1, +} MEMExpandedHeapMode; + +typedef enum MEMExpandedHeapDirection +{ + MEM_EXP_HEAP_DIR_FROM_TOP = 0, + MEM_EXP_HEAP_DIR_FROM_BOTTOM = 1, +} MEMExpandedHeapDirection; + +struct MEMExpandedHeapBlock +{ + uint32_t attribs; + uint32_t blockSize; + MEMExpandedHeapBlock *prev; + MEMExpandedHeapBlock *next; + uint16_t tag; + UNKNOWN(0x02); +}; +CHECK_OFFSET(MEMExpandedHeapBlock, 0x00, attribs); +CHECK_OFFSET(MEMExpandedHeapBlock, 0x04, blockSize); +CHECK_OFFSET(MEMExpandedHeapBlock, 0x08, prev); +CHECK_OFFSET(MEMExpandedHeapBlock, 0x0c, next); +CHECK_OFFSET(MEMExpandedHeapBlock, 0x10, tag); +CHECK_SIZE(MEMExpandedHeapBlock, 0x14); + +struct MEMExpandedHeapBlockList +{ + MEMExpandedHeapBlock *head; + MEMExpandedHeapBlock *tail; +}; +CHECK_OFFSET(MEMExpandedHeapBlockList, 0x00, head); +CHECK_OFFSET(MEMExpandedHeapBlockList, 0x04, tail); +CHECK_SIZE(MEMExpandedHeapBlockList, 0x08); + +struct MEMExpandedHeap +{ + MEMHeapHeader header; + MEMExpandedHeapBlockList freeList; + MEMExpandedHeapBlockList usedList; + uint16_t groupId; + uint16_t attribs; +}; +CHECK_OFFSET(MEMExpandedHeap, 0x00, header); +CHECK_OFFSET(MEMExpandedHeap, 0x40, freeList); +CHECK_OFFSET(MEMExpandedHeap, 0x48, usedList); +CHECK_OFFSET(MEMExpandedHeap, 0x50, groupId); +CHECK_OFFSET(MEMExpandedHeap, 0x52, attribs); +CHECK_SIZE(MEMExpandedHeap, 0x54); + +MEMExpandedHeap * +MEMCreateExpHeapEx(MEMExpandedHeap *heap, + uint32_t size, + uint16_t flags); + +MEMExpandedHeap * +MEMDestroyExpHeap(MEMExpandedHeap *heap); + +void * +MEMAllocFromExpHeapEx(MEMExpandedHeap *heap, + uint32_t size, + int alignment); + +void +MEMFreeToExpHeap(MEMExpandedHeap *heap, + uint8_t *block); + +MEMExpandedHeapMode +MEMSetAllocModeForExpHeap(MEMExpandedHeap *heap, + MEMExpandedHeapMode mode); + +MEMExpandedHeapMode +MEMGetAllocModeForExpHeap(MEMExpandedHeap *heap); + +uint32_t +MEMAdjustExpHeap(MEMExpandedHeap *heap); + +uint32_t +MEMResizeForMBlockExpHeap(MEMExpandedHeap *heap, + uint8_t *address, + uint32_t size); + +uint32_t +MEMGetTotalFreeSizeForExpHeap(MEMExpandedHeap *heap); + +uint32_t +MEMGetAllocatableSizeForExpHeapEx(MEMExpandedHeap *heap, + int alignment); + +uint16_t +MEMSetGroupIDForExpHeap(MEMExpandedHeap *heap, + uint16_t id); + +uint16_t +MEMGetGroupIDForExpHeap(MEMExpandedHeap *heap); + +uint32_t +MEMGetSizeForMBlockExpHeap(uint8_t *addr); + +uint16_t +MEMGetGroupIDForMBlockExpHeap(uint8_t *addr); + +MEMExpandedHeapDirection +MEMGetAllocDirForMBlockExpHeap(uint8_t *addr); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/fastcondition.h b/wiiu/wut/include/coreinit/fastcondition.h new file mode 100644 index 0000000000..bc2b836b17 --- /dev/null +++ b/wiiu/wut/include/coreinit/fastcondition.h @@ -0,0 +1,50 @@ +#pragma once +#include +#include "threadqueue.h" + +/** + * \defgroup coreinit_fastcond Fast Condition Variable + * \ingroup coreinit + * + * A condition variable to be used with an OSFastMutex. + * + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OSFastCondition OSFastCondition; +typedef struct OSFastMutex OSFastMutex; + +#define OS_FAST_CONDITION_TAG 0x664E6456u + +struct OSFastCondition +{ + uint32_t tag; + const char *name; + UNKNOWN(4); + OSThreadQueue queue; +}; +CHECK_OFFSET(OSFastCondition, 0x00, tag); +CHECK_OFFSET(OSFastCondition, 0x04, name); +CHECK_OFFSET(OSFastCondition, 0x0c, queue); +CHECK_SIZE(OSFastCondition, 0x1c); + +void +OSFastCond_Init(OSFastCondition *condition, + const char *name); + +void +OSFastCond_Wait(OSFastCondition *condition, + OSFastMutex *mutex); + +void +OSFastCond_Signal(OSFastCondition *condition); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/fastmutex.h b/wiiu/wut/include/coreinit/fastmutex.h new file mode 100644 index 0000000000..98dd477824 --- /dev/null +++ b/wiiu/wut/include/coreinit/fastmutex.h @@ -0,0 +1,65 @@ +#pragma once +#include +#include "threadqueue.h" + +/** + * \defgroup coreinit_fastmutex Fast Mutex + * \ingroup coreinit + * + * Similar to OSMutex but tries to acquire the mutex without using the global + * scheduler lock, and does not test for thread cancel. + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OSFastMutex OSFastMutex; +typedef struct OSFastMutexLink OSFastMutexLink; +typedef struct OSFastCondition OSFastCondition; + +struct OSFastMutexLink +{ + OSFastMutex *next; + OSFastMutex *prev; +}; +CHECK_OFFSET(OSFastMutexLink, 0x00, next); +CHECK_OFFSET(OSFastMutexLink, 0x04, prev); +CHECK_SIZE(OSFastMutexLink, 0x08); + +#define OS_FAST_MUTEX_TAG 0x664D7458u + +struct OSFastMutex +{ + uint32_t tag; + const char *name; + UNKNOWN(4); + OSThreadSimpleQueue queue; + OSFastMutexLink link; + UNKNOWN(16); +}; +CHECK_OFFSET(OSFastMutex, 0x00, tag); +CHECK_OFFSET(OSFastMutex, 0x04, name); +CHECK_OFFSET(OSFastMutex, 0x0c, queue); +CHECK_OFFSET(OSFastMutex, 0x14, link); +CHECK_SIZE(OSFastMutex, 0x2c); + +void +OSFastMutex_Init(OSFastMutex *mutex, + const char *name); + +void +OSFastMutex_Lock(OSFastMutex *mutex); + +void +OSFastMutex_Unlock(OSFastMutex *mutex); + +BOOL +OSFastMutex_TryLock(OSFastMutex *mutex); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/filesystem.h b/wiiu/wut/include/coreinit/filesystem.h new file mode 100644 index 0000000000..2ef8850aff --- /dev/null +++ b/wiiu/wut/include/coreinit/filesystem.h @@ -0,0 +1,621 @@ +#pragma once +#include + +/** + * \defgroup coreinit_fs Filesystem + * \ingroup coreinit + * + * First call FSInit to initialise the file system library, then call + * FSAddClient to initialise your FSClient structure, then you need to use + * FSInitCmdBlock to initialise an FSCmdBlock structure for each command you + * want to run in parallel. You must ensure the previous filesystem command + * has been completed before reusing the same FSCmdBlock, you do not need to + * reinitialise an FSCmdBlock before reusing it. + * + * Calling fsDevInit initializes the stdlib devoptab, allowing for standard + * file IO. + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef uint32_t FSDirectoryHandle; +typedef uint32_t FSFileHandle; +typedef uint32_t FSPriority; + +typedef struct FSAsyncData FSAsyncData; +typedef struct FSCmdBlock FSCmdBlock; +typedef struct FSClient FSClient; +typedef struct FSDirectoryEntry FSDirectoryEntry; +typedef struct FSStat FSStat; +typedef struct FSStateChangeInfo FSStateChangeInfo; +typedef struct FSMountSource FSMountSource; + +typedef enum FSStatus +{ + FS_STATUS_OK = 0, + FS_STATUS_CANCELLED = -1, + FS_STATUS_END = -2, + FS_STATUS_MAX = -3, + FS_STATUS_ALREADY_OPEN = -4, + FS_STATUS_EXISTS = -5, + FS_STATUS_NOT_FOUND = -6, + FS_STATUS_NOT_FILE = -7, + FS_STATUS_NOT_DIR = -8, + FS_STATUS_ACCESS_ERROR = -9, + FS_STATUS_PERMISSION_ERROR = -10, + FS_STATUS_FILE_TOO_BIG = -11, + FS_STATUS_STORAGE_FULL = -12, + FS_STATUS_JOURNAL_FULL = -13, + FS_STATUS_UNSUPPORTED_CMD = -14, + FS_STATUS_MEDIA_NOT_READY = -15, + FS_STATUS_MEDIA_ERROR = -17, + FS_STATUS_CORRUPTED = -18, + FS_STATUS_FATAL_ERROR = -0x400, +} FSStatus; + +typedef enum FSError +{ + FS_ERROR_NOT_INIT = -0x30001, + FS_ERROR_BUSY = -0x30002, + FS_ERROR_CANCELLED = -0x30003, + FS_ERROR_END_OF_DIR = -0x30004, + FS_ERROR_END_OF_FILE = -0x30005, + FS_ERROR_MAX_MOUNT_POINTS = -0x30010, + FS_ERROR_MAX_VOLUMES = -0x30011, + FS_ERROR_MAX_CLIENTS = -0x30012, + FS_ERROR_MAX_FILES = -0x30013, + FS_ERROR_MAX_DIRS = -0x30014, + FS_ERROR_ALREADY_OPEN = -0x30015, + FS_ERROR_ALREADY_EXISTS = -0x30016, + FS_ERROR_NOT_FOUND = -0x30017, + FS_ERROR_NOT_EMPTY = -0x30018, + FS_ERROR_ACCESS_ERROR = -0x30019, + FS_ERROR_PERMISSION_ERROR = -0x3001A, + FS_ERROR_DATA_CORRUPTED = -0x3001B, + FS_ERROR_STORAGE_FULL = -0x3001C, + FS_ERROR_JOURNAL_FULL = -0x3001D, + FS_ERROR_UNAVAILABLE_COMMAND = -0x3001F, + FS_ERROR_UNSUPPORTED_COMMAND = -0x30020, + FS_ERROR_INVALID_PARAM = -0x30021, + FS_ERROR_INVALID_PATH = -0x30022, + FS_ERROR_INVALID_BUFFER = -0x30023, + FS_ERROR_INVALID_ALIGNMENT = -0x30024, + FS_ERROR_INVALID_CLIENTHANDLE = -0x30025, + FS_ERROR_INVALID_FILEHANDLE = -0x30026, + FS_ERROR_INVALID_DIRHANDLE = -0x30027, + FS_ERROR_NOT_FILE = -0x30028, + FS_ERROR_NOT_DIR = -0x30029, + FS_ERROR_FILE_TOO_BIG = -0x3002A, + FS_ERROR_OUT_OF_RANGE = -0x3002B, + FS_ERROR_OUT_OF_RESOURCES = -0x3002C, + FS_ERROR_MEDIA_NOT_READY = -0x30030, + FS_ERROR_MEDIA_ERROR = -0x30031, + FS_ERROR_WRITE_PROTECTED = -0x30032, + FS_ERROR_INVALID_MEDIA = -0x30033, +} FSError; + +typedef enum FSMode +{ + FS_MODE_READ_OWNER = 0x400, + FS_MODE_WRITE_OWNER = 0x200, + FS_MODE_EXEC_OWNER = 0x100, + + FS_MODE_READ_GROUP = 0x040, + FS_MODE_WRITE_GROUP = 0x020, + FS_MODE_EXEC_GROUP = 0x010, + + FS_MODE_READ_OTHER = 0x004, + FS_MODE_WRITE_OTHER = 0x002, + FS_MODE_EXEC_OTHER = 0x001, +} FSMode; + +typedef enum FSStatFlags +{ + FS_STAT_DIRECTORY = 0x80000000, +} FSStatFlags; + +typedef enum FSVolumeState +{ + FS_VOLUME_STATE_INITIAL = 0, + FS_VOLUME_STATE_READY = 1, + FS_VOLUME_STATE_NO_MEDIA = 2, + FS_VOLUME_STATE_INVALID_MEDIA = 3, + FS_VOLUME_STATE_DIRTY_MEDIA = 4, + FS_VOLUME_STATE_WRONG_MEDIA = 5, + FS_VOLUME_STATE_MEDIA_ERROR = 6, + FS_VOLUME_STATE_DATA_CORRUPTED = 7, + FS_VOLUME_STATE_WRITE_PROTECTED = 8, + FS_VOLUME_STATE_JOURNAL_FULL = 9, + FS_VOLUME_STATE_FATAL = 10, + FS_VOLUME_STATE_INVALID = 11, +} FSVolumeState; + +typedef enum FSMountSourceType +{ + FS_MOUNT_SOURCE_SD = 0, + FS_MOUNT_SOURCE_UNK = 1, +} FSMountSourceType; + +typedef void(*FSAsyncCallback)(FSClient *, FSCmdBlock *, FSStatus, uint32_t); + +struct FSClient +{ + UNKNOWN(0x1700); +}; +CHECK_SIZE(FSClient, 0x1700); + +struct FSCmdBlock +{ + UNKNOWN(0xA80); +}; +CHECK_SIZE(FSCmdBlock, 0xA80); + +struct FSStat +{ + FSStatFlags flags; + FSMode mode; + uint32_t owner; + uint32_t group; + uint32_t size; + UNKNOWN(0x50); +}; +CHECK_OFFSET(FSStat, 0x00, flags); +CHECK_OFFSET(FSStat, 0x10, size); +CHECK_SIZE(FSStat, 0x64); + +struct FSStateChangeInfo +{ + UNKNOWN(0xC); +}; +CHECK_SIZE(FSStateChangeInfo, 0xC); + +struct FSAsyncData +{ + uint32_t callback; + uint32_t param; + UNKNOWN(4); +}; +CHECK_OFFSET(FSAsyncData, 0x0, callback); +CHECK_OFFSET(FSAsyncData, 0x4, param); +CHECK_SIZE(FSAsyncData, 0xC); + +struct FSDirectoryEntry +{ + FSStat info; + char name[256]; +}; +CHECK_OFFSET(FSDirectoryEntry, 0x64, name); +CHECK_SIZE(FSDirectoryEntry, 0x164); + +struct FSMountSource +{ + UNKNOWN(0x300); +}; +CHECK_SIZE(FSMountSource, 0x300); + +FSStatus +fsDevInit(); + +FSStatus +fsDevExit(); + +void +FSInit(); + +void +FSShutdown(); + +FSStatus +FSAddClient(FSClient *client, + uint32_t flags); + +FSStatus +FSDelClient(FSClient *client, + uint32_t flags); + +uint32_t +FSGetClientNum(); + +void +FSInitCmdBlock(FSCmdBlock *block); + +FSStatus +FSSetCmdPriority(FSCmdBlock *block, + FSPriority priority); + +void +FSSetStateChangeNotification(FSClient *client, + FSStateChangeInfo *info); + +FSStatus +FSGetCwd(FSClient *client, + FSCmdBlock *block, + char *buffer, + uint32_t bufferSize, + uint32_t flags); + +FSStatus +FSChangeDir(FSClient *client, + FSCmdBlock *block, + const char *path, + uint32_t flags); + +FSStatus +FSChangeDirAsync(FSClient *client, + FSCmdBlock *block, + const char *path, + uint32_t flags, + FSAsyncData *asyncData); + +FSStatus +FSGetStat(FSClient *client, + FSCmdBlock *block, + const char *path, + FSStat *stat, + uint32_t flags); + +FSStatus +FSGetStatAsync(FSClient *client, + FSCmdBlock *block, + const char *path, + FSStat *stat, + uint32_t flags, + FSAsyncData *asyncData); + +FSStatus +FSRemove(FSClient *client, + FSCmdBlock *block, + const char *path, + uint32_t flags); + +FSStatus +FSRemoveAsync(FSClient *client, + FSCmdBlock *block, + const char *path, + uint32_t flags, + FSAsyncData *asyncData); + + +FSStatus +FSOpenFile(FSClient *client, + FSCmdBlock *block, + const char *path, + const char *mode, + FSFileHandle *handle, + uint32_t flags); + +FSStatus +FSOpenFileAsync(FSClient *client, + FSCmdBlock *block, + const char *path, + const char *mode, + FSFileHandle *outHandle, + uint32_t flags, + FSAsyncData *asyncData); + +FSStatus +FSCloseFile(FSClient *client, + FSCmdBlock *block, + FSFileHandle handle, + uint32_t flags); + +FSStatus +FSCloseFileAsync(FSClient *client, + FSCmdBlock *block, + FSFileHandle handle, + uint32_t flags, + FSAsyncData *asyncData); + +FSStatus +FSOpenDir(FSClient *client, + FSCmdBlock *block, + const char *path, + FSDirectoryHandle *handle, + uint32_t flags); + +FSStatus +FSOpenDirAsync(FSClient *client, + FSCmdBlock *block, + const char *path, + FSDirectoryHandle *handle, + uint32_t flags, + FSAsyncData *asyncData); + +FSStatus +FSMakeDir(FSClient *client, + FSCmdBlock *block, + const char *path, + uint32_t flags); + +FSStatus +FSMakeDirAsync(FSClient *client, + FSCmdBlock *block, + const char *path, + uint32_t flags, + FSAsyncData *asyncData); + +FSStatus +FSReadDir(FSClient *client, + FSCmdBlock *block, + FSDirectoryHandle handle, + FSDirectoryEntry *entry, + uint32_t flags); + +FSStatus +FSReadDirAsync(FSClient *client, + FSCmdBlock *block, + FSDirectoryHandle handle, + FSDirectoryEntry *entry, + uint32_t flags, + FSAsyncData *asyncData); + +FSStatus +FSRewindDir(FSClient *client, + FSCmdBlock *block, + FSDirectoryHandle handle, + uint32_t flags); + +FSStatus +FSCloseDir(FSClient *client, + FSCmdBlock *block, + FSDirectoryHandle handle, + uint32_t flags); + +FSStatus +FSCloseDirAsync(FSClient *client, + FSCmdBlock *block, + FSDirectoryHandle handle, + uint32_t flags, + FSAsyncData *asyncData); +FSStatus +FSChangeMode(FSClient *client, + FSCmdBlock *block, + char *path, + FSMode mode, + uint32_t flags); + +FSStatus +FSChangeModeAsync(FSClient *client, + FSCmdBlock *block, + char *path, + FSMode mode, + uint32_t flags, + FSAsyncData *asyncData); + +FSStatus +FSGetFreeSpaceSize(FSClient *client, + FSCmdBlock *block, + char *path, + u64 *outSize, + uint32_t flags); + +FSStatus +FSGetFreeSpaceSizeAsync(FSClient *client, + FSCmdBlock *block, + char *path, + u64 *outSize, + uint32_t flags, + FSAsyncData *asyncData); + +FSStatus +FSGetStatFile(FSClient *client, + FSCmdBlock *block, + FSFileHandle handle, + FSStat *stat, + uint32_t flags); + +FSStatus +FSGetStatFileAsync(FSClient *client, + FSCmdBlock *block, + FSFileHandle handle, + FSStat *stat, + uint32_t flags, + FSAsyncData *asyncData); + +FSStatus +FSReadFile(FSClient *client, + FSCmdBlock *block, + uint8_t *buffer, + uint32_t size, + uint32_t count, + FSFileHandle handle, + uint32_t unk1, + uint32_t flags); + +FSStatus +FSReadFileAsync(FSClient *client, + FSCmdBlock *block, + uint8_t *buffer, + uint32_t size, + uint32_t count, + FSFileHandle handle, + uint32_t unk1, + uint32_t flags, + FSAsyncData *asyncData); + +FSStatus +FSReadFileWithPos(FSClient *client, + FSCmdBlock *block, + uint8_t *buffer, + uint32_t size, + uint32_t count, + uint32_t pos, + FSFileHandle handle, + uint32_t unk1, + uint32_t flags); + +FSStatus +FSReadFileWithPosAsync(FSClient *client, + FSCmdBlock *block, + uint8_t *buffer, + uint32_t size, + uint32_t count, + uint32_t pos, + FSFileHandle handle, + uint32_t unk1, + uint32_t flags, + FSAsyncData *asyncData); + +FSStatus +FSWriteFile(FSClient *client, + FSCmdBlock *block, + uint8_t *buffer, + uint32_t size, + uint32_t count, + FSFileHandle handle, + uint32_t unk1, + uint32_t flags); + +FSStatus +FSWriteFileAsync(FSClient *client, + FSCmdBlock *block, + uint8_t *buffer, + uint32_t size, + uint32_t count, + FSFileHandle handle, + uint32_t unk1, + uint32_t flags, + FSAsyncData *asyncData); + +FSStatus +FSWriteFileWithPos(FSClient *client, + FSCmdBlock *block, + uint8_t *buffer, + uint32_t size, + uint32_t count, + uint32_t pos, + FSFileHandle handle, + uint32_t unk1, + uint32_t flags); + +FSStatus +FSWriteFileWithPosAsync(FSClient *client, + FSCmdBlock *block, + uint8_t *buffer, + uint32_t size, + uint32_t count, + uint32_t pos, + FSFileHandle handle, + uint32_t unk1, + uint32_t flags, + FSAsyncData *asyncData); + +FSStatus +FSGetPosFile(FSClient *client, + FSCmdBlock *block, + FSFileHandle fileHandle, + uint32_t *pos, + uint32_t flags); + +FSStatus +FSGetPosFileAsync(FSClient *client, + FSCmdBlock *block, + FSFileHandle fileHandle, + uint32_t *pos, + uint32_t flags, + FSAsyncData *asyncData); + +FSStatus +FSSetPosFile(FSClient *client, + FSCmdBlock *block, + FSFileHandle handle, + uint32_t pos, + uint32_t flags); + +FSStatus +FSSetPosFileAsync(FSClient *client, + FSCmdBlock *block, + FSFileHandle handle, + uint32_t pos, + uint32_t flags, + FSAsyncData *asyncData); + +FSStatus +FSFlushFile(FSClient *client, + FSCmdBlock *block, + FSFileHandle handle, + uint32_t flags); + +FSStatus +FSFlushFileAsync(FSClient *client, + FSCmdBlock *block, + FSFileHandle handle, + uint32_t flags, + FSAsyncData *asyncData); + +FSStatus +FSTruncateFile(FSClient *client, + FSCmdBlock *block, + FSFileHandle handle, + uint32_t flags); + +FSStatus +FSTruncateFileAsync(FSClient *client, + FSCmdBlock *block, + FSFileHandle handle, + uint32_t flags, + FSAsyncData *asyncData); + +FSStatus +FSRename(FSClient *client, + FSCmdBlock *block, + const char *oldPath, + const char *newPath, + uint32_t flags); + +FSStatus +FSRenameAsync(FSClient *client, + FSCmdBlock *block, + const char *oldPath, + const char *newPath, + uint32_t flags, + FSAsyncData *asyncData); + +FSVolumeState +FSGetVolumeState(FSClient *client); + +FSError +FSGetLastErrorCodeForViewer(FSClient *client); + +FSStatus +FSGetMountSource(FSClient *client, + FSCmdBlock *cmd, + FSMountSourceType type, + FSMountSource *out, + uint32_t flags); + +FSStatus +FSMount(FSClient *client, + FSCmdBlock *cmd, + FSMountSource *source, + const char *target, + uint32_t bytes, + uint32_t flags); + +FSStatus +FSUnmount(FSClient *client, + FSCmdBlock *cmd, + const char *target, + uint32_t flags); + +FSStatus +FSBindMount(FSClient *client, + FSCmdBlock *cmd, + const char *source, + const char *target, + uint32_t flags); + +FSStatus +FSbindUnmount(FSClient *client, + FSCmdBlock *cmd, + const char *target, + uint32_t flags); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/foreground.h b/wiiu/wut/include/coreinit/foreground.h new file mode 100644 index 0000000000..88eb1b0c21 --- /dev/null +++ b/wiiu/wut/include/coreinit/foreground.h @@ -0,0 +1,27 @@ +#pragma once +#include + +/** + * \defgroup coreinit_foreground Foreground Management + * \ingroup coreinit + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +void +OSEnableForegroundExit(); + +void +OSReleaseForeground(); + +void +OSSavesDone_ReadyToRelease(); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/frameheap.h b/wiiu/wut/include/coreinit/frameheap.h new file mode 100644 index 0000000000..fc9cf447b8 --- /dev/null +++ b/wiiu/wut/include/coreinit/frameheap.h @@ -0,0 +1,92 @@ +#pragma once +#include +#include "memheap.h" + +/** + * \defgroup coreinit_frameheap Frame Heap + * \ingroup coreinit + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum MEMFrameHeapFreeMode +{ + MEM_FRAME_HEAP_FREE_HEAD = 1 << 0, + MEM_FRAME_HEAP_FREE_TAIL = 1 << 1, + MEM_FRAME_HEAP_FREE_ALL = MEM_FRAME_HEAP_FREE_HEAD | MEM_FRAME_HEAP_FREE_TAIL, +} MEMFrameHeapFreeMode; + +typedef struct MEMFrameHeap MEMFrameHeap; +typedef struct MEMFrameHeapState MEMFrameHeapState; + +struct MEMFrameHeapState +{ + uint32_t tag; + void *head; + void *tail; + MEMFrameHeapState *previous; +}; +CHECK_OFFSET(MEMFrameHeapState, 0x00, tag); +CHECK_OFFSET(MEMFrameHeapState, 0x04, head); +CHECK_OFFSET(MEMFrameHeapState, 0x08, tail); +CHECK_OFFSET(MEMFrameHeapState, 0x0C, previous); +CHECK_SIZE(MEMFrameHeapState, 0x10); + +struct MEMFrameHeap +{ + MEMHeapHeader header; + void *head; + void *tail; + MEMFrameHeapState *previousState; +}; +CHECK_OFFSET(MEMFrameHeap, 0x00, header); +CHECK_OFFSET(MEMFrameHeap, 0x40, head); +CHECK_OFFSET(MEMFrameHeap, 0x44, tail); +CHECK_OFFSET(MEMFrameHeap, 0x48, previousState); +CHECK_SIZE(MEMFrameHeap, 0x4C); + +MEMFrameHeap * +MEMCreateFrmHeapEx(void *heap, + uint32_t size, + uint32_t flags); + +void * +MEMDestroyFrmHeap(MEMFrameHeap *heap); + +void * +MEMAllocFromFrmHeapEx(MEMFrameHeap *heap, + uint32_t size, + int alignment); + +void +MEMFreeToFrmHeap(MEMFrameHeap *heap, + MEMFrameHeapFreeMode mode); + +BOOL +MEMRecordStateForFrmHeap(MEMFrameHeap *heap, + uint32_t tag); + +BOOL +MEMFreeByStateToFrmHeap(MEMFrameHeap *heap, + uint32_t tag); + +uint32_t +MEMAdjustFrmHeap(MEMFrameHeap *heap); + +uint32_t +MEMResizeForMBlockFrmHeap(MEMFrameHeap *heap, + uint32_t addr, + uint32_t size); + +uint32_t +MEMGetAllocatableSizeForFrmHeapEx(MEMFrameHeap *heap, + int alignment); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/internal.h b/wiiu/wut/include/coreinit/internal.h new file mode 100644 index 0000000000..bd0f087314 --- /dev/null +++ b/wiiu/wut/include/coreinit/internal.h @@ -0,0 +1,13 @@ +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int +__os_snprintf(char *buf, size_t n, const char *format, ... ); + +#ifdef __cplusplus +} +#endif diff --git a/wiiu/wut/include/coreinit/mcp.h b/wiiu/wut/include/coreinit/mcp.h new file mode 100644 index 0000000000..9e6b33ee94 --- /dev/null +++ b/wiiu/wut/include/coreinit/mcp.h @@ -0,0 +1,123 @@ +#pragma once +#include + +/** + * \defgroup coreinit_mcp MCP IOS Calls + * \ingroup coreinit + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct MCPInstallProgress MCPInstallProgress; +typedef struct MCPInstallInfo MCPInstallInfo; +typedef struct MCPInstallTitleInfo MCPInstallTitleInfo; +typedef struct MCPDevice MCPDevice; +typedef struct MCPDeviceList MCPDeviceList; + +typedef enum MCPInstallTarget +{ + MCP_INSTALL_TARGET_MLC = 0, + MCP_INSTALL_TARGET_USB = 1, +} MCPInstallTarget; + +struct __attribute__((__packed__)) MCPInstallProgress +{ + uint32_t inProgress; + uint64_t tid; + uint64_t sizeTotal; + uint64_t sizeProgress; + uint32_t contentsTotal; + uint32_t contentsProgress; +}; +CHECK_OFFSET(MCPInstallProgress, 0x00, inProgress); +CHECK_OFFSET(MCPInstallProgress, 0x04, tid); +CHECK_OFFSET(MCPInstallProgress, 0x0C, sizeTotal); +CHECK_OFFSET(MCPInstallProgress, 0x14, sizeProgress); +CHECK_OFFSET(MCPInstallProgress, 0x1C, contentsTotal); +CHECK_OFFSET(MCPInstallProgress, 0x20, contentsProgress); +CHECK_SIZE(MCPInstallProgress, 0x24); + +struct MCPInstallInfo +{ + UNKNOWN(0x27F); +}; +CHECK_SIZE(MCPInstallInfo, 0x27F); + +struct MCPInstallTitleInfo +{ + UNKNOWN(0x27F); +}; +CHECK_SIZE(MCPInstallTitleInfo, 0x27F); + +struct MCPDevice +{ + char name[0x31B]; +}; +CHECK_SIZE(MCPDevice, 0x31B); + +struct MCPDeviceList +{ + MCPDevice devices[32]; +}; +CHECK_SIZE(MCPDeviceList, 0x31B*32); + +int +MCP_Open(); + +int +MCP_Close(int handle); + +int +MCP_InstallSetTargetDevice(int handle, + MCPInstallTarget device); + +int +MCP_InstallGetTargetDevice(int handle, + MCPInstallTarget *deviceOut); + +int +MCP_InstallSetTargetUsb(int handle, + int usb); + +int +MCP_InstallGetInfo(int handle, + char *path, + MCPInstallInfo *out); + +int +MCP_InstallTitleAsync(int handle, + char *path, + MCPInstallTitleInfo *out); + +int +MCP_InstallGetProgress(int handle, + MCPInstallProgress *installProgressOut); + +int +MCP_InstallTitleAbort(int handle); + +int +MCP_UninstallTitleAsync(int handle, + char *path, + MCPInstallTitleInfo *out); + +int +MCP_DeviceList(int handle, + int *numDevices, + MCPDeviceList *outDevices, + uint32_t outBufferSize); + +int +MCP_FullDeviceList(int handle, + int *numDevices, + MCPDeviceList *outDevices, + uint32_t outBufferSize); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/memheap.h b/wiiu/wut/include/coreinit/memheap.h new file mode 100644 index 0000000000..d937992fc5 --- /dev/null +++ b/wiiu/wut/include/coreinit/memheap.h @@ -0,0 +1,106 @@ +#pragma once +#include +#include "spinlock.h" +#include "memlist.h" + +/** + * \defgroup coreinit_memheap Common Memory Heap + * \ingroup coreinit + * + * Common memory heap fucntions. + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct MEMHeapHeader MEMHeapHeader; + +typedef enum MEMHeapFillType +{ + MEM_HEAP_FILL_TYPE_UNUSED = 0, + MEM_HEAP_FILL_TYPE_ALLOCATED = 1, + MEM_HEAP_FILL_TYPE_FREED = 2, +} MEMHeapFillType; + +typedef enum MEMHeapTag +{ + MEM_BLOCK_HEAP_TAG = 0x424C4B48u, + MEM_EXPANDED_HEAP_TAG = 0x45585048u, + MEM_FRAME_HEAP_TAG = 0x46524D48u, + MEM_UNIT_HEAP_TAG = 0x554E5448u, + MEM_USER_HEAP_TAG = 0x55535248u, +} MEMHeapTag; + +typedef enum MEMHeapFlags +{ + MEM_HEAP_FLAG_ZERO_ALLOCATED = 1 << 0, + MEM_HEAP_FLAG_DEBUG_MODE = 1 << 1, + MEM_HEAP_FLAG_USE_LOCK = 1 << 2, +} MEMHeapFlags; + +struct MEMHeapHeader +{ + //! Tag indicating which type of heap this is + MEMHeapTag tag; + + //! Link for list this heap is in + MEMMemoryLink link; + + //! List of all child heaps in this heap + MEMMemoryList list; + + //! Pointer to start of allocatable memory + void *dataStart; + + //! Pointer to end of allocatable memory + void *dataEnd; + + //! Lock used when MEM_HEAP_FLAG_USE_LOCK is set. + OSSpinLock lock; + + //! Flags set during heap creation. + uint32_t flags; + + UNKNOWN(0x0C); +}; +CHECK_OFFSET(MEMHeapHeader, 0x00, tag); +CHECK_OFFSET(MEMHeapHeader, 0x04, link); +CHECK_OFFSET(MEMHeapHeader, 0x0C, list); +CHECK_OFFSET(MEMHeapHeader, 0x18, dataStart); +CHECK_OFFSET(MEMHeapHeader, 0x1C, dataEnd); +CHECK_OFFSET(MEMHeapHeader, 0x20, lock); +CHECK_OFFSET(MEMHeapHeader, 0x30, flags); +CHECK_SIZE(MEMHeapHeader, 0x40); + +/** + * Print details about heap to COSWarn + */ +void +MEMDumpHeap(MEMHeapHeader *heap); + +/** + * Find heap which contains a memory block. + */ +MEMHeapHeader * +MEMFindContainHeap(void *block); + +/** + * Get the data fill value used when MEM_HEAP_FLAG_DEBUG_MODE is set. + */ +uint32_t +MEMGetFillValForHeap(MEMHeapFillType type); + +/** + * Set the data fill value used when MEM_HEAP_FLAG_DEBUG_MODE is set. + */ +void +MEMSetFillValForHeap(MEMHeapFillType type, + uint32_t value); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/memlist.h b/wiiu/wut/include/coreinit/memlist.h new file mode 100644 index 0000000000..4841e0c377 --- /dev/null +++ b/wiiu/wut/include/coreinit/memlist.h @@ -0,0 +1,76 @@ +#pragma once +#include + +/** + * \defgroup coreinit_memlist Memory List + * \ingroup coreinit + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct MEMMemoryLink MEMMemoryLink; +typedef struct MEMMemoryList MEMMemoryList; + +struct MEMMemoryLink +{ + void *prev; + void *next; +}; +CHECK_OFFSET(MEMMemoryLink, 0x0, prev); +CHECK_OFFSET(MEMMemoryLink, 0x4, next); +CHECK_SIZE(MEMMemoryLink, 0x8); + +struct MEMMemoryList +{ + void *head; + void *tail; + uint16_t count; + uint16_t offsetToMemoryLink; +}; +CHECK_OFFSET(MEMMemoryList, 0x0, head); +CHECK_OFFSET(MEMMemoryList, 0x4, tail); +CHECK_OFFSET(MEMMemoryList, 0x8, count); +CHECK_OFFSET(MEMMemoryList, 0xa, offsetToMemoryLink); +CHECK_SIZE(MEMMemoryList, 0xc); + +void +MEMInitList(MEMMemoryList *list, + uint16_t offsetToMemoryLink); + +void +MEMAppendListObject(MEMMemoryList *list, + void *object); + +void +MEMPrependListObject(MEMMemoryList *list, + void *object); + +void +MEMInsertListObject(MEMMemoryList *list, + void *before, + void *object); + +void +MEMRemoveListObject(MEMMemoryList *list, + void *object); + +void * +MEMGetNextListObject(MEMMemoryList *list, + void *object); + +void * +MEMGetPrevListObject(MEMMemoryList *list, + void *object); + +void * +MEMGetNthListObject(MEMMemoryList *list, + uint16_t n); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/memory.h b/wiiu/wut/include/coreinit/memory.h new file mode 100644 index 0000000000..3efc92c64e --- /dev/null +++ b/wiiu/wut/include/coreinit/memory.h @@ -0,0 +1,40 @@ +#pragma once +#include + +/** + * \defgroup coreinit_memory Memory + * \ingroup coreinit + * + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +void * +OSBlockMove(void *dst, + const void *src, + uint32_t size, + BOOL flush); + +void * +OSBlockSet(void *dst, + uint8_t val, + uint32_t size); + +uint32_t +OSEffectiveToPhysical(void *vaddr); + +void* +OSAllocFromSystem(uint32_t size, + int align); + +void +OSFreeToSystem(void *ptr); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/messagequeue.h b/wiiu/wut/include/coreinit/messagequeue.h new file mode 100644 index 0000000000..e270bbb7a6 --- /dev/null +++ b/wiiu/wut/include/coreinit/messagequeue.h @@ -0,0 +1,88 @@ +#pragma once +#include + +/** + * \defgroup coreinit_msgq Message Queue + * \ingroup coreinit + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OSMessage OSMessage; +typedef struct OSMessageQueue OSMessageQueue; + +typedef enum OSMessageFlags +{ + OS_MESSAGE_QUEUE_BLOCKING = 1 << 0, + OS_MESSAGE_QUEUE_HIGH_PRIORITY = 1 << 1, +} OSMessageFlags; + +struct OSMessage +{ + void *message; + uint32_t args[3]; +}; +CHECK_OFFSET(OSMessage, 0x00, message); +CHECK_OFFSET(OSMessage, 0x04, args); +CHECK_SIZE(OSMessage, 0x10); + +#define OS_MESSAGE_QUEUE_TAG 0x6D536751u + +struct OSMessageQueue +{ + uint32_t tag; + const char *name; + UNKNOWN(4); + OSThreadQueue sendQueue; + OSThreadQueue recvQueue; + OSMessage *messages; + uint32_t size; + uint32_t first; + uint32_t used; +}; +CHECK_OFFSET(OSMessageQueue, 0x00, tag); +CHECK_OFFSET(OSMessageQueue, 0x04, name); +CHECK_OFFSET(OSMessageQueue, 0x0c, sendQueue); +CHECK_OFFSET(OSMessageQueue, 0x1c, recvQueue); +CHECK_OFFSET(OSMessageQueue, 0x2c, messages); +CHECK_OFFSET(OSMessageQueue, 0x30, size); +CHECK_OFFSET(OSMessageQueue, 0x34, first); +CHECK_OFFSET(OSMessageQueue, 0x38, used); +CHECK_SIZE(OSMessageQueue, 0x3c); + +void +OSInitMessageQueue(OSMessageQueue *queue, + OSMessage *messages, + int32_t size); + +void +OSInitMessageQueueEx(OSMessageQueue *queue, + OSMessage *messages, + int32_t size, + const char *name); + +BOOL +OSSendMessage(OSMessageQueue *queue, + OSMessage *message, + OSMessageFlags flags); + +BOOL +OSReceiveMessage(OSMessageQueue *queue, + OSMessage *message, + OSMessageFlags flags); + +BOOL +OSPeekMessage(OSMessageQueue *queue, + OSMessage *message); + +OSMessageQueue * +OSGetSystemMessageQueue(); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/mutex.h b/wiiu/wut/include/coreinit/mutex.h new file mode 100644 index 0000000000..2b7c9e26ad --- /dev/null +++ b/wiiu/wut/include/coreinit/mutex.h @@ -0,0 +1,132 @@ +#pragma once +#include +#include "threadqueue.h" + +/** + * \defgroup coreinit_mutex Mutex + * \ingroup coreinit + * + * Standard mutex object, supports recursive locking. + * + * Similar to std::recursive_mutex. + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OSThread OSThread; + +typedef struct OSMutex OSMutex; +typedef struct OSMutexLink OSMutexLink; + +struct OSMutexLink +{ + OSMutex *next; + OSMutex *prev; +}; +CHECK_OFFSET(OSMutexLink, 0x00, next); +CHECK_OFFSET(OSMutexLink, 0x04, prev); +CHECK_SIZE(OSMutexLink, 0x8); + +#define OS_MUTEX_TAG 0x6D557458u + +struct OSMutex +{ + //! Should always be set to the value OS_MUTEX_TAG. + uint32_t tag; + + //! Name set by OSInitMutexEx. + const char *name; + + UNKNOWN(4); + + //! Queue of threads waiting for this mutex to unlock. + OSThreadQueue queue; + + //! Current owner of mutex. + OSThread *owner; + + //! Current recursion lock count of mutex. + int32_t count; + + //! Link used inside OSThread's mutex queue. + OSMutexLink link; +}; +CHECK_OFFSET(OSMutex, 0x00, tag); +CHECK_OFFSET(OSMutex, 0x04, name); +CHECK_OFFSET(OSMutex, 0x0c, queue); +CHECK_OFFSET(OSMutex, 0x1c, owner); +CHECK_OFFSET(OSMutex, 0x20, count); +CHECK_OFFSET(OSMutex, 0x24, link); +CHECK_SIZE(OSMutex, 0x2c); + + +/** + * Initialise a mutex structure. + */ +void +OSInitMutex(OSMutex *mutex); + + +/** + * Initialise a mutex structure with a name. + */ +void +OSInitMutexEx(OSMutex *mutex, + const char *name); + + +/** + * Lock the mutex. + * + * If no one owns the mutex, set current thread as owner. + * + * If the lock is owned by the current thread, increase the recursion count. + * + * If the lock is owned by another thread, the current thread will sleep until + * the owner has unlocked this mutex. + * + * Similar to std::recursive_mutex::lock. + */ +void +OSLockMutex(OSMutex *mutex); + + +/** + * Try to lock a mutex. + * + * If no one owns the mutex, set current thread as owner. + * + * If the lock is owned by the current thread, increase the recursion count. + * + * If the lock is owned by another thread, do not block, return FALSE. + * + * \return TRUE if the mutex is locked, FALSE if the mutex is owned by another thread. + * + * Similar to std::recursive_mutex::try_lock. + */ +BOOL +OSTryLockMutex(OSMutex *mutex); + + +/** + * Unlocks the mutex. + * + * Will decrease the recursion count, will only unlock the mutex when the + * recursion count reaches 0. + * + * If any other threads are waiting to lock the mutex they will be woken. + * + * Similar to std::recursive_mutex::unlock. + */ +void +OSUnlockMutex(OSMutex *mutex); + + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/rendezvous.h b/wiiu/wut/include/coreinit/rendezvous.h new file mode 100644 index 0000000000..edb44f6a03 --- /dev/null +++ b/wiiu/wut/include/coreinit/rendezvous.h @@ -0,0 +1,40 @@ +#pragma once +#include + +/** + * \defgroup coreinit_rendezvous Rendezvous + * \ingroup coreinit + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OSRendezvous OSRendezvous; + +struct OSRendezvous +{ + uint32_t core[3]; + UNKNOWN(4); +}; +CHECK_OFFSET(OSRendezvous, 0x00, core); +CHECK_SIZE(OSRendezvous, 0x10); + +void +OSInitRendezvous(OSRendezvous *rendezvous); + +BOOL +OSWaitRendezvous(OSRendezvous *rendezvous, + uint32_t coreMask); + +BOOL +OSWaitRendezvousWithTimeout(OSRendezvous *rendezvous, + uint32_t coreMask, + OSTime timeout); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/screen.h b/wiiu/wut/include/coreinit/screen.h new file mode 100644 index 0000000000..a2ef936c3f --- /dev/null +++ b/wiiu/wut/include/coreinit/screen.h @@ -0,0 +1,57 @@ +#pragma once +#include + +/** + * \defgroup coreinit_screen Screen + * \ingroup coreinit + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum OSScreenID +{ + SCREEN_TV = 0, + SCREEN_DRC = 1, +} OSScreenID; + +void +OSScreenInit(); + +uint32_t +OSScreenGetBufferSizeEx(OSScreenID screen); + +void +OSScreenSetBufferEx(OSScreenID screen, + void *addr); + +void +OSScreenClearBufferEx(OSScreenID screen, + uint32_t colour); + +void +OSScreenFlipBuffersEx(OSScreenID screen); + +void +OSScreenPutFontEx(OSScreenID screen, + uint32_t row, + uint32_t column, + const char *buffer); + +void +OSScreenPutPixelEx(OSScreenID screen, + uint32_t x, + uint32_t y, + uint32_t colour); + +void +OSScreenEnableEx(OSScreenID screen, + BOOL enable); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/semaphore.h b/wiiu/wut/include/coreinit/semaphore.h new file mode 100644 index 0000000000..2d1b0f9cce --- /dev/null +++ b/wiiu/wut/include/coreinit/semaphore.h @@ -0,0 +1,104 @@ +#pragma once +#include +#include "threadqueue.h" + +/** + * \defgroup coreinit_semaphore Semaphore + * \ingroup coreinit + * + * Similar to Windows Semaphore Objects. + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OSSemaphore OSSemaphore; + +#define OS_SEMAPHORE_TAG 0x73506852u + +struct OSSemaphore +{ + //! Should always be set to the value OS_SEMAPHORE_TAG. + uint32_t tag; + + //! Name set by OSInitMutexEx. + const char *name; + + UNKNOWN(4); + + //! Current count of semaphore + int32_t count; + + //! Queue of threads waiting on semaphore object with OSWaitSemaphore + OSThreadQueue queue; +}; +CHECK_OFFSET(OSSemaphore, 0x00, tag); +CHECK_OFFSET(OSSemaphore, 0x04, name); +CHECK_OFFSET(OSSemaphore, 0x0C, count); +CHECK_OFFSET(OSSemaphore, 0x10, queue); +CHECK_SIZE(OSSemaphore, 0x20); + + +/** + * Initialise semaphore object with count. + */ +void +OSInitSemaphore(OSSemaphore *semaphore, + int32_t count); + + +/** + * Initialise semaphore object with count and name. + */ +void +OSInitSemaphoreEx(OSSemaphore *semaphore, + int32_t count, + const char *name); + + +/** + * Get the current semaphore count. + */ +int32_t +OSGetSemaphoreCount(OSSemaphore *semaphore); + + +/** + * Increase the semaphore value. + * + * If any threads are waiting for semaphore, they are woken. + */ +int32_t +OSSignalSemaphore(OSSemaphore *semaphore); + + +/** + * Decrease the semaphore value. + * + * If the value is less than or equal to zero the current thread will be put to + * sleep until the count is above zero and it can decrement it safely. + */ +int32_t +OSWaitSemaphore(OSSemaphore *semaphore); + + +/** + * Try to decrease the semaphore value. + * + * If the value is greater than zero then it will be decremented, else the function + * will return immediately with a value <= 0 indicating a failure. + * + * \return Returns previous semaphore count, before the decrement in this function. + * If the value is >0 then it means the call was succesful. + */ +int32_t +OSTryWaitSemaphore(OSSemaphore *semaphore); + + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/spinlock.h b/wiiu/wut/include/coreinit/spinlock.h new file mode 100644 index 0000000000..440c815caf --- /dev/null +++ b/wiiu/wut/include/coreinit/spinlock.h @@ -0,0 +1,61 @@ +#pragma once +#include +#include "time.h" + +/** + * \defgroup coreinit_spinlock Spinlock + * \ingroup coreinit + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OSSpinLock OSSpinLock; + +struct OSSpinLock +{ + uint32_t owner; + UNKNOWN(0x4); + uint32_t recursion; + UNKNOWN(0x4); +}; +CHECK_OFFSET(OSSpinLock, 0x0, owner); +CHECK_OFFSET(OSSpinLock, 0x8, recursion); +CHECK_SIZE(OSSpinLock, 0x10); + +void +OSInitSpinLock(OSSpinLock *spinlock); + +BOOL +OSAcquireSpinLock(OSSpinLock *spinlock); + +BOOL +OSTryAcquireSpinLock(OSSpinLock *spinlock); + +BOOL +OSTryAcquireSpinLockWithTimeout(OSSpinLock *spinlock, + OSTime timeout); + +BOOL +OSReleaseSpinLock(OSSpinLock *spinlock); + +BOOL +OSUninterruptibleSpinLock_Acquire(OSSpinLock *spinlock); + +BOOL +OSUninterruptibleSpinLock_TryAcquire(OSSpinLock *spinlock); + +BOOL +OSUninterruptibleSpinLock_TryAcquireWithTimeout(OSSpinLock *spinlock, + OSTime timeout); + +BOOL +OSUninterruptibleSpinLock_Release(OSSpinLock *spinlock); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/systeminfo.h b/wiiu/wut/include/coreinit/systeminfo.h new file mode 100644 index 0000000000..00c7ab9e79 --- /dev/null +++ b/wiiu/wut/include/coreinit/systeminfo.h @@ -0,0 +1,35 @@ +#pragma once +#include +#include "time.h" + +/** + * \defgroup coreinit_systeminfo System Info + * \ingroup coreinit + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OSSystemInfo OSSystemInfo; + +struct OSSystemInfo +{ + uint32_t clockSpeed; + UNKNOWN(0x4); + OSTime baseTime; + UNKNOWN(0x10); +}; +CHECK_OFFSET(OSSystemInfo, 0x0, clockSpeed); +CHECK_OFFSET(OSSystemInfo, 0x8, baseTime); +CHECK_SIZE(OSSystemInfo, 0x20); + +OSSystemInfo * +OSGetSystemInfo(); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/taskqueue.h b/wiiu/wut/include/coreinit/taskqueue.h new file mode 100644 index 0000000000..ad7d572b52 --- /dev/null +++ b/wiiu/wut/include/coreinit/taskqueue.h @@ -0,0 +1,204 @@ +#pragma once +#include +#include "time.h" + +/** + * \defgroup coreinit_taskq Task Queue + * \ingroup coreinit + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct MPTask MPTask; +typedef struct MPTaskInfo MPTaskInfo; +typedef struct MPTaskQueue MPTaskQueue; +typedef struct MPTaskQueueInfo MPTaskQueueInfo; + +typedef uint32_t (*MPTaskFunc)(uint32_t, uint32_t); + +typedef enum MPTaskState +{ + MP_TASK_STATE_INITIALISED = 1 << 0, + MP_TASK_STATE_READY = 1 << 1, + MP_TASK_STATE_RUNNING = 1 << 2, + MP_TASK_STATE_FINISHED = 1 << 3, +} MPTaskState; + +typedef enum MPTaskQueueState +{ + MP_TASK_QUEUE_STATE_INITIALISED = 1 << 0, + MP_TASK_QUEUE_STATE_READY = 1 << 1, + MP_TASK_QUEUE_STATE_STOPPING = 1 << 2, + MP_TASK_QUEUE_STATE_STOPPED = 1 << 3, + MP_TASK_QUEUE_STATE_FINISHED = 1 << 4, +} MPTaskQueueState; + +#pragma pack(push, 1) +struct MPTaskInfo +{ + MPTaskState state; + uint32_t result; + uint32_t coreID; + OSTime duration; +}; +#pragma pack(pop) +CHECK_OFFSET(MPTaskInfo, 0x00, state); +CHECK_OFFSET(MPTaskInfo, 0x04, result); +CHECK_OFFSET(MPTaskInfo, 0x08, coreID); +CHECK_OFFSET(MPTaskInfo, 0x0C, duration); +CHECK_SIZE(MPTaskInfo, 0x14); + +#pragma pack(push, 1) +struct MPTask +{ + MPTask *self; + MPTaskQueue *queue; + MPTaskState state; + MPTaskFunc func; + uint32_t userArg1; + uint32_t userArg2; + uint32_t result; + uint32_t coreID; + OSTime duration; + void *userData; +}; +#pragma pack(pop) +CHECK_OFFSET(MPTask, 0x00, self); +CHECK_OFFSET(MPTask, 0x04, queue); +CHECK_OFFSET(MPTask, 0x08, state); +CHECK_OFFSET(MPTask, 0x0C, func); +CHECK_OFFSET(MPTask, 0x10, userArg1); +CHECK_OFFSET(MPTask, 0x14, userArg2); +CHECK_OFFSET(MPTask, 0x18, result); +CHECK_OFFSET(MPTask, 0x1C, coreID); +CHECK_OFFSET(MPTask, 0x20, duration); +CHECK_OFFSET(MPTask, 0x28, userData); +CHECK_SIZE(MPTask, 0x2C); + +struct MPTaskQueueInfo +{ + MPTaskQueueState state; + uint32_t tasks; + uint32_t tasksReady; + uint32_t tasksRunning; + uint32_t tasksFinished; +}; +CHECK_OFFSET(MPTaskQueueInfo, 0x00, state); +CHECK_OFFSET(MPTaskQueueInfo, 0x04, tasks); +CHECK_OFFSET(MPTaskQueueInfo, 0x08, tasksReady); +CHECK_OFFSET(MPTaskQueueInfo, 0x0C, tasksRunning); +CHECK_OFFSET(MPTaskQueueInfo, 0x10, tasksFinished); +CHECK_SIZE(MPTaskQueueInfo, 0x14); + +struct MPTaskQueue +{ + MPTaskQueue *self; + MPTaskQueueState state; + uint32_t tasks; + uint32_t tasksReady; + uint32_t tasksRunning; + UNKNOWN(4); + uint32_t tasksFinished; + UNKNOWN(8); + uint32_t queueIndex; + UNKNOWN(8); + uint32_t queueSize; + UNKNOWN(4); + MPTask **queue; + uint32_t queueMaxSize; + OSSpinLock lock; +}; +CHECK_OFFSET(MPTaskQueue, 0x00, self); +CHECK_OFFSET(MPTaskQueue, 0x04, state); +CHECK_OFFSET(MPTaskQueue, 0x08, tasks); +CHECK_OFFSET(MPTaskQueue, 0x0C, tasksReady); +CHECK_OFFSET(MPTaskQueue, 0x10, tasksRunning); +CHECK_OFFSET(MPTaskQueue, 0x18, tasksFinished); +CHECK_OFFSET(MPTaskQueue, 0x24, queueIndex); +CHECK_OFFSET(MPTaskQueue, 0x30, queueSize); +CHECK_OFFSET(MPTaskQueue, 0x38, queue); +CHECK_OFFSET(MPTaskQueue, 0x3C, queueMaxSize); +CHECK_OFFSET(MPTaskQueue, 0x40, lock); +CHECK_SIZE(MPTaskQueue, 0x50); + +void +MPInitTaskQ(MPTaskQueue *queue, + MPTask **queueBuffer, + uint32_t queueBufferLen); + +BOOL +MPTermTaskQ(MPTaskQueue *queue); + +BOOL +MPGetTaskQInfo(MPTaskQueue *queue, + MPTaskQueueInfo *info); + +BOOL +MPStartTaskQ(MPTaskQueue *queue); + +BOOL +MPStopTaskQ(MPTaskQueue *queue); + +BOOL +MPResetTaskQ(MPTaskQueue *queue); + +BOOL +MPEnqueTask(MPTaskQueue *queue, + MPTask *task); + +MPTask * +MPDequeTask(MPTaskQueue *queue); + +uint32_t +MPDequeTasks(MPTaskQueue *queue, + MPTask **queueBuffer, + uint32_t queueBufferLen); + +BOOL +MPWaitTaskQ(MPTaskQueue *queue, + MPTaskQueueState mask); + +BOOL +MPWaitTaskQWithTimeout(MPTaskQueue *queue, + MPTaskQueueState wmask, + OSTime timeout); + +BOOL +MPPrintTaskQStats(MPTaskQueue *queue, + uint32_t unk); + +void +MPInitTask(MPTask *task, + MPTaskFunc func, + uint32_t userArg1, + uint32_t userArg2); + +BOOL +MPTermTask(MPTask* task); + +BOOL +MPGetTaskInfo(MPTask *task, + MPTaskInfo *info); + +void * +MPGetTaskUserData(MPTask *task); + +void +MPSetTaskUserData(MPTask *task, + void *userData); + +BOOL +MPRunTasksFromTaskQ(MPTaskQueue *queue, + uint32_t count); + +BOOL +MPRunTask(MPTask *task); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/thread.h b/wiiu/wut/include/coreinit/thread.h new file mode 100644 index 0000000000..7e6779bff8 --- /dev/null +++ b/wiiu/wut/include/coreinit/thread.h @@ -0,0 +1,637 @@ +#pragma once +#include +#include "time.h" +#include "threadqueue.h" + +/** + * \defgroup coreinit_thread Thread + * \ingroup coreinit + * + * The thread scheduler in the Wii U uses co-operative scheduling, this is different + * to the usual pre-emptive scheduling that most operating systems use (such as + * Windows, Linux, etc). In co-operative scheduling threads must voluntarily yield + * execution to other threads. In pre-emptive threads are switched by the operating + * system after an amount of time. + * + * With the Wii U's scheduling model the thread with the highest priority which + * is in a non-waiting state will always be running (where 0 is the highest + * priority and 31 is the lowest). Execution will only switch to other threads + * once this thread has been forced to wait, such as when waiting to acquire a + * mutex, or when the thread voluntarily yields execution to other threads which + * have the same priority using OSYieldThread. OSYieldThread will never yield to + * a thread with lower priority than the current thread. + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OSContext OSContext; +typedef struct OSFastMutex OSFastMutex; +typedef struct OSFastMutexQueue OSFastMutexQueue; +typedef struct OSMutex OSMutex; +typedef struct OSMutexQueue OSMutexQueue; +typedef struct OSThread OSThread; + +//! A value from enum OS_THREAD_STATE. +typedef uint8_t OSThreadState; + +//! A value from enum OS_THREAD_REQUEST. +typedef uint32_t OSThreadRequest; + +//! A bitfield of enum OS_THREAD_ATTRIB. +typedef uint8_t OSThreadAttributes; + +typedef int (*OSThreadEntryPointFn)(int argc, const char **argv); +typedef void (*OSThreadCleanupCallbackFn)(OSThread *thread, void *stack); +typedef void (*OSThreadDeallocatorFn)(OSThread *thread, void *stack); + +enum OS_THREAD_STATE +{ + OS_THREAD_STATE_NONE = 0, + + //! Thread is ready to run + OS_THREAD_STATE_READY = 1 << 0, + + //! Thread is running + OS_THREAD_STATE_RUNNING = 1 << 1, + + //! Thread is waiting, i.e. on a mutex + OS_THREAD_STATE_WAITING = 1 << 2, + + //! Thread is about to terminate + OS_THREAD_STATE_MORIBUND = 1 << 3, +}; + +enum OS_THREAD_REQUEST +{ + OS_THREAD_REQUEST_NONE = 0, + OS_THREAD_REQUEST_SUSPEND = 1, + OS_THREAD_REQUEST_CANCEL = 2, +}; + +enum OS_THREAD_ATTRIB +{ + //! Allow the thread to run on CPU0. + OS_THREAD_ATTRIB_AFFINITY_CPU0 = 1 << 0, + + //! Allow the thread to run on CPU1. + OS_THREAD_ATTRIB_AFFINITY_CPU1 = 1 << 1, + + //! Allow the thread to run on CPU2. + OS_THREAD_ATTRIB_AFFINITY_CPU2 = 1 << 2, + + //! Allow the thread to run any CPU. + OS_THREAD_ATTRIB_AFFINITY_ANY = ((1 << 0) | (1 << 1) | (1 << 2)), + + //! Start the thread detached. + OS_THREAD_ATTRIB_DETACHED = 1 << 3, + + //! Enables tracking of stack usage. + OS_THREAD_ATTRIB_STACK_USAGE = 1 << 5 +}; + +#define OS_CONTEXT_TAG 0x4F53436F6E747874ull + +struct OSContext +{ + //! Should always be set to the value OS_CONTEXT_TAG. + uint64_t tag; + + uint32_t gpr[32]; + uint32_t cr; + uint32_t lr; + uint32_t ctr; + uint32_t xer; + uint32_t srr0; + uint32_t srr1; + UNKNOWN(0x14); + uint32_t fpscr; + double fpr[32]; + uint16_t spinLockCount; + uint16_t state; + uint32_t gqr[8]; + UNKNOWN(4); + double psf[32]; + uint64_t coretime[3]; + uint64_t starttime; + uint32_t error; + UNKNOWN(4); + uint32_t pmc1; + uint32_t pmc2; + uint32_t pmc3; + uint32_t pmc4; + uint32_t mmcr0; + uint32_t mmcr1; +}; +CHECK_OFFSET(OSContext, 0x00, tag); +CHECK_OFFSET(OSContext, 0x08, gpr); +CHECK_OFFSET(OSContext, 0x88, cr); +CHECK_OFFSET(OSContext, 0x8c, lr); +CHECK_OFFSET(OSContext, 0x90, ctr); +CHECK_OFFSET(OSContext, 0x94, xer); +CHECK_OFFSET(OSContext, 0x98, srr0); +CHECK_OFFSET(OSContext, 0x9c, srr1); +CHECK_OFFSET(OSContext, 0xb4, fpscr); +CHECK_OFFSET(OSContext, 0xb8, fpr); +CHECK_OFFSET(OSContext, 0x1b8, spinLockCount); +CHECK_OFFSET(OSContext, 0x1ba, state); +CHECK_OFFSET(OSContext, 0x1bc, gqr); +CHECK_OFFSET(OSContext, 0x1e0, psf); +CHECK_OFFSET(OSContext, 0x2e0, coretime); +CHECK_OFFSET(OSContext, 0x2f8, starttime); +CHECK_OFFSET(OSContext, 0x300, error); +CHECK_OFFSET(OSContext, 0x308, pmc1); +CHECK_OFFSET(OSContext, 0x30c, pmc2); +CHECK_OFFSET(OSContext, 0x310, pmc3); +CHECK_OFFSET(OSContext, 0x314, pmc4); +CHECK_OFFSET(OSContext, 0x318, mmcr0); +CHECK_OFFSET(OSContext, 0x31c, mmcr1); +CHECK_SIZE(OSContext, 0x320); + +struct OSMutexQueue +{ + OSMutex *head; + OSMutex *tail; + void *parent; + UNKNOWN(4); +}; +CHECK_OFFSET(OSMutexQueue, 0x0, head); +CHECK_OFFSET(OSMutexQueue, 0x4, tail); +CHECK_OFFSET(OSMutexQueue, 0x8, parent); +CHECK_SIZE(OSMutexQueue, 0x10); + +struct OSFastMutexQueue +{ + OSFastMutex *head; + OSFastMutex *tail; +}; +CHECK_OFFSET(OSFastMutexQueue, 0x00, head); +CHECK_OFFSET(OSFastMutexQueue, 0x04, tail); +CHECK_SIZE(OSFastMutexQueue, 0x08); + +#define OS_THREAD_TAG 0x74487244u +#pragma pack(push, 1) +struct OSThread +{ + OSContext context; + + //! Should always be set to the value OS_THREAD_TAG. + uint32_t tag; + + //! Bitfield of OS_THREAD_STATE + OSThreadState state; + + //! Bitfield of OS_THREAD_ATTRIB + OSThreadAttributes attr; + + //! Unique thread ID + uint16_t id; + + //! Suspend count (increased by OSSuspendThread). + int32_t suspendCounter; + + //! Actual priority of thread. + int32_t priority; + + //! Base priority of thread, 0 is highest priority, 31 is lowest priority. + int32_t basePriority; + + //! Exit value + int32_t exitValue; + + UNKNOWN(0x35C - 0x338); + + //! Queue the thread is currently waiting on + OSThreadQueue *queue; + + //! Link used for thread queue + OSThreadLink link; + + //! Queue of threads waiting to join this thread + OSThreadQueue joinQueue; + + //! Mutex this thread is waiting to lock + OSMutex *mutex; + + //! Queue of mutexes this thread owns + OSMutexQueue mutexQueue; + + //! Link for global active thread queue + OSThreadLink activeLink; + + //! Stack start (top, highest address) + void *stackStart; + + //! Stack end (bottom, lowest address) + void *stackEnd; + + //! Thread entry point + OSThreadEntryPointFn entryPoint; + + UNKNOWN(0x57c - 0x3a0); + + //! Thread specific values, accessed with OSSetThreadSpecific and OSGetThreadSpecific. + uint32_t specific[0x10]; + + UNKNOWN(0x5c0 - 0x5bc); + + //! Thread name, accessed with OSSetThreadName and OSGetThreadName. + const char *name; + + UNKNOWN(0x4); + + //! The stack pointer passed in OSCreateThread. + void *userStackPointer; + + //! Called just before thread is terminated, set with OSSetThreadCleanupCallback + OSThreadCleanupCallbackFn cleanupCallback; + + //! Called just after a thread is terminated, set with OSSetThreadDeallocator + OSThreadDeallocatorFn deallocator; + + //! If TRUE then a thread can be cancelled or suspended, set with OSSetThreadCancelState + BOOL cancelState; + + //! Current thread request, used for cancelleing and suspending the thread. + OSThreadRequest requestFlag; + + //! Pending suspend request count + int32_t needSuspend; + + //! Result of thread suspend + int32_t suspendResult; + + //! Queue of threads waiting for a thread to be suspended. + OSThreadQueue suspendQueue; + + UNKNOWN(0x69c - 0x5f4); +}; +#pragma pack(pop) +CHECK_OFFSET(OSThread, 0x320, tag); +CHECK_OFFSET(OSThread, 0x324, state); +CHECK_OFFSET(OSThread, 0x325, attr); +CHECK_OFFSET(OSThread, 0x326, id); +CHECK_OFFSET(OSThread, 0x328, suspendCounter); +CHECK_OFFSET(OSThread, 0x32c, priority); +CHECK_OFFSET(OSThread, 0x330, basePriority); +CHECK_OFFSET(OSThread, 0x334, exitValue); +CHECK_OFFSET(OSThread, 0x35c, queue); +CHECK_OFFSET(OSThread, 0x360, link); +CHECK_OFFSET(OSThread, 0x368, joinQueue); +CHECK_OFFSET(OSThread, 0x378, mutex); +CHECK_OFFSET(OSThread, 0x37c, mutexQueue); +CHECK_OFFSET(OSThread, 0x38c, activeLink); +CHECK_OFFSET(OSThread, 0x394, stackStart); +CHECK_OFFSET(OSThread, 0x398, stackEnd); +CHECK_OFFSET(OSThread, 0x39c, entryPoint); +CHECK_OFFSET(OSThread, 0x57c, specific); +CHECK_OFFSET(OSThread, 0x5c0, name); +CHECK_OFFSET(OSThread, 0x5c8, userStackPointer); +CHECK_OFFSET(OSThread, 0x5cc, cleanupCallback); +CHECK_OFFSET(OSThread, 0x5d0, deallocator); +CHECK_OFFSET(OSThread, 0x5d4, cancelState); +CHECK_OFFSET(OSThread, 0x5d8, requestFlag); +CHECK_OFFSET(OSThread, 0x5dc, needSuspend); +CHECK_OFFSET(OSThread, 0x5e0, suspendResult); +CHECK_OFFSET(OSThread, 0x5e4, suspendQueue); +CHECK_SIZE(OSThread, 0x69c); + + +/** + * Cancels a thread. + * + * This sets the threads requestFlag to OS_THREAD_REQUEST_CANCEL, the thread will + * be terminated next time OSTestThreadCancel is called. + */ +void +OSCancelThread(OSThread *thread); + + +/** + * Returns the count of active threads. + */ +int32_t +OSCheckActiveThreads(); + + +/** + * Get the maximum amount of stack the thread has used. + */ +int32_t +OSCheckThreadStackUsage(OSThread *thread); + + +/** + * Disable tracking of thread stack usage + */ +void +OSClearThreadStackUsage(OSThread *thread); + + +/** + * Clears a thread's suspend counter and resumes it. + */ +void +OSContinueThread(OSThread *thread); + + +/** + * Create a new thread. + * + * \param thread Thread to initialise. + * \param entry Thread entry point. + * \param argc argc argument passed to entry point. + * \param argv argv argument passed to entry point. + * \param stack Top of stack (highest address). + * \param stackSize Size of stack. + * \param priority Thread priority, 0 is highest priorty, 31 is lowest. + * \param attributes Thread attributes, see OSThreadAttributes. + */ +BOOL +OSCreateThread(OSThread *thread, + OSThreadEntryPointFn entry, + int32_t argc, + char *argv, + void *stack, + uint32_t stackSize, + int32_t priority, + OSThreadAttributes attributes); + + +/** + * Detach thread. + */ +void +OSDetachThread(OSThread *thread); + + +/** + * Exit the current thread with a exit code. + * + * This function is implicitly called when the thread entry point returns. + */ +void +OSExitThread(int32_t result); + + +/** + * Get the next and previous thread in the thread's active queue. + */ +void +OSGetActiveThreadLink(OSThread *thread, + OSThreadLink *link); + + +/** + * Return pointer to OSThread object for the current thread. + */ +OSThread * +OSGetCurrentThread(); + + +/** + * Returns the default thread for a specific core. + * + * Each core has 1 default thread created before the game boots. The default + * thread for core 1 calls the RPX entry point, the default threads for core 0 + * and 2 are suspended and can be used with OSRunThread. + */ +OSThread * +OSGetDefaultThread(uint32_t coreID); + + +/** + * Return current stack pointer, value of r1 register. + */ +uint32_t +OSGetStackPointer(); + + +/** + * Get a thread's affinity. + */ +uint32_t +OSGetThreadAffinity(OSThread *thread); + + +/** + * Get a thread's name. + */ +const char * +OSGetThreadName(OSThread *thread); + + +/** + * Get a thread's base priority. + */ +int32_t +OSGetThreadPriority(OSThread *thread); + + +/** + * Get a thread's specific value set by OSSetThreadSpecific. + */ +uint32_t +OSGetThreadSpecific(uint32_t id); + + +/** + * Returns TRUE if a thread is suspended. + */ +BOOL +OSIsThreadSuspended(OSThread *thread); + + +/** + * Returns TRUE if a thread is terminated. + */ +BOOL +OSIsThreadTerminated(OSThread *thread); + + +/** + * Wait until thread is terminated. + * + * If the target thread is detached, returns FALSE. + * + * \param thread Thread to wait for + * \param threadResult Pointer to store thread exit value in. + * \returns Returns TRUE if thread has terminated, FALSE if thread is detached. + */ +BOOL +OSJoinThread(OSThread *thread, + int *threadResult); + + +/** + * Resumes a thread. + * + * Decrements the thread's suspend counter, if the counter reaches 0 the thread + * is resumed. + * + * \returns Returns the previous value of the suspend counter. + */ +int32_t +OSResumeThread(OSThread *thread); + + +/** + * Run a function on an already created thread. + * + * Can only be used on idle threads. + */ +BOOL +OSRunThread(OSThread *thread, + OSThreadEntryPointFn entry, + int argc, + const char **argv); + + +/** + * Set a thread's affinity. + */ +BOOL +OSSetThreadAffinity(OSThread *thread, + uint32_t affinity); + + +/** + * Set a thread's cancellation state. + * + * If the state is TRUE then the thread can be suspended or cancelled when + * OSTestThreadCancel is called. + */ +BOOL +OSSetThreadCancelState(BOOL state); + + +/** + * Set the callback to be called just before a thread is terminated. + */ +OSThreadCleanupCallbackFn +OSSetThreadCleanupCallback(OSThread *thread, + OSThreadCleanupCallbackFn callback); + + +/** + * Set the callback to be called just after a thread is terminated. + */ +OSThreadDeallocatorFn +OSSetThreadDeallocator(OSThread *thread, + OSThreadDeallocatorFn deallocator); + + +/** + * Set a thread's name. + */ +void +OSSetThreadName(OSThread *thread, + const char *name); + + +/** + * Set a thread's priority. + */ +BOOL +OSSetThreadPriority(OSThread *thread, + int32_t priority); + + +/** + * Set a thread's run quantum. + * + * This is the maximum amount of time the thread can run for before being forced + * to yield. + */ +BOOL +OSSetThreadRunQuantum(OSThread *thread, + uint32_t quantum); + +/** + * Set a thread specific value. + * + * Can be read with OSGetThreadSpecific. + */ +void +OSSetThreadSpecific(uint32_t id, + uint32_t value); + + +/** + * Set thread stack usage tracking. + */ +BOOL +OSSetThreadStackUsage(OSThread *thread); + + +/** + * Sleep the current thread and add it to a thread queue. + * + * Will sleep until the thread queue is woken with OSWakeupThread. + */ +void +OSSleepThread(OSThreadQueue *queue); + + +/** + * Sleep the current thread for a period of time. + */ +void +OSSleepTicks(OSTime ticks); + + +/** + * Suspend a thread. + * + * Increases a thread's suspend counter, if the counter is >0 then the thread is + * suspended. + * + * \returns Returns the thread's previous suspend counter value + */ +uint32_t +OSSuspendThread(OSThread *thread); + + +/** + * Check to see if the current thread should be cancelled or suspended. + * + * This is implicitly called in: + * - OSLockMutex + * - OSTryLockMutex + * - OSUnlockMutex + * - OSAcquireSpinLock + * - OSTryAcquireSpinLock + * - OSTryAcquireSpinLockWithTimeout + * - OSReleaseSpinLock + * - OSCancelThread + */ +void +OSTestThreadCancel(); + + +/** + * Wake up all threads in queue. + * + * Clears the thread queue. + */ +void +OSWakeupThread(OSThreadQueue *queue); + + +/** + * Yield execution to waiting threads with same priority. + * + * This will never switch to a thread with a lower priority than the current + * thread. + */ +void +OSYieldThread(); + + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/threadqueue.h b/wiiu/wut/include/coreinit/threadqueue.h new file mode 100644 index 0000000000..32a70ed22d --- /dev/null +++ b/wiiu/wut/include/coreinit/threadqueue.h @@ -0,0 +1,61 @@ +#pragma once +#include + +/** + * \defgroup coreinit_threadq Thread Queue + * \ingroup coreinit + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OSThread OSThread; + +typedef struct OSThreadLink OSThreadLink; +typedef struct OSThreadQueue OSThreadQueue; +typedef struct OSThreadSimpleQueue OSThreadSimpleQueue; + +struct OSThreadLink +{ + OSThread *prev; + OSThread *next; +}; +CHECK_OFFSET(OSThreadLink, 0x00, prev); +CHECK_OFFSET(OSThreadLink, 0x04, next); +CHECK_SIZE(OSThreadLink, 0x8); + +struct OSThreadQueue +{ + OSThread *head; + OSThread *tail; + void *parent; + UNKNOWN(4); +}; +CHECK_OFFSET(OSThreadQueue, 0x00, head); +CHECK_OFFSET(OSThreadQueue, 0x04, tail); +CHECK_OFFSET(OSThreadQueue, 0x08, parent); +CHECK_SIZE(OSThreadQueue, 0x10); + +struct OSThreadSimpleQueue +{ + OSThread *head; + OSThread *tail; +}; +CHECK_OFFSET(OSThreadSimpleQueue, 0x00, head); +CHECK_OFFSET(OSThreadSimpleQueue, 0x04, tail); +CHECK_SIZE(OSThreadSimpleQueue, 0x08); + +void +OSInitThreadQueue(OSThreadQueue *queue); + +void +OSInitThreadQueueEx(OSThreadQueue *queue, + void *parent); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/time.h b/wiiu/wut/include/coreinit/time.h new file mode 100644 index 0000000000..aed728d378 --- /dev/null +++ b/wiiu/wut/include/coreinit/time.h @@ -0,0 +1,64 @@ +#pragma once +#include + +/** + * \defgroup coreinit_time Time + * \ingroup coreinit + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OSCalendarTime OSCalendarTime; + +typedef int32_t OSTick; +typedef int64_t OSTime; + +struct OSCalendarTime +{ + int32_t tm_sec; + int32_t tm_min; + int32_t tm_hour; + int32_t tm_mday; + int32_t tm_mon; + int32_t tm_year; +}; +CHECK_OFFSET(OSCalendarTime, 0x00, tm_sec); +CHECK_OFFSET(OSCalendarTime, 0x04, tm_min); +CHECK_OFFSET(OSCalendarTime, 0x08, tm_hour); +CHECK_OFFSET(OSCalendarTime, 0x0C, tm_mday); +CHECK_OFFSET(OSCalendarTime, 0x10, tm_mon); +CHECK_OFFSET(OSCalendarTime, 0x14, tm_year); +CHECK_SIZE(OSCalendarTime, 0x18); + +#define OSOneSecond ((OSGetSystemInfo()->clockSpeed) / 4) +#define OSMilliseconds(val) ((((uint64_t)(val)) * (uint64_t)(OSOneSecond)) / 1000ull) +#define OSMicroseconds(val) ((((uint64_t)(val)) * (uint64_t)(OSOneSecond)) / 1000000ull) +#define OSNanoseconds(val) ((((uint64_t)(val)) * (uint64_t)(OSOneSecond)) / 1000000000ull) + +OSTime +OSGetTime(); + +OSTime +OSGetSystemTime(); + +OSTick +OSGetTick(); + +OSTick +OSGetSystemTick(); + +OSTime +OSCalendarTimeToTicks(OSCalendarTime *calendarTime); + +void +OSTicksToCalendarTime(OSTime time, + OSCalendarTime *calendarTime); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/title.h b/wiiu/wut/include/coreinit/title.h new file mode 100644 index 0000000000..c37a15a102 --- /dev/null +++ b/wiiu/wut/include/coreinit/title.h @@ -0,0 +1,14 @@ +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +u64 OSGetTitleID(void); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/coreinit/unitheap.h b/wiiu/wut/include/coreinit/unitheap.h new file mode 100644 index 0000000000..549a0c1eb3 --- /dev/null +++ b/wiiu/wut/include/coreinit/unitheap.h @@ -0,0 +1,68 @@ +#pragma once +#include +#include "memheap.h" + +/** + * \defgroup coreinit_unitheap Unit Heap + * \ingroup coreinit + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct MEMUnitHeap MEMUnitHeap; +typedef struct MEMUnitHeapFreeBlock MEMUnitHeapFreeBlock; + +struct MEMUnitHeapFreeBlock +{ + MEMUnitHeapFreeBlock *next; +}; +CHECK_OFFSET(MEMUnitHeapFreeBlock, 0x00, next); +CHECK_SIZE(MEMUnitHeapFreeBlock, 0x04); + +struct MEMUnitHeap +{ + MEMHeapHeader header; + MEMUnitHeapFreeBlock *freeBlocks; + uint32_t blockSize; +}; +CHECK_OFFSET(MEMUnitHeap, 0x00, header); +CHECK_OFFSET(MEMUnitHeap, 0x40, freeBlocks); +CHECK_OFFSET(MEMUnitHeap, 0x44, blockSize); +CHECK_SIZE(MEMUnitHeap, 0x48); + +MEMUnitHeap * +MEMCreateUnitHeapEx(MEMUnitHeap *heap, + uint32_t size, + uint32_t blockSize, + int32_t alignment, + uint16_t flags); + +void * +MEMDestroyUnitHeap(MEMUnitHeap *heap); + +void * +MEMAllocFromUnitHeap(MEMUnitHeap *heap); + +void +MEMFreeToUnitHeap(MEMUnitHeap *heap, + void *block); + +void +MEMiDumpUnitHeap(MEMUnitHeap *heap); + +uint32_t +MEMCountFreeBlockForUnitHeap(MEMUnitHeap *heap); + +uint32_t +MEMCalcHeapSizeForUnitHeap(uint32_t blockSize, + uint32_t count, + int32_t alignment); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/gx2/clear.h b/wiiu/wut/include/gx2/clear.h new file mode 100644 index 0000000000..e8eea698ed --- /dev/null +++ b/wiiu/wut/include/gx2/clear.h @@ -0,0 +1,59 @@ +#pragma once +#include +#include "enum.h" + +/** + * \defgroup gx2_clear Clear + * \ingroup gx2 + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct GX2ColorBuffer GX2ColorBuffer; +typedef struct GX2DepthBuffer GX2DepthBuffer; + +void +GX2ClearColor(GX2ColorBuffer *colorBuffer, + float red, + float green, + float blue, + float alpha); + +void +GX2ClearDepthStencilEx(GX2DepthBuffer *depthBuffer, + float depth, + uint8_t stencil, + GX2ClearFlags clearMode); + +void +GX2ClearBuffersEx(GX2ColorBuffer *colorBuffer, + GX2DepthBuffer *depthBuffer, + float red, + float green, + float blue, + float alpha, + float depth, + uint8_t stencil, + GX2ClearFlags clearMode); + +void +GX2SetClearDepth(GX2DepthBuffer *depthBuffer, + float depth); + +void +GX2SetClearStencil(GX2DepthBuffer *depthBuffer, + uint8_t stencil); + +void +GX2SetClearDepthStencil(GX2DepthBuffer *depthBuffer, + float depth, + uint8_t stencil); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/gx2/context.h b/wiiu/wut/include/gx2/context.h new file mode 100644 index 0000000000..2c2ed39756 --- /dev/null +++ b/wiiu/wut/include/gx2/context.h @@ -0,0 +1,69 @@ +#pragma once +#include + +/** + * \defgroup gx2_context Context State + * \ingroup gx2 + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct GX2ShadowState GX2ShadowState; +typedef struct GX2ContextState GX2ContextState; + +struct GX2ShadowState +{ + uint32_t config[0xB00]; + uint32_t context[0x400]; + uint32_t alu[0x800]; + uint32_t loop[0x60]; + PADDING((0x80 - 0x60) * 4); + uint32_t resource[0xD9E]; + PADDING((0xDC0 - 0xD9E) * 4); + uint32_t sampler[0xA2]; + PADDING((0xC0 - 0xA2) * 4); +}; +CHECK_OFFSET(GX2ShadowState, 0x0000, config); +CHECK_OFFSET(GX2ShadowState, 0x2C00, context); +CHECK_OFFSET(GX2ShadowState, 0x3C00, alu); +CHECK_OFFSET(GX2ShadowState, 0x5C00, loop); +CHECK_OFFSET(GX2ShadowState, 0x5E00, resource); +CHECK_OFFSET(GX2ShadowState, 0x9500, sampler); +CHECK_SIZE(GX2ShadowState, 0x9800); + +struct GX2ContextState +{ + GX2ShadowState shadowState; + UNKNOWN(4); + uint32_t shadowDisplayListSize; + UNKNOWN(0x9e00 - 0x9808); + uint32_t shadowDisplayList[192]; +}; +CHECK_OFFSET(GX2ContextState, 0x0000, shadowState); +CHECK_OFFSET(GX2ContextState, 0x9804, shadowDisplayListSize); +CHECK_OFFSET(GX2ContextState, 0x9e00, shadowDisplayList); +CHECK_SIZE(GX2ContextState, 0xa100); + +void +GX2SetupContextStateEx(GX2ContextState *state, + BOOL unk1); + +void +GX2GetContextStateDisplayList(GX2ContextState *state, + void *outDisplayList, + uint32_t *outSize); + +void +GX2SetContextState(GX2ContextState *state); + +void +GX2SetDefaultState(); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/gx2/display.h b/wiiu/wut/include/gx2/display.h new file mode 100644 index 0000000000..71f8dfde87 --- /dev/null +++ b/wiiu/wut/include/gx2/display.h @@ -0,0 +1,71 @@ +#pragma once +#include +#include "enum.h" +#include "surface.h" + +/** + * \defgroup gx2_display Display + * \ingroup gx2 + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +void +GX2SetTVEnable(BOOL enable); + +void +GX2SetDRCEnable(BOOL enable); + +void +GX2CalcTVSize(GX2TVRenderMode tvRenderMode, + GX2SurfaceFormat surfaceFormat, + GX2BufferingMode bufferingMode, + uint32_t *size, + uint32_t *unkOut); + +void +GX2CalcDRCSize(GX2DrcRenderMode drcRenderMode, + GX2SurfaceFormat surfaceFormat, + GX2BufferingMode bufferingMode, + uint32_t *size, + uint32_t *unkOut); + +void +GX2SetTVBuffer(void *buffer, + uint32_t size, + GX2TVRenderMode tvRenderMode, + GX2SurfaceFormat surfaceFormat, + GX2BufferingMode bufferingMode); + +void +GX2SetDRCBuffer(void *buffer, + uint32_t size, + GX2DrcRenderMode drcRenderMode, + GX2SurfaceFormat surfaceFormat, + GX2BufferingMode bufferingMode); + +void +GX2SetTVScale(uint32_t x, + uint32_t y); + +void +GX2SetDRCScale(uint32_t x, + uint32_t y); + +GX2TVScanMode +GX2GetSystemTVScanMode(); + +GX2TVScanMode +GX2GetSystemDRCScanMode(); + +GX2DrcRenderMode +GX2GetSystemDRCMode(); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/gx2/displaylist.h b/wiiu/wut/include/gx2/displaylist.h new file mode 100644 index 0000000000..eb6ab5d319 --- /dev/null +++ b/wiiu/wut/include/gx2/displaylist.h @@ -0,0 +1,45 @@ +#pragma once +#include + +/** + * \defgroup gx2_displaylist Display List + * \ingroup gx2 + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +void +GX2BeginDisplayListEx(void *displayList, + uint32_t bytes, + BOOL unk1); + +uint32_t +GX2EndDisplayList(void *displayList); + +void +GX2DirectCallDisplayList(void *displayList, + uint32_t bytes); + +void +GX2CallDisplayList(void *displayList, + uint32_t bytes); + +BOOL +GX2GetDisplayListWriteStatus(); + +BOOL +GX2GetCurrentDisplayList(void **outDisplayList, + uint32_t *outSize); + +void +GX2CopyDisplayList(void *displayList, + uint32_t bytes); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/gx2/draw.h b/wiiu/wut/include/gx2/draw.h new file mode 100644 index 0000000000..5281a81b02 --- /dev/null +++ b/wiiu/wut/include/gx2/draw.h @@ -0,0 +1,66 @@ +#pragma once +#include +#include "enum.h" + +/** + * \defgroup gx2_draw Draw + * \ingroup gx2 + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +void +GX2SetAttribBuffer(uint32_t index, + uint32_t size, + uint32_t stride, + void *buffer); + +void +GX2DrawEx(GX2PrimitiveMode mode, + uint32_t count, + uint32_t offset, + uint32_t numInstances); + +void +GX2DrawEx2(GX2PrimitiveMode mode, + uint32_t count, + uint32_t offset, + uint32_t numInstances, + uint32_t baseInstance); + +void +GX2DrawIndexedEx(GX2PrimitiveMode mode, + uint32_t count, + GX2IndexType indexType, + void *indices, + uint32_t offset, + uint32_t numInstances); + +void +GX2DrawIndexedEx2(GX2PrimitiveMode mode, + uint32_t count, + GX2IndexType indexType, + void *indices, + uint32_t offset, + uint32_t numInstances, + uint32_t baseInstance); + +void +GX2DrawIndexedImmediateEx(GX2PrimitiveMode mode, + uint32_t count, + GX2IndexType indexType, + void *indices, + uint32_t offset, + uint32_t numInstances); + +void +GX2SetPrimitiveRestartIndex(uint32_t index); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/gx2/enum.h b/wiiu/wut/include/gx2/enum.h new file mode 100644 index 0000000000..605aeb3a86 --- /dev/null +++ b/wiiu/wut/include/gx2/enum.h @@ -0,0 +1,506 @@ +#pragma once +#include + +/** + * \defgroup gx2_enum Enums + * \ingroup gx2 + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum GX2AAMode +{ + GX2_AA_MODE1X = 0, + GX2_AA_MODE2X = 1, + GX2_AA_MODE4X = 2 +} GX2AAMode; + +typedef enum GX2AlphaToMaskMode +{ + GX2_ALPHA_TO_MASK_MODE_NON_DITHERED = 0, + GX2_ALPHA_TO_MASK_MODE_DITHER_0 = 1, + GX2_ALPHA_TO_MASK_MODE_DITHER_90 = 2, + GX2_ALPHA_TO_MASK_MODE_DITHER_180 = 3, + GX2_ALPHA_TO_MASK_MODE_DITHER_270 = 4, +} GX2AlphaToMaskMode; + +typedef enum GX2AttribFormat +{ + GX2_ATTRIB_FORMAT_UNORM_8 = 0x0, + GX2_ATTRIB_FORMAT_UNORM_8_8 = 0x04, + GX2_ATTRIB_FORMAT_UNORM_8_8_8_8 = 0x0A, + + GX2_ATTRIB_FORMAT_UINT_8 = 0x100, + GX2_ATTRIB_FORMAT_UINT_8_8 = 0x104, + GX2_ATTRIB_FORMAT_UINT_8_8_8_8 = 0x10A, + + GX2_ATTRIB_FORMAT_SNORM_8 = 0x200, + GX2_ATTRIB_FORMAT_SNORM_8_8 = 0x204, + GX2_ATTRIB_FORMAT_SNORM_8_8_8_8 = 0x20A, + + GX2_ATTRIB_FORMAT_SINT_8 = 0x300, + GX2_ATTRIB_FORMAT_SINT_8_8 = 0x304, + GX2_ATTRIB_FORMAT_SINT_8_8_8_8 = 0x30A, + + GX2_ATTRIB_FORMAT_FLOAT_32 = 0x806, + GX2_ATTRIB_FORMAT_FLOAT_32_32 = 0x80d, + GX2_ATTRIB_FORMAT_FLOAT_32_32_32 = 0x811, + GX2_ATTRIB_FORMAT_FLOAT_32_32_32_32 = 0x813, +} GX2AttribFormat; + +typedef enum GX2AttribIndexType +{ + GX2_ATTRIB_INDEX_PER_VERTEX = 0, + GX2_ATTRIB_INDEX_PER_INSTANCE = 1, +} GX2AttribIndexType; + +typedef enum GX2BlendMode +{ + GX2_BLEND_MODE_ZERO = 0, + GX2_BLEND_MODE_ONE = 1, + GX2_BLEND_MODE_SRC_COLOR = 2, + GX2_BLEND_MODE_INV_SRC_COLOR = 3, + GX2_BLEND_MODE_SRC_ALPHA = 4, + GX2_BLEND_MODE_INV_SRC_ALPHA = 5, + GX2_BLEND_MODE_DST_ALPHA = 6, + GX2_BLEND_MODE_INV_DST_ALPHA = 7, + GX2_BLEND_MODE_DST_COLOR = 8, + GX2_BLEND_MODE_INV_DST_COLOR = 9, + GX2_BLEND_MODE_SRC_ALPHA_SAT = 10, + GX2_BLEND_MODE_BOTH_SRC_ALPHA = 11, + GX2_BLEND_MODE_BOTH_INV_SRC_ALPHA = 12, + GX2_BLEND_MODE_BLEND_FACTOR = 13, + GX2_BLEND_MODE_INV_BLEND_FACTOR = 14, + GX2_BLEND_MODE_SRC1_COLOR = 15, + GX2_BLEND_MODE_INV_SRC1_COLOR = 16, + GX2_BLEND_MODE_SRC1_ALPHA = 17, + GX2_BLEND_MODE_INV_SRC1_ALPHA = 18, +} GX2BlendMode; + +typedef enum GX2BlendCombineMode +{ + GX2_BLEND_COMBINE_MODE_ADD = 0, + GX2_BLEND_COMBINE_MODE_SUB = 1, + GX2_BLEND_COMBINE_MODE_MIN = 2, + GX2_BLEND_COMBINE_MODE_MAX = 3, + GX2_BLEND_COMBINE_MODE_REV_SUB = 4, +} GX2BlendCombineMode; + +typedef enum GX2BufferingMode +{ + GX2_BUFFERING_MODE_SINGLE = 1, + GX2_BUFFERING_MODE_DOUBLE = 2, + GX2_BUFFERING_MODE_TRIPLE = 3, +} GX2BufferingMode; + +typedef enum GX2ChannelMask +{ + GX2_CHANNEL_MASK_R = 1, + GX2_CHANNEL_MASK_G = 2, + GX2_CHANNEL_MASK_RG = 3, + GX2_CHANNEL_MASK_B = 4, + GX2_CHANNEL_MASK_RB = 5, + GX2_CHANNEL_MASK_GB = 6, + GX2_CHANNEL_MASK_RGB = 7, + GX2_CHANNEL_MASK_A = 8, + GX2_CHANNEL_MASK_RA = 9, + GX2_CHANNEL_MASK_GA = 10, + GX2_CHANNEL_MASK_RGA = 11, + GX2_CHANNEL_MASK_BA = 12, + GX2_CHANNEL_MASK_RBA = 13, + GX2_CHANNEL_MASK_GBA = 14, + GX2_CHANNEL_MASK_RGBA = 15, +} GX2ChannelMask; + +typedef enum GX2ClearFlags +{ + GX2_CLEAR_FLAGS_DEPTH = 1, + GX2_CLEAR_FLAGS_STENCIL = 2, + GX2_CLEAR_FLAGS_BOTH = (GX2_CLEAR_FLAGS_DEPTH | GX2_CLEAR_FLAGS_STENCIL), +} GX2ClearFlags; + +typedef enum GX2CompareFunction +{ + GX2_COMPARE_FUNC_NEVER = 0, + GX2_COMPARE_FUNC_LESS = 1, + GX2_COMPARE_FUNC_EQUAL = 2, + GX2_COMPARE_FUNC_LEQUAL = 3, + GX2_COMPARE_FUNC_GREATER = 4, + GX2_COMPARE_FUNC_NOT_EQUAL = 5, + GX2_COMPARE_FUNC_GEQUAL = 6, + GX2_COMPARE_FUNC_ALWAYS = 7, +} GX2CompareFunction; + +typedef enum GX2DrcRenderMode +{ + GX2_DRC_RENDER_MODE_DISABLED = 0, + GX2_DRC_RENDER_MODE_SINGLE = 1, +} GX2DrcRenderMode; + +typedef enum GX2EventType +{ + GX2_EVENT_TYPE_VSYNC = 2, + GX2_EVENT_TYPE_FLIP = 3, + GX2_EVENT_TYPE_DISPLAY_LIST_OVERRUN = 4, +} GX2EventType; + +typedef enum GX2EndianSwapMode +{ + GX2_ENDIAN_SWAP_NONE = 0, + GX2_ENDIAN_SWAP_8_IN_16 = 1, + GX2_ENDIAN_SWAP_8_IN_32 = 2, + GX2_ENDIAN_SWAP_DEFAULT = 3, +} GX2EndianSwapMode; + +typedef enum GX2FetchShaderType +{ + GX2_FETCH_SHADER_TESSELLATION_NONE = 0, + GX2_FETCH_SHADER_TESSELLATION_LINE = 1, + GX2_FETCH_SHADER_TESSELLATION_TRIANGLE = 2, + GX2_FETCH_SHADER_TESSELLATION_QUAD = 3, +} GX2FetchShaderType; + +typedef enum GX2FrontFace +{ + GX2_FRONT_FACE_CCW = 0, + GX2_FRONT_FACE_CW = 1, +} GX2FrontFace; + +typedef enum GX2IndexType +{ + GX2_INDEX_TYPE_U16_LE = 0, + GX2_INDEX_TYPE_U32_LE = 1, + GX2_INDEX_TYPE_U16 = 4, + GX2_INDEX_TYPE_U32 = 9, +} GX2IndexType; + +typedef enum GX2InvalidateMode +{ + GX2_INVALIDATE_MODE_ATTRIBUTE_BUFFER = 1 << 0, + GX2_INVALIDATE_MODE_TEXTURE = 1 << 1, + GX2_INVALIDATE_MODE_UNIFORM_BLOCK = 1 << 2, + GX2_INVALIDATE_MODE_SHADER = 1 << 3, + GX2_INVALIDATE_MODE_COLOR_BUFFER = 1 << 4, + GX2_INVALIDATE_MODE_DEPTH_BUFFER = 1 << 5, + GX2_INVALIDATE_MODE_CPU = 1 << 6, + GX2_INVALIDATE_MODE_STREAM_OUT_BUFFER = 1 << 7, + GX2_INVALIDATE_MODE_EXPORT_BUFFER = 1 << 8, + GX2_INVALIDATE_MODE_CPU_ATTRIBUTE_BUFFER= GX2_INVALIDATE_MODE_CPU | GX2_INVALIDATE_MODE_ATTRIBUTE_BUFFER, + GX2_INVALIDATE_MODE_CPU_TEXTURE = GX2_INVALIDATE_MODE_CPU | GX2_INVALIDATE_MODE_TEXTURE, + GX2_INVALIDATE_MODE_CPU_SHADER = GX2_INVALIDATE_MODE_CPU | GX2_INVALIDATE_MODE_SHADER, +} GX2InvalidateMode; + +typedef enum GX2InitAttributes +{ + GX2_INIT_END = 0, + GX2_INIT_CMD_BUF_BASE = 1, + GX2_INIT_CMD_BUF_POOL_SIZE = 2, + GX2_INIT_ARGC = 7, + GX2_INIT_ARGV = 8, +} GX2InitAttributes; + +typedef enum GX2LogicOp +{ + GX2_LOGIC_OP_CLEAR = 0x00, + GX2_LOGIC_OP_NOR = 0x11, + GX2_LOGIC_OP_INV_AND = 0x22, + GX2_LOGIC_OP_INV_COPY = 0x33, + GX2_LOGIC_OP_REV_AND = 0x44, + GX2_LOGIC_OP_INV = 0x55, + GX2_LOGIC_OP_XOR = 0x66, + GX2_LOGIC_OP_NOT_AND = 0x77, + GX2_LOGIC_OP_AND = 0x88, + GX2_LOGIC_OP_EQUIV = 0x99, + GX2_LOGIC_OP_NOP = 0xAA, + GX2_LOGIC_OP_INV_OR = 0xBB, + GX2_LOGIC_OP_COPY = 0xCC, + GX2_LOGIC_OP_REV_OR = 0xDD, + GX2_LOGIC_OP_OR = 0xEE, + GX2_LOGIC_OP_SET = 0xFF, +} GX2LogicOp; + +typedef enum GX2PrimitiveMode +{ + GX2_PRIMITIVE_MODE_LINES = 2, + GX2_PRIMITIVE_MODE_LINE_STRIP = 3, + GX2_PRIMITIVE_MODE_TRIANGLES = 4, + GX2_PRIMITIVE_MODE_TRIANGLE_FAN = 5, + GX2_PRIMITIVE_MODE_TRIANGLE_STRIP = 6, + GX2_PRIMITIVE_MODE_QUADS = 19, + GX2_PRIMITIVE_MODE_QUAD_STRIP = 20, +} GX2PrimitiveMode; + +typedef enum GX2PolygonMode +{ + GX2_POLYGON_MODE_POINT = 0, + GX2_POLYGON_MODE_LINE = 1, + GX2_POLYGON_MODE_TRIANGLE = 2, +} GX2PolygonMode; + +typedef enum GX2RenderTarget +{ + GX2_RENDER_TARGET_0 = 0, + GX2_RENDER_TARGET_1 = 1, + GX2_RENDER_TARGET_2 = 2, + GX2_RENDER_TARGET_3 = 3, + GX2_RENDER_TARGET_4 = 4, + GX2_RENDER_TARGET_5 = 5, + GX2_RENDER_TARGET_6 = 6, +} GX2RenderTarget; + +typedef enum GX2RoundingMode +{ + GX2_ROUNDING_MODE_ROUND_TO_EVEN = 0, + GX2_ROUNDING_MODE_TRUNCATE = 1, +} GX2RoundingMode; + +typedef enum GX2SamplerVarType +{ + GX2_SAMPLER_VAR_TYPE_SAMPLER_1D = 0, + GX2_SAMPLER_VAR_TYPE_SAMPLER_2D = 1, + GX2_SAMPLER_VAR_TYPE_SAMPLER_3D = 3, + GX2_SAMPLER_VAR_TYPE_SAMPLER_CUBE = 4, +} GX2SamplerVarType; + +typedef enum GX2ScanTarget +{ + GX2_SCAN_TARGET_TV = 1, + GX2_SCAN_TARGET_DRC = 4, +} GX2ScanTarget; + +typedef enum GX2ShaderMode +{ + GX2_SHADER_MODE_UNIFORM_REGISTER = 0, + GX2_SHADER_MODE_UNIFORM_BLOCK = 1, + GX2_SHADER_MODE_GEOMETRY_SHADER = 2, + GX2_SHADER_MODE_COMPUTE_SHADER = 3, +} GX2ShaderMode; + +typedef enum GX2ShaderVarType +{ + GX2_SHADER_VAR_TYPE_INT = 2, + GX2_SHADER_VAR_TYPE_FLOAT = 4, + GX2_SHADER_VAR_TYPE_FLOAT2 = 9, + GX2_SHADER_VAR_TYPE_FLOAT3 = 10, + GX2_SHADER_VAR_TYPE_FLOAT4 = 11, + GX2_SHADER_VAR_TYPE_INT2 = 15, + GX2_SHADER_VAR_TYPE_INT3 = 16, + GX2_SHADER_VAR_TYPE_INT4 = 17, + GX2_SHADER_VAR_TYPE_MATRIX4X4 = 29, +} GX2ShaderVarType; + +typedef enum GX2StencilFunction +{ + GX2_STENCIL_FUNCTION_KEEP = 0, + GX2_STENCIL_FUNCTION_ZERO = 1, + GX2_STENCIL_FUNCTION_REPLACE = 2, + GX2_STENCIL_FUNCTION_INCR_CLAMP = 3, + GX2_STENCIL_FUNCTION_DECR_CLAMP = 4, + GX2_STENCIL_FUNCTION_INV = 5, + GX2_STENCIL_FUNCTION_INCR_WRAP = 6, + GX2_STENCIL_FUNCTION_DECR_WRAP = 7, +} GX2StencilFunction; + +typedef enum +{ + GX2_SURFACE_DIM_TEXTURE_1D = 0, + GX2_SURFACE_DIM_TEXTURE_2D = 1, + GX2_SURFACE_DIM_TEXTURE_3D = 2, + GX2_SURFACE_DIM_TEXTURE_CUBE = 3, + GX2_SURFACE_DIM_TEXTURE_1D_ARRAY = 4, + GX2_SURFACE_DIM_TEXTURE_2D_ARRAY = 5, + GX2_SURFACE_DIM_TEXTURE_2D_MSAA = 6, + GX2_SURFACE_DIM_TEXTURE_2D_MSAA_ARRAY = 7, +} GX2SurfaceDim; + +typedef enum +{ + GX2_SURFACE_FORMAT_INVALID = 0x00, + GX2_SURFACE_FORMAT_UNORM_R4_G4 = 0x02, + GX2_SURFACE_FORMAT_UNORM_R4_G4_B4_A4 = 0x0b, + GX2_SURFACE_FORMAT_UNORM_R8 = 0x01, + GX2_SURFACE_FORMAT_UNORM_R8_G8 = 0x07, + GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8 = 0x01a, + GX2_SURFACE_FORMAT_UNORM_R16 = 0x05, + GX2_SURFACE_FORMAT_UNORM_R16_G16 = 0x0f, + GX2_SURFACE_FORMAT_UNORM_R16_G16_B16_A16 = 0x01f, + GX2_SURFACE_FORMAT_UNORM_R5_G6_B5 = 0x08, + GX2_SURFACE_FORMAT_UNORM_R5_G5_B5_A1 = 0x0a, + GX2_SURFACE_FORMAT_UNORM_A1_B5_G5_R5 = 0x0c, + GX2_SURFACE_FORMAT_UNORM_R24_X8 = 0x011, + GX2_SURFACE_FORMAT_UNORM_A2_B10_G10_R10 = 0x01b, + GX2_SURFACE_FORMAT_UNORM_R10_G10_B10_A2 = 0x019, + GX2_SURFACE_FORMAT_UNORM_BC1 = 0x031, + GX2_SURFACE_FORMAT_UNORM_BC2 = 0x032, + GX2_SURFACE_FORMAT_UNORM_BC3 = 0x033, + GX2_SURFACE_FORMAT_UNORM_BC4 = 0x034, + GX2_SURFACE_FORMAT_UNORM_BC5 = 0x035, + GX2_SURFACE_FORMAT_UNORM_NV12 = 0x081, + + GX2_SURFACE_FORMAT_UINT_R8 = 0x101, + GX2_SURFACE_FORMAT_UINT_R8_G8 = 0x107, + GX2_SURFACE_FORMAT_UINT_R8_G8_B8_A8 = 0x11a, + GX2_SURFACE_FORMAT_UINT_R16 = 0x105, + GX2_SURFACE_FORMAT_UINT_R16_G16 = 0x10f, + GX2_SURFACE_FORMAT_UINT_R16_G16_B16_A16 = 0x11f, + GX2_SURFACE_FORMAT_UINT_R32 = 0x10d, + GX2_SURFACE_FORMAT_UINT_R32_G32 = 0x11d, + GX2_SURFACE_FORMAT_UINT_R32_G32_B32_A32 = 0x122, + GX2_SURFACE_FORMAT_UINT_A2_B10_G10_R10 = 0x11b, + GX2_SURFACE_FORMAT_UINT_R10_G10_B10_A2 = 0x119, + GX2_SURFACE_FORMAT_UINT_X24_G8 = 0x111, + GX2_SURFACE_FORMAT_UINT_G8_X24 = 0x11c, + + GX2_SURFACE_FORMAT_SNORM_R8 = 0x201, + GX2_SURFACE_FORMAT_SNORM_R8_G8 = 0x207, + GX2_SURFACE_FORMAT_SNORM_R8_G8_B8_A8 = 0x21a, + GX2_SURFACE_FORMAT_SNORM_R16 = 0x205, + GX2_SURFACE_FORMAT_SNORM_R16_G16 = 0x20f, + GX2_SURFACE_FORMAT_SNORM_R16_G16_B16_A16 = 0x21f, + GX2_SURFACE_FORMAT_SNORM_R10_G10_B10_A2 = 0x219, + GX2_SURFACE_FORMAT_SNORM_BC4 = 0x234, + GX2_SURFACE_FORMAT_SNORM_BC5 = 0x235, + + GX2_SURFACE_FORMAT_SINT_R8 = 0x301, + GX2_SURFACE_FORMAT_SINT_R8_G8 = 0x307, + GX2_SURFACE_FORMAT_SINT_R8_G8_B8_A8 = 0x31a, + GX2_SURFACE_FORMAT_SINT_R16 = 0x305, + GX2_SURFACE_FORMAT_SINT_R16_G16 = 0x30f, + GX2_SURFACE_FORMAT_SINT_R16_G16_B16_A16 = 0x31f, + GX2_SURFACE_FORMAT_SINT_R32 = 0x30d, + GX2_SURFACE_FORMAT_SINT_R32_G32 = 0x31d, + GX2_SURFACE_FORMAT_SINT_R32_G32_B32_A32 = 0x322, + GX2_SURFACE_FORMAT_SINT_R10_G10_B10_A2 = 0x319, + + GX2_SURFACE_FORMAT_SRGB_R8_G8_B8_A8 = 0x41a, + GX2_SURFACE_FORMAT_SRGB_BC1 = 0x431, + GX2_SURFACE_FORMAT_SRGB_BC2 = 0x432, + GX2_SURFACE_FORMAT_SRGB_BC3 = 0x433, + + GX2_SURFACE_FORMAT_FLOAT_R32 = 0x80e, + GX2_SURFACE_FORMAT_FLOAT_R32_G32 = 0x81e, + GX2_SURFACE_FORMAT_FLOAT_R32_G32_B32_A32 = 0x823, + GX2_SURFACE_FORMAT_FLOAT_R16 = 0x806, + GX2_SURFACE_FORMAT_FLOAT_R16_G16 = 0x810, + GX2_SURFACE_FORMAT_FLOAT_R16_G16_B16_A16 = 0x820, + GX2_SURFACE_FORMAT_FLOAT_R11_G11_B10 = 0x816, + GX2_SURFACE_FORMAT_FLOAT_D24_S8 = 0x811, + GX2_SURFACE_FORMAT_FLOAT_X8_X24 = 0x81c, +} GX2SurfaceFormat; + +typedef enum GX2SurfaceUse +{ + GX2_SURFACE_USE_TEXTURE = 1 << 0, + GX2_SURFACE_USE_COLOR_BUFFER = 1 << 1, + GX2_SURFACE_USE_DEPTH_BUFFER = 1 << 2, + GX2_SURFACE_USE_SCAN_BUFFER = 1 << 3, + GX2_SURFACE_USE_TV = 1 << 31, + GX2_SURFACE_USE_TEXTURE_COLOR_BUFFER_TV = (GX2_SURFACE_USE_TEXTURE | GX2_SURFACE_USE_COLOR_BUFFER | GX2_SURFACE_USE_TV) +} GX2SurfaceUse; + +typedef enum GX2TessellationMode +{ + GX2_TESSELLATION_MODE_DISCRETE = 0, + GX2_TESSELLATION_MODE_CONTINUOUS = 1, + GX2_TESSELLATION_MODE_ADAPTIVE = 2, +} GX2TessellationMode; + +typedef enum GX2TexBorderType +{ + GX2_TEX_BORDER_TYPE_TRANSPARENT_BLACK = 0, + GX2_TEX_BORDER_TYPE_BLACK = 1, + GX2_TEX_BORDER_TYPE_WHITE = 2, + GX2_TEX_BORDER_TYPE_VARIABLE = 3, +} GX2TexBorderType; + +typedef enum GX2TexClampMode +{ + GX2_TEX_CLAMP_MODE_WRAP = 0, + GX2_TEX_CLAMP_MODE_MIRROR = 1, + GX2_TEX_CLAMP_MODE_CLAMP = 2, + GX2_TEX_CLAMP_MODE_MIRROR_ONCE = 3, + GX2_TEX_CLAMP_MODE_CLAMP_BORDER = 6, +} GX2TexClampMode; + +typedef enum GX2TexMipFilterMode +{ + GX2_TEX_MIP_FILTER_MODE_NONE = 0, + GX2_TEX_MIP_FILTER_MODE_POINT = 1, + GX2_TEX_MIP_FILTER_MODE_LINEAR = 2, +} GX2TexMipFilterMode; + +typedef enum GX2TexMipPerfMode +{ + GX2_TEX_MIP_PERF_MODE_DISABLE = 0, +} GX2TexMipPerfMode; + +typedef enum GX2TexXYFilterMode +{ + GX2_TEX_XY_FILTER_MODE_POINT = 0, + GX2_TEX_XY_FILTER_MODE_LINEAR = 1, +} GX2TexXYFilterMode; + +typedef enum GX2TexAnisoRatio +{ + GX2_TEX_ANISO_RATIO_NONE = 0, +} GX2TexAnisoRatio; + +typedef enum GX2TexZFilterMode +{ + GX2_TEX_Z_FILTER_MODE_NONE = 0, + GX2_TEX_Z_FILTER_MODE_POINT = 1, + GX2_TEX_Z_FILTER_MODE_LINEAR = 2, +} GX2TexZFilterMode; + +typedef enum GX2TexZPerfMode +{ + GX2_TEX_Z_PERF_MODE_DISABLED = 0, +} GX2TexZPerfMode; + +typedef enum GX2TileMode +{ + GX2_TILE_MODE_DEFAULT = 0, + GX2_TILE_MODE_LINEAR_ALIGNED = 1, + GX2_TILE_MODE_TILED_1D_THIN1 = 2, + GX2_TILE_MODE_TILED_1D_THICK = 3, + GX2_TILE_MODE_TILED_2D_THIN1 = 4, + GX2_TILE_MODE_TILED_2D_THIN2 = 5, + GX2_TILE_MODE_TILED_2D_THIN4 = 6, + GX2_TILE_MODE_TILED_2D_THICK = 7, + GX2_TILE_MODE_TILED_2B_THIN1 = 8, + GX2_TILE_MODE_TILED_2B_THIN2 = 9, + GX2_TILE_MODE_TILED_2B_THIN4 = 10, + GX2_TILE_MODE_TILED_2B_THICK = 11, + GX2_TILE_MODE_TILED_3D_THIN1 = 12, + GX2_TILE_MODE_TILED_3D_THICK = 13, + GX2_TILE_MODE_TILED_3B_THIN1 = 14, + GX2_TILE_MODE_TILED_3B_THICK = 15, + GX2_TILE_MODE_LINEAR_SPECIAL = 16, +} GX2TileMode; + +typedef enum GX2TVRenderMode +{ + GX2_TV_RENDER_MODE_STANDARD_480P = 1, + GX2_TV_RENDER_MODE_WIDE_480P = 2, + GX2_TV_RENDER_MODE_WIDE_720P = 3, + GX2_TV_RENDER_MODE_WIDE_1080P = 5, +} GX2TVRenderMode; + +typedef enum GX2TVScanMode +{ + GX2_TV_SCAN_MODE_NONE = 0, + GX2_TV_SCAN_MODE_480I = 1, + GX2_TV_SCAN_MODE_480P = 2, + GX2_TV_SCAN_MODE_720P = 3, + GX2_TV_SCAN_MODE_1080I = 5, + GX2_TV_SCAN_MODE_1080P = 6, +} GX2TVScanMode; + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/gx2/event.h b/wiiu/wut/include/gx2/event.h new file mode 100644 index 0000000000..135585711e --- /dev/null +++ b/wiiu/wut/include/gx2/event.h @@ -0,0 +1,79 @@ +#pragma once +#include +#include +#include "enum.h" + +/** + * \defgroup gx2_event Event + * \ingroup gx2 + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct GX2DisplayListOverrunData GX2DisplayListOverrunData; +typedef void (*GX2EventCallbackFunction)(GX2EventType, void *); + +struct GX2DisplayListOverrunData +{ + //! Pointer to overrun display list + void *oldList; + + //! Size of overrun display list + uint32_t oldSize; + + //! Pointer to new display list + void *newList; + + //! Size of new display list + uint32_t newSize; + + UNKNOWN(8); +}; +CHECK_OFFSET(GX2DisplayListOverrunData, 0x00, oldList); +CHECK_OFFSET(GX2DisplayListOverrunData, 0x04, oldSize); +CHECK_OFFSET(GX2DisplayListOverrunData, 0x08, newList); +CHECK_OFFSET(GX2DisplayListOverrunData, 0x0C, newSize); +CHECK_SIZE(GX2DisplayListOverrunData, 0x18); + +BOOL +GX2DrawDone(); + +void +GX2WaitForVsync(); + +void +GX2WaitForFlip(); + +void +GX2SetEventCallback(GX2EventType type, + GX2EventCallbackFunction func, + void *userData); + +void +GX2GetEventCallback(GX2EventType type, + GX2EventCallbackFunction *funcOut, + void **userDataOut); + +OSTime +GX2GetRetiredTimeStamp(); + +OSTime +GX2GetLastSubmittedTimeStamp(); + +BOOL +GX2WaitTimeStamp(OSTime time); + +void +GX2GetSwapStatus(uint32_t *swapCount, + uint32_t *flipCount, + OSTime *lastFlip, + OSTime *lastVsync); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/gx2/mem.h b/wiiu/wut/include/gx2/mem.h new file mode 100644 index 0000000000..a37b0d74fa --- /dev/null +++ b/wiiu/wut/include/gx2/mem.h @@ -0,0 +1,24 @@ +#pragma once +#include +#include "enum.h" + +/** + * \defgroup gx2_mem Memory + * \ingroup gx2 + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +void +GX2Invalidate(GX2InvalidateMode mode, + void *buffer, + uint32_t size); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/gx2/registers.h b/wiiu/wut/include/gx2/registers.h new file mode 100644 index 0000000000..618133504a --- /dev/null +++ b/wiiu/wut/include/gx2/registers.h @@ -0,0 +1,622 @@ +#pragma once +#include +#include "enum.h" +#include "surface.h" + +/** + * \defgroup gx2_registers Registers + * \ingroup gx2 + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct GX2AAMaskReg GX2AAMaskReg; +typedef struct GX2AlphaTestReg GX2AlphaTestReg; +typedef struct GX2AlphaToMaskReg GX2AlphaToMaskReg; +typedef struct GX2BlendControlReg GX2BlendControlReg; +typedef struct GX2BlendConstantColorReg GX2BlendConstantColorReg; +typedef struct GX2ColorControlReg GX2ColorControlReg; +typedef struct GX2DepthStencilControlReg GX2DepthStencilControlReg; +typedef struct GX2StencilMaskReg GX2StencilMaskReg; +typedef struct GX2LineWidthReg GX2LineWidthReg; +typedef struct GX2PointSizeReg GX2PointSizeReg; +typedef struct GX2PointLimitsReg GX2PointLimitsReg; +typedef struct GX2PolygonControlReg GX2PolygonControlReg; +typedef struct GX2PolygonOffsetReg GX2PolygonOffsetReg; +typedef struct GX2ScissorReg GX2ScissorReg; +typedef struct GX2TargetChannelMaskReg GX2TargetChannelMaskReg; +typedef struct GX2ViewportReg GX2ViewportReg; + +struct GX2AAMaskReg +{ + uint32_t pa_sc_aa_mask; +}; +CHECK_OFFSET(GX2AAMaskReg, 0, pa_sc_aa_mask); +CHECK_SIZE(GX2AAMaskReg, 4); + +struct GX2AlphaTestReg +{ + uint32_t sx_alpha_test_control; + uint32_t sx_alpha_ref; +}; +CHECK_OFFSET(GX2AlphaTestReg, 0, sx_alpha_test_control); +CHECK_OFFSET(GX2AlphaTestReg, 4, sx_alpha_ref); +CHECK_SIZE(GX2AlphaTestReg, 8); + +struct GX2AlphaToMaskReg +{ + uint32_t db_alpha_to_mask; +}; +CHECK_OFFSET(GX2AlphaToMaskReg, 0, db_alpha_to_mask); +CHECK_SIZE(GX2AlphaToMaskReg, 4); + +struct GX2BlendControlReg +{ + GX2RenderTarget target; + uint32_t cb_blend_control; +}; +CHECK_OFFSET(GX2BlendControlReg, 0, target); +CHECK_OFFSET(GX2BlendControlReg, 4, cb_blend_control); +CHECK_SIZE(GX2BlendControlReg, 8); + +struct GX2BlendConstantColorReg +{ + float red; + float green; + float blue; + float alpha; +}; +CHECK_OFFSET(GX2BlendConstantColorReg, 0x00, red); +CHECK_OFFSET(GX2BlendConstantColorReg, 0x04, green); +CHECK_OFFSET(GX2BlendConstantColorReg, 0x08, blue); +CHECK_OFFSET(GX2BlendConstantColorReg, 0x0c, alpha); +CHECK_SIZE(GX2BlendConstantColorReg, 0x10); + +struct GX2ColorControlReg +{ + uint32_t cb_color_control; +}; +CHECK_OFFSET(GX2ColorControlReg, 0x00, cb_color_control); +CHECK_SIZE(GX2ColorControlReg, 4); + +struct GX2DepthStencilControlReg +{ + uint32_t db_depth_control; +}; +CHECK_OFFSET(GX2DepthStencilControlReg, 0, db_depth_control); +CHECK_SIZE(GX2DepthStencilControlReg, 4); + +struct GX2StencilMaskReg +{ + uint32_t db_stencilrefmask; + uint32_t db_stencilrefmask_bf; +}; +CHECK_OFFSET(GX2StencilMaskReg, 0, db_stencilrefmask); +CHECK_OFFSET(GX2StencilMaskReg, 4, db_stencilrefmask_bf); +CHECK_SIZE(GX2StencilMaskReg, 8); + +struct GX2LineWidthReg +{ + uint32_t pa_su_line_cntl; +}; +CHECK_OFFSET(GX2LineWidthReg, 0, pa_su_line_cntl); +CHECK_SIZE(GX2LineWidthReg, 4); + +struct GX2PointSizeReg +{ + uint32_t pa_su_point_size; +}; +CHECK_OFFSET(GX2PointSizeReg, 0, pa_su_point_size); +CHECK_SIZE(GX2PointSizeReg, 4); + +struct GX2PointLimitsReg +{ + uint32_t pa_su_point_minmax; +}; +CHECK_OFFSET(GX2PointLimitsReg, 0, pa_su_point_minmax); +CHECK_SIZE(GX2PointLimitsReg, 4); + +struct GX2PolygonControlReg +{ + uint32_t pa_su_sc_mode_cntl; +}; +CHECK_OFFSET(GX2PolygonControlReg, 0, pa_su_sc_mode_cntl); +CHECK_SIZE(GX2PolygonControlReg, 4); + +struct GX2PolygonOffsetReg +{ + uint32_t pa_su_poly_offset_front_scale; + uint32_t pa_su_poly_offset_front_offset; + uint32_t pa_su_poly_offset_back_scale; + uint32_t pa_su_poly_offset_back_offset; + uint32_t pa_su_poly_offset_clamp; +}; +CHECK_OFFSET(GX2PolygonOffsetReg, 0x00, pa_su_poly_offset_front_scale); +CHECK_OFFSET(GX2PolygonOffsetReg, 0x04, pa_su_poly_offset_front_offset); +CHECK_OFFSET(GX2PolygonOffsetReg, 0x08, pa_su_poly_offset_back_scale); +CHECK_OFFSET(GX2PolygonOffsetReg, 0x0C, pa_su_poly_offset_back_offset); +CHECK_OFFSET(GX2PolygonOffsetReg, 0x10, pa_su_poly_offset_clamp); +CHECK_SIZE(GX2PolygonOffsetReg, 20); + +struct GX2ScissorReg +{ + uint32_t pa_sc_generic_scissor_tl; + uint32_t pa_sc_generic_scissor_br; +}; +CHECK_OFFSET(GX2ScissorReg, 0x00, pa_sc_generic_scissor_tl); +CHECK_OFFSET(GX2ScissorReg, 0x04, pa_sc_generic_scissor_br); +CHECK_SIZE(GX2ScissorReg, 8); + +struct GX2TargetChannelMaskReg +{ + uint32_t cb_target_mask; +}; +CHECK_OFFSET(GX2TargetChannelMaskReg, 0x00, cb_target_mask); +CHECK_SIZE(GX2TargetChannelMaskReg, 4); + +struct GX2ViewportReg +{ + uint32_t pa_cl_vport_xscale; + uint32_t pa_cl_vport_xoffset; + uint32_t pa_cl_vport_yscale; + uint32_t pa_cl_vport_yoffset; + uint32_t pa_cl_vport_zscale; + uint32_t pa_cl_vport_zoffset; + uint32_t pa_cl_gb_vert_clip_adj; + uint32_t pa_cl_gb_vert_disc_adj; + uint32_t pa_cl_gb_horz_clip_adj; + uint32_t pa_cl_gb_horz_disc_adj; + uint32_t pa_sc_vport_zmin; + uint32_t pa_sc_vport_zmax; +}; +CHECK_OFFSET(GX2ViewportReg, 0x00, pa_cl_vport_xscale); +CHECK_OFFSET(GX2ViewportReg, 0x04, pa_cl_vport_xoffset); +CHECK_OFFSET(GX2ViewportReg, 0x08, pa_cl_vport_yscale); +CHECK_OFFSET(GX2ViewportReg, 0x0C, pa_cl_vport_yoffset); +CHECK_OFFSET(GX2ViewportReg, 0x10, pa_cl_vport_zscale); +CHECK_OFFSET(GX2ViewportReg, 0x14, pa_cl_vport_zoffset); +CHECK_OFFSET(GX2ViewportReg, 0x18, pa_cl_gb_vert_clip_adj); +CHECK_OFFSET(GX2ViewportReg, 0x1C, pa_cl_gb_vert_disc_adj); +CHECK_OFFSET(GX2ViewportReg, 0x20, pa_cl_gb_horz_clip_adj); +CHECK_OFFSET(GX2ViewportReg, 0x24, pa_cl_gb_horz_disc_adj); +CHECK_OFFSET(GX2ViewportReg, 0x28, pa_sc_vport_zmin); +CHECK_OFFSET(GX2ViewportReg, 0x2C, pa_sc_vport_zmax); +CHECK_SIZE(GX2ViewportReg, 48); + +void +GX2SetAAMask(uint8_t upperLeft, + uint8_t upperRight, + uint8_t lowerLeft, + uint8_t lowerRight); + +void +GX2InitAAMaskReg(GX2AAMaskReg *reg, + uint8_t upperLeft, + uint8_t upperRight, + uint8_t lowerLeft, + uint8_t lowerRight); + +void +GX2GetAAMaskReg(GX2AAMaskReg *reg, + uint8_t *upperLeft, + uint8_t *upperRight, + uint8_t *lowerLeft, + uint8_t *lowerRight); + +void +GX2SetAAMaskReg(GX2AAMaskReg *reg); + +void +GX2SetAlphaTest(BOOL alphaTest, + GX2CompareFunction func, + float ref); + +void +GX2InitAlphaTestReg(GX2AlphaTestReg *reg, + BOOL alphaTest, + GX2CompareFunction func, + float ref); + +void +GX2GetAlphaTestReg(const GX2AlphaTestReg *reg, + BOOL *alphaTest, + GX2CompareFunction *func, + float *ref); + +void +GX2SetAlphaTestReg(GX2AlphaTestReg *reg); + +void +GX2SetAlphaToMask(BOOL alphaToMask, + GX2AlphaToMaskMode mode); + +void +GX2InitAlphaToMaskReg(GX2AlphaToMaskReg *reg, + BOOL alphaToMask, + GX2AlphaToMaskMode mode); + +void +GX2GetAlphaToMaskReg(const GX2AlphaToMaskReg *reg, + BOOL *alphaToMask, + GX2AlphaToMaskMode *mode); + +void +GX2SetAlphaToMaskReg(GX2AlphaToMaskReg *reg); + +void +GX2SetBlendConstantColor(float red, + float green, + float blue, + float alpha); + +void +GX2InitBlendConstantColorReg(GX2BlendConstantColorReg *reg, + float red, + float green, + float blue, + float alpha); + +void +GX2GetBlendConstantColorReg(GX2BlendConstantColorReg *reg, + float *red, + float *green, + float *blue, + float *alpha); + +void +GX2SetBlendConstantColorReg(GX2BlendConstantColorReg *reg); + +void +GX2SetBlendControl(GX2RenderTarget target, + GX2BlendMode colorSrcBlend, + GX2BlendMode colorDstBlend, + GX2BlendCombineMode colorCombine, + BOOL useAlphaBlend, + GX2BlendMode alphaSrcBlend, + GX2BlendMode alphaDstBlend, + GX2BlendCombineMode alphaCombine); + +void +GX2InitBlendControlReg(GX2BlendControlReg *reg, + GX2RenderTarget target, + GX2BlendMode colorSrcBlend, + GX2BlendMode colorDstBlend, + GX2BlendCombineMode colorCombine, + BOOL useAlphaBlend, + GX2BlendMode alphaSrcBlend, + GX2BlendMode alphaDstBlend, + GX2BlendCombineMode alphaCombine); + +void +GX2GetBlendControlReg(GX2BlendControlReg *reg, + GX2RenderTarget *target, + GX2BlendMode *colorSrcBlend, + GX2BlendMode *colorDstBlend, + GX2BlendCombineMode *colorCombine, + BOOL *useAlphaBlend, + GX2BlendMode *alphaSrcBlend, + GX2BlendMode *alphaDstBlend, + GX2BlendCombineMode *alphaCombine); + +void +GX2SetBlendControlReg(GX2BlendControlReg *reg); + +void +GX2SetColorControl(GX2LogicOp rop3, + uint8_t targetBlendEnable, + BOOL multiWriteEnable, + BOOL colorWriteEnable); + +void +GX2InitColorControlReg(GX2ColorControlReg *reg, + GX2LogicOp rop3, + uint8_t targetBlendEnable, + BOOL multiWriteEnable, + BOOL colorWriteEnable); + +void +GX2GetColorControlReg(GX2ColorControlReg *reg, + GX2LogicOp *rop3, + uint8_t *targetBlendEnable, + BOOL *multiWriteEnable, + BOOL *colorWriteEnable); + +void +GX2SetColorControlReg(GX2ColorControlReg *reg); + +void +GX2SetDepthOnlyControl(BOOL depthTest, + BOOL depthWrite, + GX2CompareFunction depthCompare); + +void +GX2SetDepthStencilControl(BOOL depthTest, + BOOL depthWrite, + GX2CompareFunction depthCompare, + BOOL stencilTest, + BOOL backfaceStencil, + GX2CompareFunction frontStencilFunc, + GX2StencilFunction frontStencilZPass, + GX2StencilFunction frontStencilZFail, + GX2StencilFunction frontStencilFail, + GX2CompareFunction backStencilFunc, + GX2StencilFunction backStencilZPass, + GX2StencilFunction backStencilZFail, + GX2StencilFunction backStencilFail); + +void +GX2InitDepthStencilControlReg(GX2DepthStencilControlReg *reg, + BOOL depthTest, + BOOL depthWrite, + GX2CompareFunction depthCompare, + BOOL stencilTest, + BOOL backfaceStencil, + GX2CompareFunction frontStencilFunc, + GX2StencilFunction frontStencilZPass, + GX2StencilFunction frontStencilZFail, + GX2StencilFunction frontStencilFail, + GX2CompareFunction backStencilFunc, + GX2StencilFunction backStencilZPass, + GX2StencilFunction backStencilZFail, + GX2StencilFunction backStencilFail); + +void +GX2GetDepthStencilControlReg(GX2DepthStencilControlReg *reg, + BOOL *depthTest, + BOOL *depthWrite, + GX2CompareFunction *depthCompare, + BOOL *stencilTest, + BOOL *backfaceStencil, + GX2CompareFunction *frontStencilFunc, + GX2StencilFunction *frontStencilZPass, + GX2StencilFunction *frontStencilZFail, + GX2StencilFunction *frontStencilFail, + GX2CompareFunction *backStencilFunc, + GX2StencilFunction *backStencilZPass, + GX2StencilFunction *backStencilZFail, + GX2StencilFunction *backStencilFail); + +void +GX2SetDepthStencilControlReg(GX2DepthStencilControlReg *reg); + +void +GX2SetStencilMask(uint8_t frontMask, + uint8_t frontWriteMask, + uint8_t frontRef, + uint8_t backMask, + uint8_t backWriteMask, + uint8_t backRef); + +void +GX2InitStencilMaskReg(GX2StencilMaskReg *reg, + uint8_t frontMask, + uint8_t frontWriteMask, + uint8_t frontRef, + uint8_t backMask, + uint8_t backWriteMask, + uint8_t backRef); + +void +GX2GetStencilMaskReg(GX2StencilMaskReg *reg, + uint8_t *frontMask, + uint8_t *frontWriteMask, + uint8_t *frontRef, + uint8_t *backMask, + uint8_t *backWriteMask, + uint8_t *backRef); + +void +GX2SetStencilMaskReg(GX2StencilMaskReg *reg); + +void +GX2SetLineWidth(float width); + +void +GX2InitLineWidthReg(GX2LineWidthReg *reg, + float width); + +void +GX2GetLineWidthReg(GX2LineWidthReg *reg, + float *width); + +void +GX2SetLineWidthReg(GX2LineWidthReg *reg); + +void +GX2SetPointSize(float width, + float height); + +void +GX2InitPointSizeReg(GX2PointSizeReg *reg, + float width, + float height); + +void +GX2GetPointSizeReg(GX2PointSizeReg *reg, + float *width, + float *height); + +void +GX2SetPointSizeReg(GX2PointSizeReg *reg); + +void +GX2SetPointLimits(float min, + float max); + +void +GX2InitPointLimitsReg(GX2PointLimitsReg *reg, + float min, + float max); + +void +GX2GetPointLimitsReg(GX2PointLimitsReg *reg, + float *min, + float *max); + +void +GX2SetPointLimitsReg(GX2PointLimitsReg *reg); + +void +GX2SetCullOnlyControl(GX2FrontFace frontFace, + BOOL cullFront, + BOOL cullBack); + +void +GX2SetPolygonControl(GX2FrontFace frontFace, + BOOL cullFront, + BOOL cullBack, + BOOL polyMode, + GX2PolygonMode polyModeFront, + GX2PolygonMode polyModeBack, + BOOL polyOffsetFrontEnable, + BOOL polyOffsetBackEnable, + BOOL polyOffsetParaEnable); + +void +GX2InitPolygonControlReg(GX2PolygonControlReg *reg, + GX2FrontFace frontFace, + BOOL cullFront, + BOOL cullBack, + BOOL polyMode, + GX2PolygonMode polyModeFront, + GX2PolygonMode polyModeBack, + BOOL polyOffsetFrontEnable, + BOOL polyOffsetBackEnable, + BOOL polyOffsetParaEnable); + +void +GX2GetPolygonControlReg(GX2PolygonControlReg *reg, + GX2FrontFace *frontFace, + BOOL *cullFront, + BOOL *cullBack, + BOOL *polyMode, + GX2PolygonMode *polyModeFront, + GX2PolygonMode *polyModeBack, + BOOL *polyOffsetFrontEnable, + BOOL *polyOffsetBackEnable, + BOOL *polyOffsetParaEnable); + +void +GX2SetPolygonControlReg(GX2PolygonControlReg *reg); + +void +GX2SetPolygonOffset(float frontOffset, + float frontScale, + float backOffset, + float backScale, + float clamp); + +void +GX2InitPolygonOffsetReg(GX2PolygonOffsetReg *reg, + float frontOffset, + float frontScale, + float backOffset, + float backScale, + float clamp); + +void +GX2GetPolygonOffsetReg(GX2PolygonOffsetReg *reg, + float *frontOffset, + float *frontScale, + float *backOffset, + float *backScale, + float *clamp); + +void +GX2SetPolygonOffsetReg(GX2PolygonOffsetReg *reg); + +void +GX2SetScissor(uint32_t x, + uint32_t y, + uint32_t width, + uint32_t height); + +void +GX2InitScissorReg(GX2ScissorReg *reg, + uint32_t x, + uint32_t y, + uint32_t width, + uint32_t height); + +void +GX2GetScissorReg(GX2ScissorReg *reg, + uint32_t *x, + uint32_t *y, + uint32_t *width, + uint32_t *height); + +void +GX2SetScissorReg(GX2ScissorReg *reg); + +void +GX2SetTargetChannelMasks(GX2ChannelMask mask0, + GX2ChannelMask mask1, + GX2ChannelMask mask2, + GX2ChannelMask mask3, + GX2ChannelMask mask4, + GX2ChannelMask mask5, + GX2ChannelMask mask6, + GX2ChannelMask mask7); + +void +GX2InitTargetChannelMasksReg(GX2TargetChannelMaskReg *reg, + GX2ChannelMask mask0, + GX2ChannelMask mask1, + GX2ChannelMask mask2, + GX2ChannelMask mask3, + GX2ChannelMask mask4, + GX2ChannelMask mask5, + GX2ChannelMask mask6, + GX2ChannelMask mask7); + +void +GX2GetTargetChannelMasksReg(GX2TargetChannelMaskReg *reg, + GX2ChannelMask *mask0, + GX2ChannelMask *mask1, + GX2ChannelMask *mask2, + GX2ChannelMask *mask3, + GX2ChannelMask *mask4, + GX2ChannelMask *mask5, + GX2ChannelMask *mask6, + GX2ChannelMask *mask7); + +void +GX2SetTargetChannelMasksReg(GX2TargetChannelMaskReg *reg); + +void +GX2SetViewport(float x, + float y, + float width, + float height, + float nearZ, + float farZ); + +void +GX2InitViewportReg(GX2ViewportReg *reg, + float x, + float y, + float width, + float height, + float nearZ, + float farZ); + +void +GX2GetViewportReg(GX2ViewportReg *reg, + float *x, + float *y, + float *width, + float *height, + float *nearZ, + float *farZ); + +void +GX2SetViewportReg(GX2ViewportReg *reg); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/gx2/sampler.h b/wiiu/wut/include/gx2/sampler.h new file mode 100644 index 0000000000..cdb1a1df3c --- /dev/null +++ b/wiiu/wut/include/gx2/sampler.h @@ -0,0 +1,78 @@ +#pragma once +#include +#include "enum.h" + +/** + * \defgroup gx2_sampler Sampler + * \ingroup gx2 + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct GX2Sampler GX2Sampler; + +struct GX2Sampler +{ + uint32_t regs[3]; +}; +CHECK_SIZE(GX2Sampler, 12); + +void +GX2InitSampler(GX2Sampler *sampler, + GX2TexClampMode clampMode, + GX2TexXYFilterMode minMagFilterMode); + +void +GX2InitSamplerBorderType(GX2Sampler *sampler, + GX2TexBorderType borderType); + +void +GX2InitSamplerClamping(GX2Sampler *sampler, + GX2TexClampMode clampX, + GX2TexClampMode clampY, + GX2TexClampMode clampZ); + +void +GX2InitSamplerDepthCompare(GX2Sampler *sampler, + GX2CompareFunction depthCompare); + +void +GX2InitSamplerFilterAdjust(GX2Sampler *sampler, + BOOL highPrecision, + GX2TexMipPerfMode perfMip, + GX2TexZPerfMode perfZ); + +void +GX2InitSamplerLOD(GX2Sampler *sampler, + float lodMin, + float lodMax, + float lodBias); + +void +GX2InitSamplerLODAdjust(GX2Sampler *sampler, + float unk1, + BOOL unk2); + +void +GX2InitSamplerRoundingMode(GX2Sampler *sampler, + GX2RoundingMode roundingMode); + +void +GX2InitSamplerXYFilter(GX2Sampler *sampler, + GX2TexXYFilterMode filterMag, + GX2TexXYFilterMode filterMin, + GX2TexAnisoRatio maxAniso); + +void +GX2InitSamplerZMFilter(GX2Sampler *sampler, + GX2TexZFilterMode filterZ, + GX2TexMipFilterMode filterMip); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/gx2/shaders.h b/wiiu/wut/include/gx2/shaders.h new file mode 100644 index 0000000000..f5535626bb --- /dev/null +++ b/wiiu/wut/include/gx2/shaders.h @@ -0,0 +1,466 @@ +#pragma once +#include +#include "enum.h" +#include "sampler.h" +#include "gx2r/buffer.h" + +/** + * \defgroup gx2_shader Shaders + * \ingroup gx2 + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct GX2AttribVar GX2AttribVar; +typedef struct GX2AttribStream GX2AttribStream; +typedef struct GX2FetchShader GX2FetchShader; +typedef struct GX2GeometryShader GX2GeometryShader; +typedef struct GX2LoopVar GX2LoopVar; +typedef struct GX2PixelShader GX2PixelShader; +typedef struct GX2SamplerVar GX2SamplerVar; +typedef struct GX2UniformBlock GX2UniformBlock; +typedef struct GX2UniformVar GX2UniformVar; +typedef struct GX2UniformInitialValue GX2UniformInitialValue; +typedef struct GX2VertexShader GX2VertexShader; + +struct GX2FetchShader +{ + GX2FetchShaderType type; + + struct + { + uint32_t sq_pgm_resources_fs; + } regs; + + uint32_t size; + uint8_t *program; + uint32_t attribCount; + uint32_t numDivisors; + uint32_t divisors[2]; +}; +CHECK_OFFSET(GX2FetchShader, 0x0, type); +CHECK_OFFSET(GX2FetchShader, 0x4, regs.sq_pgm_resources_fs); +CHECK_OFFSET(GX2FetchShader, 0x8, size); +CHECK_OFFSET(GX2FetchShader, 0xc, program); +CHECK_OFFSET(GX2FetchShader, 0x10, attribCount); +CHECK_OFFSET(GX2FetchShader, 0x14, numDivisors); +CHECK_OFFSET(GX2FetchShader, 0x18, divisors); +CHECK_SIZE(GX2FetchShader, 0x20); + +struct GX2UniformBlock +{ + const char *name; + uint32_t offset; + uint32_t size; +}; +CHECK_OFFSET(GX2UniformBlock, 0x00, name); +CHECK_OFFSET(GX2UniformBlock, 0x04, offset); +CHECK_OFFSET(GX2UniformBlock, 0x08, size); +CHECK_SIZE(GX2UniformBlock, 0x0C); + +struct GX2UniformVar +{ + const char *name; + GX2ShaderVarType type; + uint32_t count; + uint32_t offset; + int32_t block; +}; +CHECK_OFFSET(GX2UniformVar, 0x00, name); +CHECK_OFFSET(GX2UniformVar, 0x04, type); +CHECK_OFFSET(GX2UniformVar, 0x08, count); +CHECK_OFFSET(GX2UniformVar, 0x0C, offset); +CHECK_OFFSET(GX2UniformVar, 0x10, block); +CHECK_SIZE(GX2UniformVar, 0x14); + +struct GX2UniformInitialValue +{ + float value[4]; + uint32_t offset; +}; +CHECK_OFFSET(GX2UniformInitialValue, 0x00, value); +CHECK_OFFSET(GX2UniformInitialValue, 0x10, offset); +CHECK_SIZE(GX2UniformInitialValue, 0x14); + +struct GX2LoopVar +{ + uint32_t offset; + uint32_t value; +}; +CHECK_OFFSET(GX2LoopVar, 0x00, offset); +CHECK_OFFSET(GX2LoopVar, 0x04, value); +CHECK_SIZE(GX2LoopVar, 0x08); + +struct GX2SamplerVar +{ + const char *name; + GX2SamplerVarType type; + uint32_t location; +}; +CHECK_OFFSET(GX2SamplerVar, 0x00, name); +CHECK_OFFSET(GX2SamplerVar, 0x04, type); +CHECK_OFFSET(GX2SamplerVar, 0x08, location); +CHECK_SIZE(GX2SamplerVar, 0x0C); + +struct GX2AttribVar +{ + const char *name; + GX2ShaderVarType type; + uint32_t count; + uint32_t location; +}; +CHECK_OFFSET(GX2AttribVar, 0x00, name); +CHECK_OFFSET(GX2AttribVar, 0x04, type); +CHECK_OFFSET(GX2AttribVar, 0x08, count); +CHECK_OFFSET(GX2AttribVar, 0x0C, location); +CHECK_SIZE(GX2AttribVar, 0x10); + +struct GX2VertexShader +{ + struct + { + uint32_t sq_pgm_resources_vs; + uint32_t vgt_primitiveid_en; + uint32_t spi_vs_out_config; + uint32_t num_spi_vs_out_id; + uint32_t spi_vs_out_id[10]; + uint32_t pa_cl_vs_out_cntl; + uint32_t sq_vtx_semantic_clear; + uint32_t num_sq_vtx_semantic; + uint32_t sq_vtx_semantic[32]; + uint32_t vgt_strmout_buffer_en; + uint32_t vgt_vertex_reuse_block_cntl; + uint32_t vgt_hos_reuse_depth; + } regs; + + uint32_t size; + uint8_t *program; + GX2ShaderMode mode; + + uint32_t uniformBlockCount; + GX2UniformBlock *uniformBlocks; + + uint32_t uniformVarCount; + GX2UniformVar *uniformVars; + + uint32_t initialValueCount; + GX2UniformInitialValue *initialValues; + + uint32_t loopVarCount; + GX2LoopVar *loopVars; + + uint32_t samplerVarCount; + GX2SamplerVar *samplerVars; + + uint32_t attribVarCount; + GX2AttribVar *attribVars; + + uint32_t ringItemsize; + + BOOL hasStreamOut; + uint32_t streamOutStride[4]; + + GX2RBuffer gx2rBuffer; +}; +CHECK_OFFSET(GX2VertexShader, 0x00, regs.sq_pgm_resources_vs); +CHECK_OFFSET(GX2VertexShader, 0x04, regs.vgt_primitiveid_en); +CHECK_OFFSET(GX2VertexShader, 0x08, regs.spi_vs_out_config); +CHECK_OFFSET(GX2VertexShader, 0x0C, regs.num_spi_vs_out_id); +CHECK_OFFSET(GX2VertexShader, 0x10, regs.spi_vs_out_id); +CHECK_OFFSET(GX2VertexShader, 0x38, regs.pa_cl_vs_out_cntl); +CHECK_OFFSET(GX2VertexShader, 0x3C, regs.sq_vtx_semantic_clear); +CHECK_OFFSET(GX2VertexShader, 0x40, regs.num_sq_vtx_semantic); +CHECK_OFFSET(GX2VertexShader, 0x44, regs.sq_vtx_semantic); +CHECK_OFFSET(GX2VertexShader, 0xC4, regs.vgt_strmout_buffer_en); +CHECK_OFFSET(GX2VertexShader, 0xC8, regs.vgt_vertex_reuse_block_cntl); +CHECK_OFFSET(GX2VertexShader, 0xCC, regs.vgt_hos_reuse_depth); +CHECK_OFFSET(GX2VertexShader, 0xD0, size); +CHECK_OFFSET(GX2VertexShader, 0xD4, program); +CHECK_OFFSET(GX2VertexShader, 0xD8, mode); +CHECK_OFFSET(GX2VertexShader, 0xDc, uniformBlockCount); +CHECK_OFFSET(GX2VertexShader, 0xE0, uniformBlocks); +CHECK_OFFSET(GX2VertexShader, 0xE4, uniformVarCount); +CHECK_OFFSET(GX2VertexShader, 0xE8, uniformVars); +CHECK_OFFSET(GX2VertexShader, 0xEc, initialValueCount); +CHECK_OFFSET(GX2VertexShader, 0xF0, initialValues); +CHECK_OFFSET(GX2VertexShader, 0xF4, loopVarCount); +CHECK_OFFSET(GX2VertexShader, 0xF8, loopVars); +CHECK_OFFSET(GX2VertexShader, 0xFc, samplerVarCount); +CHECK_OFFSET(GX2VertexShader, 0x100, samplerVars); +CHECK_OFFSET(GX2VertexShader, 0x104, attribVarCount); +CHECK_OFFSET(GX2VertexShader, 0x108, attribVars); +CHECK_OFFSET(GX2VertexShader, 0x10c, ringItemsize); +CHECK_OFFSET(GX2VertexShader, 0x110, hasStreamOut); +CHECK_OFFSET(GX2VertexShader, 0x114, streamOutStride); +CHECK_OFFSET(GX2VertexShader, 0x124, gx2rBuffer); +CHECK_SIZE(GX2VertexShader, 0x134); + +struct GX2PixelShader +{ + struct + { + uint32_t sq_pgm_resources_ps; + uint32_t sq_pgm_exports_ps; + uint32_t spi_ps_in_control_0; + uint32_t spi_ps_in_control_1; + uint32_t num_spi_ps_input_cntl; + uint32_t spi_ps_input_cntls[32]; + uint32_t cb_shader_mask; + uint32_t cb_shader_control; + uint32_t db_shader_control; + uint32_t spi_input_z; + } regs; + + uint32_t size; + uint8_t *program; + GX2ShaderMode mode; + + uint32_t uniformBlockCount; + GX2UniformBlock *uniformBlocks; + + uint32_t uniformVarCount; + GX2UniformVar *uniformVars; + + uint32_t initialValueCount; + GX2UniformInitialValue *initialValues; + + uint32_t loopVarCount; + GX2LoopVar *loopVars; + + uint32_t samplerVarCount; + GX2SamplerVar *samplerVars; + + GX2RBuffer gx2rBuffer; +}; +CHECK_OFFSET(GX2PixelShader, 0x00, regs.sq_pgm_resources_ps); +CHECK_OFFSET(GX2PixelShader, 0x04, regs.sq_pgm_exports_ps); +CHECK_OFFSET(GX2PixelShader, 0x08, regs.spi_ps_in_control_0); +CHECK_OFFSET(GX2PixelShader, 0x0C, regs.spi_ps_in_control_1); +CHECK_OFFSET(GX2PixelShader, 0x10, regs.num_spi_ps_input_cntl); +CHECK_OFFSET(GX2PixelShader, 0x14, regs.spi_ps_input_cntls); +CHECK_OFFSET(GX2PixelShader, 0x94, regs.cb_shader_mask); +CHECK_OFFSET(GX2PixelShader, 0x98, regs.cb_shader_control); +CHECK_OFFSET(GX2PixelShader, 0x9C, regs.db_shader_control); +CHECK_OFFSET(GX2PixelShader, 0xA0, regs.spi_input_z); +CHECK_OFFSET(GX2PixelShader, 0xA4, size); +CHECK_OFFSET(GX2PixelShader, 0xA8, program); +CHECK_OFFSET(GX2PixelShader, 0xAC, mode); +CHECK_OFFSET(GX2PixelShader, 0xB0, uniformBlockCount); +CHECK_OFFSET(GX2PixelShader, 0xB4, uniformBlocks); +CHECK_OFFSET(GX2PixelShader, 0xB8, uniformVarCount); +CHECK_OFFSET(GX2PixelShader, 0xBC, uniformVars); +CHECK_OFFSET(GX2PixelShader, 0xC0, initialValueCount); +CHECK_OFFSET(GX2PixelShader, 0xC4, initialValues); +CHECK_OFFSET(GX2PixelShader, 0xC8, loopVarCount); +CHECK_OFFSET(GX2PixelShader, 0xCC, loopVars); +CHECK_OFFSET(GX2PixelShader, 0xD0, samplerVarCount); +CHECK_OFFSET(GX2PixelShader, 0xD4, samplerVars); +CHECK_OFFSET(GX2PixelShader, 0xD8, gx2rBuffer); +CHECK_SIZE(GX2PixelShader, 0xE8); + +struct GX2GeometryShader +{ + struct + { + uint32_t sq_pgm_resources_gs; + uint32_t vgt_gs_out_prim_type; + uint32_t vgt_gs_mode; + uint32_t pa_cl_vs_out_cntl; + uint32_t sq_pgm_resources_vs; + uint32_t sq_gs_vert_itemsize; + uint32_t spi_vs_out_config; + uint32_t num_spi_vs_out_id; + uint32_t spi_vs_out_id[10]; + uint32_t vgt_strmout_buffer_en; + } regs; + + uint32_t size; + uint8_t *program; + uint32_t vertexProgramSize; + uint8_t *vertexProgram; + GX2ShaderMode mode; + + uint32_t uniformBlockCount; + GX2UniformBlock *uniformBlocks; + + uint32_t uniformVarCount; + GX2UniformVar *uniformVars; + + uint32_t initialValueCount; + GX2UniformInitialValue *initialValues; + + uint32_t loopVarCount; + GX2LoopVar *loopVars; + + uint32_t samplerVarCount; + GX2SamplerVar *samplerVars; + + uint32_t ringItemSize; + BOOL hasStreamOut; + uint32_t streamOutStride[4]; + + GX2RBuffer gx2rBuffer; +}; +CHECK_OFFSET(GX2GeometryShader, 0x00, regs.sq_pgm_resources_gs); +CHECK_OFFSET(GX2GeometryShader, 0x04, regs.vgt_gs_out_prim_type); +CHECK_OFFSET(GX2GeometryShader, 0x08, regs.vgt_gs_mode); +CHECK_OFFSET(GX2GeometryShader, 0x0C, regs.pa_cl_vs_out_cntl); +CHECK_OFFSET(GX2GeometryShader, 0x10, regs.sq_pgm_resources_vs); +CHECK_OFFSET(GX2GeometryShader, 0x14, regs.sq_gs_vert_itemsize); +CHECK_OFFSET(GX2GeometryShader, 0x18, regs.spi_vs_out_config); +CHECK_OFFSET(GX2GeometryShader, 0x1C, regs.num_spi_vs_out_id); +CHECK_OFFSET(GX2GeometryShader, 0x20, regs.spi_vs_out_id); +CHECK_OFFSET(GX2GeometryShader, 0x48, regs.vgt_strmout_buffer_en); +CHECK_OFFSET(GX2GeometryShader, 0x4C, size); +CHECK_OFFSET(GX2GeometryShader, 0x50, program); +CHECK_OFFSET(GX2GeometryShader, 0x54, vertexProgramSize); +CHECK_OFFSET(GX2GeometryShader, 0x58, vertexProgram); +CHECK_OFFSET(GX2GeometryShader, 0x5C, mode); +CHECK_OFFSET(GX2GeometryShader, 0x60, uniformBlockCount); +CHECK_OFFSET(GX2GeometryShader, 0x64, uniformBlocks); +CHECK_OFFSET(GX2GeometryShader, 0x68, uniformVarCount); +CHECK_OFFSET(GX2GeometryShader, 0x6C, uniformVars); +CHECK_OFFSET(GX2GeometryShader, 0x70, initialValueCount); +CHECK_OFFSET(GX2GeometryShader, 0x74, initialValues); +CHECK_OFFSET(GX2GeometryShader, 0x78, loopVarCount); +CHECK_OFFSET(GX2GeometryShader, 0x7C, loopVars); +CHECK_OFFSET(GX2GeometryShader, 0x80, samplerVarCount); +CHECK_OFFSET(GX2GeometryShader, 0x84, samplerVars); +CHECK_OFFSET(GX2GeometryShader, 0x88, ringItemSize); +CHECK_OFFSET(GX2GeometryShader, 0x8C, hasStreamOut); +CHECK_OFFSET(GX2GeometryShader, 0x90, streamOutStride); +CHECK_OFFSET(GX2GeometryShader, 0xA0, gx2rBuffer); +CHECK_SIZE(GX2GeometryShader, 0xB0); + +struct GX2AttribStream +{ + uint32_t location; + uint32_t buffer; + uint32_t offset; + GX2AttribFormat format; + GX2AttribIndexType type; + uint32_t aluDivisor; + uint32_t mask; + GX2EndianSwapMode endianSwap; +}; +CHECK_OFFSET(GX2AttribStream, 0x0, location); +CHECK_OFFSET(GX2AttribStream, 0x4, buffer); +CHECK_OFFSET(GX2AttribStream, 0x8, offset); +CHECK_OFFSET(GX2AttribStream, 0xc, format); +CHECK_OFFSET(GX2AttribStream, 0x10, type); +CHECK_OFFSET(GX2AttribStream, 0x14, aluDivisor); +CHECK_OFFSET(GX2AttribStream, 0x18, mask); +CHECK_OFFSET(GX2AttribStream, 0x1c, endianSwap); +CHECK_SIZE(GX2AttribStream, 0x20); + +uint32_t +GX2CalcGeometryShaderInputRingBufferSize(uint32_t ringItemSize); + +uint32_t +GX2CalcGeometryShaderOutputRingBufferSize(uint32_t ringItemSize); + +uint32_t +GX2CalcFetchShaderSizeEx(uint32_t attribs, + GX2FetchShaderType fetchShaderType, + GX2TessellationMode tesellationMode); + +void +GX2InitFetchShaderEx(GX2FetchShader *fetchShader, + uint8_t *buffer, + uint32_t attribCount, + GX2AttribStream *attribs, + GX2FetchShaderType type, + GX2TessellationMode tessMode); + +void +GX2SetFetchShader(GX2FetchShader *shader); + +void +GX2SetVertexShader(GX2VertexShader *shader); + +void +GX2SetPixelShader(GX2PixelShader *shader); + +void +GX2SetGeometryShader(GX2GeometryShader *shader); + +void +GX2SetVertexSampler(GX2Sampler *sampler, + uint32_t id); + +void +GX2SetPixelSampler(GX2Sampler *sampler, + uint32_t id); + +void +GX2SetGeometrySampler(GX2Sampler *sampler, + uint32_t id); + +void +GX2SetVertexUniformReg(uint32_t offset, + uint32_t count, + uint32_t *data); + +void +GX2SetPixelUniformReg(uint32_t offset, + uint32_t count, + uint32_t *data); + +void +GX2SetVertexUniformBlock(uint32_t location, + uint32_t size, + const void *data); + +void +GX2SetPixelUniformBlock(uint32_t location, + uint32_t size, + const void *data); + +void +GX2SetGeometryUniformBlock(uint32_t location, + uint32_t size, + const void *data); + +void +GX2SetShaderModeEx(GX2ShaderMode mode, + uint32_t numVsGpr, uint32_t numVsStackEntries, + uint32_t numGsGpr, uint32_t numGsStackEntries, + uint32_t numPsGpr, uint32_t numPsStackEntries); + +void +GX2SetStreamOutEnable(BOOL enable); + +void +GX2SetGeometryShaderInputRingBuffer(void *buffer, + uint32_t size); + +void +GX2SetGeometryShaderOutputRingBuffer(void *buffer, + uint32_t size); + +uint32_t +GX2GetPixelShaderGPRs(GX2PixelShader *shader); + +uint32_t +GX2GetPixelShaderStackEntries(GX2PixelShader *shader); + +uint32_t +GX2GetVertexShaderGPRs(GX2VertexShader *shader); + +uint32_t +GX2GetVertexShaderStackEntries(GX2VertexShader *shader); + +uint32_t +GX2GetGeometryShaderGPRs(GX2GeometryShader *shader); + +uint32_t +GX2GetGeometryShaderStackEntries(GX2GeometryShader *shader); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/gx2/state.h b/wiiu/wut/include/gx2/state.h new file mode 100644 index 0000000000..9e7d520491 --- /dev/null +++ b/wiiu/wut/include/gx2/state.h @@ -0,0 +1,28 @@ +#pragma once +#include +#include "enum.h" + +/** + * \defgroup gx2_state State + * \ingroup gx2 + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +void +GX2Init(uint32_t *attributes); + +void +GX2Shutdown(); + +void +GX2Flush(); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/gx2/surface.h b/wiiu/wut/include/gx2/surface.h new file mode 100644 index 0000000000..815ea3bb4a --- /dev/null +++ b/wiiu/wut/include/gx2/surface.h @@ -0,0 +1,151 @@ +#pragma once +#include +#include "enum.h" + +/** + * \defgroup gx2_surface Surface + * \ingroup gx2 + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct GX2Surface GX2Surface; +typedef struct GX2DepthBuffer GX2DepthBuffer; +typedef struct GX2ColorBuffer GX2ColorBuffer; + +struct GX2Surface +{ + GX2SurfaceDim dim; + uint32_t width; + uint32_t height; + uint32_t depth; + uint32_t mipLevels; + GX2SurfaceFormat format; + GX2AAMode aa; + GX2SurfaceUse use; + uint32_t imageSize; + void *image; + uint32_t mipmapSize; + void *mipmaps; + GX2TileMode tileMode; + uint32_t swizzle; + uint32_t alignment; + uint32_t pitch; + uint32_t mipLevelOffset[13]; +}; +CHECK_OFFSET(GX2Surface, 0x0, dim); +CHECK_OFFSET(GX2Surface, 0x4, width); +CHECK_OFFSET(GX2Surface, 0x8, height); +CHECK_OFFSET(GX2Surface, 0xc, depth); +CHECK_OFFSET(GX2Surface, 0x10, mipLevels); +CHECK_OFFSET(GX2Surface, 0x14, format); +CHECK_OFFSET(GX2Surface, 0x18, aa); +CHECK_OFFSET(GX2Surface, 0x1c, use); +CHECK_OFFSET(GX2Surface, 0x20, imageSize); +CHECK_OFFSET(GX2Surface, 0x24, image); +CHECK_OFFSET(GX2Surface, 0x28, mipmapSize); +CHECK_OFFSET(GX2Surface, 0x2c, mipmaps); +CHECK_OFFSET(GX2Surface, 0x30, tileMode); +CHECK_OFFSET(GX2Surface, 0x34, swizzle); +CHECK_OFFSET(GX2Surface, 0x38, alignment); +CHECK_OFFSET(GX2Surface, 0x3C, pitch); +CHECK_OFFSET(GX2Surface, 0x40, mipLevelOffset); +CHECK_SIZE(GX2Surface, 0x74); + +struct GX2DepthBuffer +{ + GX2Surface surface; + + uint32_t viewMip; + uint32_t viewFirstSlice; + uint32_t viewNumSlices; + void *hiZPtr; + uint32_t hiZSize; + float depthClear; + uint32_t stencilClear; + + uint32_t regs[7]; +}; +CHECK_OFFSET(GX2DepthBuffer, 0x74, viewMip); +CHECK_OFFSET(GX2DepthBuffer, 0x78, viewFirstSlice); +CHECK_OFFSET(GX2DepthBuffer, 0x7C, viewNumSlices); +CHECK_OFFSET(GX2DepthBuffer, 0x80, hiZPtr); +CHECK_OFFSET(GX2DepthBuffer, 0x84, hiZSize); +CHECK_OFFSET(GX2DepthBuffer, 0x88, depthClear); +CHECK_OFFSET(GX2DepthBuffer, 0x8C, stencilClear); +CHECK_OFFSET(GX2DepthBuffer, 0x90, regs); +CHECK_SIZE(GX2DepthBuffer, 0xAC); + +struct GX2ColorBuffer +{ + GX2Surface surface; + + uint32_t viewMip; + uint32_t viewFirstSlice; + uint32_t viewNumSlices; + void *aaBuffer; + uint32_t aaSize; + + uint32_t regs[5]; +}; +CHECK_OFFSET(GX2ColorBuffer, 0x74, viewMip); +CHECK_OFFSET(GX2ColorBuffer, 0x78, viewFirstSlice); +CHECK_OFFSET(GX2ColorBuffer, 0x7C, viewNumSlices); +CHECK_OFFSET(GX2ColorBuffer, 0x80, aaBuffer); +CHECK_OFFSET(GX2ColorBuffer, 0x84, aaSize); +CHECK_OFFSET(GX2ColorBuffer, 0x88, regs); +CHECK_SIZE(GX2ColorBuffer, 0x9C); + +void +GX2CalcSurfaceSizeAndAlignment(GX2Surface *surface); + +void +GX2CalcDepthBufferHiZInfo(GX2DepthBuffer *depthBuffer, + uint32_t *outSize, + uint32_t *outAlignment); + +void +GX2CalcColorBufferAuxInfo(GX2ColorBuffer *surface, + uint32_t *outSize, + uint32_t *outAlignment); + +void +GX2SetColorBuffer(GX2ColorBuffer *colorBuffer, + GX2RenderTarget target); + +void +GX2SetDepthBuffer(GX2DepthBuffer *depthBuffer); + +void +GX2InitColorBufferRegs(GX2ColorBuffer *colorBuffer); + +void +GX2InitDepthBufferRegs(GX2DepthBuffer *depthBuffer); + +void +GX2InitDepthBufferHiZEnable(GX2DepthBuffer *depthBuffer, + BOOL enable); + +uint32_t +GX2GetSurfaceSwizzle(GX2Surface *surface); + +void +GX2SetSurfaceSwizzle(GX2Surface *surface, + uint32_t swizzle); + +void +GX2CopySurface(GX2Surface *src, + uint32_t srcLevel, + uint32_t srcDepth, + GX2Surface *dst, + uint32_t dstLevel, + uint32_t dstDepth); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/gx2/swap.h b/wiiu/wut/include/gx2/swap.h new file mode 100644 index 0000000000..194ebbf079 --- /dev/null +++ b/wiiu/wut/include/gx2/swap.h @@ -0,0 +1,43 @@ +#pragma once +#include +#include "enum.h" + +/** + * \defgroup gx2_swap Swap + * \ingroup gx2 + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct GX2ColorBuffer GX2ColorBuffer; +typedef struct GX2Texture GX2Texture; + +void +GX2CopyColorBufferToScanBuffer(GX2ColorBuffer *buffer, + GX2ScanTarget scanTarget); + +void +GX2SwapScanBuffers(); + +BOOL +GX2GetLastFrame(GX2ScanTarget scanTarget, + GX2Texture *texture); + +BOOL +GX2GetLastFrameGamma(GX2ScanTarget scanTarget, + float *gammaOut); + +uint32_t +GX2GetSwapInterval(); + +void +GX2SetSwapInterval(uint32_t interval); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/gx2/tessellation.h b/wiiu/wut/include/gx2/tessellation.h new file mode 100644 index 0000000000..458a1e6b77 --- /dev/null +++ b/wiiu/wut/include/gx2/tessellation.h @@ -0,0 +1,31 @@ +#pragma once +#include +#include +#include "enum.h" + +/** + * \defgroup gx2_tessellation Tessellation + * \ingroup gx2 + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +void +GX2SetTessellation(GX2TessellationMode tessellationMode, + GX2PrimitiveMode primitiveMode, + GX2IndexType indexType); + +void +GX2SetMinTessellationLevel(float min); + +void +GX2SetMaxTessellationLevel(float max); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/gx2/texture.h b/wiiu/wut/include/gx2/texture.h new file mode 100644 index 0000000000..3f4d8b9a2b --- /dev/null +++ b/wiiu/wut/include/gx2/texture.h @@ -0,0 +1,56 @@ +#pragma once +#include +#include "surface.h" + +/** + * \defgroup gx2_texture Texture + * \ingroup gx2 + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct GX2Texture GX2Texture; + +struct GX2Texture +{ + GX2Surface surface; + uint32_t viewFirstMip; + uint32_t viewNumMips; + uint32_t viewFirstSlice; + uint32_t viewNumSlices; + uint32_t compMap; + + uint32_t regs[5]; +}; +CHECK_OFFSET(GX2Texture, 0x0, surface); +CHECK_OFFSET(GX2Texture, 0x74, viewFirstMip); +CHECK_OFFSET(GX2Texture, 0x78, viewNumMips); +CHECK_OFFSET(GX2Texture, 0x7c, viewFirstSlice); +CHECK_OFFSET(GX2Texture, 0x80, viewNumSlices); +CHECK_OFFSET(GX2Texture, 0x84, compMap); +CHECK_OFFSET(GX2Texture, 0x88, regs); +CHECK_SIZE(GX2Texture, 0x9c); + +void +GX2InitTextureRegs(GX2Texture *texture); + +void +GX2SetPixelTexture(GX2Texture *texture, + uint32_t unit); + +void +GX2SetVertexTexture(GX2Texture *texture, + uint32_t unit); + +void +GX2SetGeometryTexture(GX2Texture *texture, + uint32_t unit); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/gx2r/buffer.h b/wiiu/wut/include/gx2r/buffer.h new file mode 100644 index 0000000000..6bd8e88c31 --- /dev/null +++ b/wiiu/wut/include/gx2r/buffer.h @@ -0,0 +1,82 @@ +#pragma once +#include +#include "resource.h" + +/** + * \defgroup gx2r_buffer Buffer + * \ingroup gx2r + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct GX2RBuffer GX2RBuffer; + +struct GX2RBuffer +{ + GX2RResourceFlags flags; + uint32_t elemSize; + uint32_t elemCount; + void *buffer; +}; +CHECK_SIZE(GX2RBuffer, 0x10); +CHECK_OFFSET(GX2RBuffer, 0x00, flags); +CHECK_OFFSET(GX2RBuffer, 0x04, elemSize); +CHECK_OFFSET(GX2RBuffer, 0x08, elemCount); +CHECK_OFFSET(GX2RBuffer, 0x0C, buffer); + +BOOL +GX2RBufferExists(GX2RBuffer *buffer); + +BOOL +GX2RCreateBuffer(GX2RBuffer *buffer); + +BOOL +GX2RCreateBufferUserMemory(GX2RBuffer *buffer, + void *memory, + uint32_t size); + +void +GX2RDestroyBufferEx(GX2RBuffer *buffer, + GX2RResourceFlags flags); + +uint32_t +GX2RGetBufferAlignment(GX2RResourceFlags flags); + +uint32_t +GX2RGetBufferAllocationSize(GX2RBuffer *buffer); + +void +GX2RInvalidateBuffer(GX2RBuffer *buffer, + GX2RResourceFlags flags); + +void * +GX2RLockBufferEx(GX2RBuffer *buffer, + GX2RResourceFlags flags); + +void +GX2RUnlockBufferEx(GX2RBuffer *buffer, + GX2RResourceFlags flags); + +void +GX2RSetVertexUniformBlock(GX2RBuffer *buffer, + uint32_t location, + uint32_t offset); + +void +GX2RSetPixelUniformBlock(GX2RBuffer *buffer, + uint32_t location, + uint32_t offset); + +void +GX2RSetGeometryUniformBlock(GX2RBuffer *buffer, + uint32_t location, + uint32_t offset); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/gx2r/displaylist.h b/wiiu/wut/include/gx2r/displaylist.h new file mode 100644 index 0000000000..6dde781b60 --- /dev/null +++ b/wiiu/wut/include/gx2r/displaylist.h @@ -0,0 +1,37 @@ +#pragma once +#include +#include "resource.h" + +/** + * \defgroup gx2r_displaylist Display List + * \ingroup gx2r + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct GX2RBuffer GX2RBuffer; + +void +GX2RBeginDisplayListEx(GX2RBuffer *displayList, + uint32_t unknown, + GX2RResourceFlags flags); + +uint32_t +GX2REndDisplayList(GX2RBuffer *displayList); + +void +GX2RCallDisplayList(GX2RBuffer *displayList, + uint32_t size); + +void +GX2RDirectCallDisplayList(GX2RBuffer *displayList, + uint32_t size); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/gx2r/draw.h b/wiiu/wut/include/gx2r/draw.h new file mode 100644 index 0000000000..60441a2551 --- /dev/null +++ b/wiiu/wut/include/gx2r/draw.h @@ -0,0 +1,37 @@ +#pragma once +#include +#include +#include "resource.h" + +/** + * \defgroup gx2r_draw Draw + * \ingroup gx2r + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct GX2RBuffer GX2RBuffer; + +void +GX2RSetAttributeBuffer(GX2RBuffer *buffer, + uint32_t index, + uint32_t stride, + uint32_t offset); + +void +GX2RDrawIndexed(GX2PrimitiveMode mode, + GX2RBuffer *buffer, + GX2IndexType indexType, + uint32_t count, + uint32_t indexOffset, + uint32_t vertexOffset, + uint32_t numInstances); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/gx2r/mem.h b/wiiu/wut/include/gx2r/mem.h new file mode 100644 index 0000000000..4afc4ef75e --- /dev/null +++ b/wiiu/wut/include/gx2r/mem.h @@ -0,0 +1,34 @@ +#pragma once +#include +#include "resource.h" + +/** + * \defgroup gx2r_mem Memory + * \ingroup gx2r + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void * (*GX2RAllocFunction)(GX2RResourceFlags, uint32_t, uint32_t); +typedef void (*GX2RFreeFunction)(GX2RResourceFlags, void *); + +void +GX2RInvalidateMemory(GX2RResourceFlags flags, + void *buffer, + uint32_t size); + +BOOL +GX2RIsUserMemory(GX2RResourceFlags flags); + +void +GX2RSetAllocator(GX2RAllocFunction allocFn, + GX2RFreeFunction freeFn); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/gx2r/resource.h b/wiiu/wut/include/gx2r/resource.h new file mode 100644 index 0000000000..41229af0c0 --- /dev/null +++ b/wiiu/wut/include/gx2r/resource.h @@ -0,0 +1,94 @@ +#pragma once +#include + +/** + * \defgroup gx2r_resource Resource + * \ingroup gx2r + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum GX2RResourceFlags +{ + //! This resource is to be used as a texture + GX2R_RESOURCE_BIND_TEXTURE = 1 << 0, + + //! This resource is to be used as a colour buffer + GX2R_RESOURCE_BIND_COLOR_BUFFER = 1 << 1, + + //! This resource is to be used as a depth buffer + GX2R_RESOURCE_BIND_DEPTH_BUFFER = 1 << 2, + + //! This resource is to be used as a scan buffer + GX2R_RESOURCE_BIND_SCAN_BUFFER = 1 << 3, + + //! This resource is to be used as a vertex buffer + GX2R_RESOURCE_BIND_VERTEX_BUFFER = 1 << 4, + + //! This resource is to be used as a index buffer + GX2R_RESOURCE_BIND_INDEX_BUFFER = 1 << 5, + + //! This resource is to be used as a uniform block + GX2R_RESOURCE_BIND_UNIFORM_BLOCK = 1 << 6, + + //! This resource is to be used as a shader program + GX2R_RESOURCE_BIND_SHADER_PROGRAM = 1 << 7, + + //! This resource is to be used as a stream output + GX2R_RESOURCE_BIND_STREAM_OUTPUT = 1 << 8, + + //! This resource is to be used as a display list + GX2R_RESOURCE_BIND_DISPLAY_LIST = 1 << 9, + + //! This resource is to be used as a geometry shader ring buffer + GX2R_RESOURCE_BIND_GS_RING_BUFFER = 1 << 10, + + //! Invalidate resource for a CPU read + GX2R_RESOURCE_USAGE_CPU_READ = 1 << 11, + + //! Invalidate resource for a CPU write + GX2R_RESOURCE_USAGE_CPU_WRITE = 1 << 12, + + //! Invalidate resource for a GPU read + GX2R_RESOURCE_USAGE_GPU_READ = 1 << 13, + + //! Invalidate resource for a GPU write + GX2R_RESOURCE_USAGE_GPU_WRITE = 1 << 14, + + //! Invalidate resource for a DMA read + GX2R_RESOURCE_USAGE_DMA_READ = 1 << 15, + + //! Invalidate resource for a DMA write + GX2R_RESOURCE_USAGE_DMA_WRITE = 1 << 16, + + //! Force resource allocation to be in MEM1 + GX2R_RESOURCE_USAGE_FORCE_MEM1 = 1 << 17, + + //! Force resource allocation to be in MEM2 + GX2R_RESOURCE_USAGE_FORCE_MEM2 = 1 << 18, + + //! Disable CPU invalidation + GX2R_RESOURCE_DISABLE_CPU_INVALIDATE = 1 << 20, + + //! Disable GPU invalidation + GX2R_RESOURCE_DISABLE_GPU_INVALIDATE = 1 << 21, + + //! Resource is locked for read-only access + GX2R_RESOURCE_LOCKED_READ_ONLY = 1 << 22, + + //! Resource is to be allocated in user memory + GX2R_RESOURCE_USER_MEMORY = 1 << 29, + + //! Resource is locked for all access + GX2R_RESOURCE_LOCKED = 1 << 30, +} GX2RResourceFlags; + + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/gx2r/surface.h b/wiiu/wut/include/gx2r/surface.h new file mode 100644 index 0000000000..1a435739ff --- /dev/null +++ b/wiiu/wut/include/gx2r/surface.h @@ -0,0 +1,50 @@ +#pragma once +#include +#include "resource.h" + +/** + * \defgroup gx2r_surface Surface + * \ingroup gx2r + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct GX2Surface GX2Surface; + +bool +GX2RCreateSurface(GX2Surface *surface, + GX2RResourceFlags flags); + +bool +GX2RCreateSurfaceUserMemory(GX2Surface *surface, + uint8_t *image, + uint8_t *mipmap, + GX2RResourceFlags flags); + +void +GX2RDestroySurfaceEx(GX2Surface *surface, + GX2RResourceFlags flags); + +void +GX2RInvalidateSurface(GX2Surface *surface, + int32_t level, + GX2RResourceFlags flags); + +void * +GX2RLockSurfaceEx(GX2Surface *surface, + int32_t level, + GX2RResourceFlags flags); + +void +GX2RUnlockSurfaceEx(GX2Surface *surface, + int32_t level, + GX2RResourceFlags flags); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/nsysnet/socket.h b/wiiu/wut/include/nsysnet/socket.h new file mode 100644 index 0000000000..35793b2165 --- /dev/null +++ b/wiiu/wut/include/nsysnet/socket.h @@ -0,0 +1,194 @@ +#pragma once +#include +#include +#include + +/** + * \defgroup nsysnet_socket Socket + * \ingroup nsysnet + * @{ + */ + +#define SOL_SOCKET 0xFFFF + +#define INADDR_ANY 0 + +#define PF_UNSPEC 0 +#define PF_INET 2 +#define PF_INET6 23 + +#define AF_UNSPEC PF_UNSPEC +#define AF_INET PF_INET +#define AF_INET6 PF_INET6 + +#define SOCK_STREAM 1 +#define SOCK_DGRAM 2 + +#define MSG_OOB 0x0001 +#define MSG_PEEK 0x0002 +#define MSG_DONTWAIT 0x0004 +#define MSG_DONTROUTE 0x0000 // ??? +#define MSG_WAITALL 0x0000 // ??? +#define MSG_MORE 0x0000 // ??? +#define MSG_NOSIGNAL 0x0000 // there are no signals + +#define SHUT_RD 0 +#define SHUT_WR 1 +#define SHUT_RDWR 2 + +#define IPPROTO_IP 0 +#define IPPROTO_TCP 6 +#define IPPROTO_UDP 17 + +/* + * SOL_SOCKET options + */ +#define SO_REUSEADDR 0x0004 // reuse address +#define SO_LINGER 0x0080 // linger (no effect?) +#define SO_OOBINLINE 0x0100 // out-of-band data inline (no effect?) +#define SO_SNDBUF 0x1001 // send buffer size +#define SO_RCVBUF 0x1002 // receive buffer size +#define SO_SNDLOWAT 0x1003 // send low-water mark (no effect?) +#define SO_RCVLOWAT 0x1004 // receive low-water mark +#define SO_TYPE 0x1008 // get socket type +#define SO_ERROR 0x1009 // get socket error + +typedef uint32_t socklen_t; +typedef uint16_t sa_family_t; + +struct sockaddr +{ + sa_family_t sa_family; + char sa_data[]; +}; + +struct sockaddr_storage +{ + sa_family_t ss_family; + char __ss_padding[26]; +}; + +struct linger +{ + int l_onoff; + int l_linger; +}; + +struct in_addr { + unsigned int s_addr; +}; +struct sockaddr_in { + short sin_family; + unsigned short sin_port; + struct in_addr sin_addr; + char sin_zero[8]; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +void +socket_lib_init(); + +int +accept(int sockfd, + struct sockaddr *addr, + socklen_t *addrlen); + +int +bind(int sockfd, + const struct sockaddr *addr, + socklen_t addrlen); + +int +socketclose(int sockfd); + +int +connect(int sockfd, + const struct sockaddr *addr, + socklen_t addrlen); + +int +getpeername(int sockfd, + struct sockaddr *addr, + socklen_t *addrlen); + +int +getsockname(int sockfd, + struct sockaddr *addr, + socklen_t *addrlen); + +int +getsockopt(int sockfd, + int level, + int optname, + void *optval, + socklen_t *optlen); + +int +listen(int sockfd, + int backlog); + +ssize_t +recv(int sockfd, + void *buf, + size_t len, + int flags); + +ssize_t +recvfrom(int sockfd, + void *buf, + size_t len, + int flags, + struct sockaddr *src_addr, + socklen_t *addrlen); + +ssize_t +send(int sockfd, + const void *buf, + size_t len, + int flags); + +ssize_t +sendto(int sockfd, + const void *buf, + size_t len, + int flags, + const struct sockaddr *dest_addr, + socklen_t addrlen); + +int +setsockopt(int sockfd, + int level, + int optname, + const void *optval, + socklen_t optlen); + +int +shutdown(int sockfd, + int how); + +int +socket(int domain, + int type, + int protocol); + +int +select(int nfds, + fd_set *readfds, + fd_set *writefds, + fd_set *exceptfds, + struct timeval *timeout); + +char * +inet_ntoa(struct in_addr in); + +int +inet_aton(const char *cp, struct in_addr *inp); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/proc_ui/procui.h b/wiiu/wut/include/proc_ui/procui.h new file mode 100644 index 0000000000..521e7e8784 --- /dev/null +++ b/wiiu/wut/include/proc_ui/procui.h @@ -0,0 +1,68 @@ +#pragma once +#include + +/** + * \defgroup proc_ui_procui ProcUI + * \ingroup proc_ui + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*ProcUISaveCallback)(void); +typedef uint32_t (*ProcUISaveCallbackEx)(void*); +typedef uint32_t (*ProcUICallback)(void*); + +typedef enum ProcUIStatus +{ + PROCUI_STATUS_IN_FOREGROUND, + PROCUI_STATUS_IN_BACKGROUND, + PROCUI_STATUS_RELEASE_FOREGROUND, + PROCUI_STATUS_EXITING, +} ProcUIStatus; + +uint32_t +ProcUICalcMemorySize(uint32_t unk); + +void +ProcUIClearCallbacks(); + +void +ProcUIDrawDoneRelease(); + +BOOL +ProcUIInForeground(); + +BOOL +ProcUIInShutdown(); + +void +ProcUIInit(ProcUISaveCallback saveCallback); + +void +ProcUIInitEx(ProcUISaveCallbackEx saveCallback, + void *arg); + +BOOL +ProcUIIsRunning(); + +ProcUIStatus +ProcUIProcessMessages(BOOL block); + +void +ProcUISetSaveCallback(ProcUISaveCallbackEx saveCallback, + void *arg); + +void +ProcUIShutdown(); + +ProcUIStatus +ProcUISubProcessMessages(BOOL block); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/sndcore2/core.h b/wiiu/wut/include/sndcore2/core.h new file mode 100644 index 0000000000..1cfd1bd40d --- /dev/null +++ b/wiiu/wut/include/sndcore2/core.h @@ -0,0 +1,90 @@ +#pragma once +#include +#include "result.h" + +/** + * \defgroup sndcore2_core Core + * \ingroup sndcore2 + * + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct AXProfile AXProfile; +typedef struct AXInitParams AXInitParams; + +typedef void(*AXFrameCallback)(void); + +//! A value from enum AX_INIT_RENDERER. +typedef uint32_t AXInitRenderer; + +//! A value from enum AX_INIT_PIPELINE. +typedef uint32_t AXInitPipeline; + +enum AX_INIT_RENDERER +{ + AX_INIT_RENDERER_32KHZ = 0, + AX_INIT_RENDERER_48KHZ = 1, +}; + +enum AX_INIT_PIPELINE +{ + AX_INIT_PIPELINE_SINGLE = 0, + AX_INIT_PIPELINE_FOUR_STAGE = 1, +}; + +struct AXProfile +{ + // Unknown +}; + +struct AXInitParams +{ + AXInitRenderer renderer; + UNKNOWN(4); + AXInitPipeline pipeline; +}; +CHECK_OFFSET(AXInitParams, 0x00, renderer); +CHECK_OFFSET(AXInitParams, 0x08, pipeline); +CHECK_SIZE(AXInitParams, 0x0C); + +void +AXInit(); + +void +AXQuit(); + +void +AXInitWithParams(AXInitParams *params); + +BOOL +AXIsInit(); + +void +AXInitProfile(AXProfile *profile, + uint32_t count); + +uint32_t +AXGetSwapProfile(AXProfile *profile, + uint32_t count); + +AXResult +AXSetDefaultMixerSelect(uint32_t unk0); + +AXResult +AXRegisterAppFrameCallback(AXFrameCallback callback); + +uint32_t +AXGetInputSamplesPerFrame(); + +uint32_t +AXGetInputSamplesPerSec(); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/sndcore2/device.h b/wiiu/wut/include/sndcore2/device.h new file mode 100644 index 0000000000..14817d98b0 --- /dev/null +++ b/wiiu/wut/include/sndcore2/device.h @@ -0,0 +1,86 @@ +#pragma once +#include +#include "result.h" + +/** + * \defgroup sndcore2_device Device + * \ingroup sndcore2 + * + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void(*AXDeviceFinalMixCallback)(void*); +typedef void(*AXAuxCallback)(void*, void*); + +//! A value from enum AX_DEVICE_MODE. +typedef uint32_t AXDeviceMode; + +//! A value from enum AX_DEVICE_TYPE. +typedef uint32_t AXDeviceType; + +enum AX_DEVICE_MODE +{ + // Unknown + AX_DEVICE_MODE_UNKNOWN +}; + +enum AX_DEVICE_TYPE +{ + AX_DEVICE_TYPE_TV = 0, + AX_DEVICE_TYPE_DRC = 1, + AX_DEVICE_TYPE_CONTROLLER = 2, +}; + +AXResult +AXGetDeviceMode(AXDeviceType type, + AXDeviceMode *mode); + +AXResult +AXGetDeviceFinalMixCallback(AXDeviceType type, + AXDeviceFinalMixCallback *func); + +AXResult +AXRegisterDeviceFinalMixCallback(AXDeviceType type, + AXDeviceFinalMixCallback func); + +AXResult +AXGetAuxCallback(AXDeviceType type, + uint32_t unk0, + uint32_t unk1, + AXAuxCallback *callback, + void **userData); + +AXResult +AXRegisterAuxCallback(AXDeviceType type, + uint32_t unk0, + uint32_t unk1, + AXAuxCallback callback, + void *userData); + +AXResult +AXSetDeviceLinearUpsampler(AXDeviceType type, + uint32_t unk0, + uint32_t unk1); + +AXResult +AXSetDeviceCompressor(AXDeviceType type, + uint32_t unk0); + +AXResult +AXSetDeviceUpsampleStage(AXDeviceType type, + BOOL postFinalMix); + +AXResult +AXSetDeviceVolume(AXDeviceType type, + uint32_t id, + uint16_t volume); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/sndcore2/drcvs.h b/wiiu/wut/include/sndcore2/drcvs.h new file mode 100644 index 0000000000..8577e542f1 --- /dev/null +++ b/wiiu/wut/include/sndcore2/drcvs.h @@ -0,0 +1,99 @@ +#pragma once +#include +#include "result.h" + +/** + * \defgroup sndcore2_drcvs DRC VS + * \ingroup sndcore2 + * + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +//! A value from enum AX_DRC_VS_MODE. +typedef uint32_t AXDRCVSMode; + +//! A value from enum AX_DRC_VS_OUTPUT. +typedef uint32_t AXDRCVSOutput; + +//! A value from enum AX_DRC_VS_LC. +typedef uint32_t AXDRCVSLC; + +//! A value from enum AX_DRC_VS_SPEAKER_POS. +typedef uint32_t AXDRCVSSpeakerPosition; + +//! A value from enum AX_DRC_VS_SURROUND_GAIN. +typedef uint32_t AXDRCVSSurroundLevelGain; + +enum AX_DRC_VS_MODE +{ + // Unknown + AX_DRC_VS_MODE_UNKNOWN +}; + +enum AX_DRC_VS_OUTPUT +{ + // Unknown + AX_DRC_VS_OUTPUT_UNKNOWN +}; + +enum AX_DRC_VS_LC +{ + // Unknown + AX_DRC_VS_LC_UNKNOWN +}; + +enum AX_DRC_VS_SPEAKER_POS +{ + // Unknown + AX_DRC_VS_SPEAKER_POS_UNKNOWN +}; + +enum AX_DRC_VS_SURROUND_GAIN +{ + // Unknown + AX_DRC_VS_SURROUND_GAIN_UNKNOWN +}; + +AXResult +AXGetDRCVSMode(AXDRCVSMode *mode); + +AXResult +AXSetDRCVSMode(AXDRCVSMode mode); + +AXResult +AXSetDRCVSDownmixBalance(AXDRCVSOutput output, + float balance); + +AXResult +AXSetDRCVSLC(AXDRCVSLC lc); + +AXResult +AXSetDRCVSLimiter(BOOL limit); + +AXResult +AXSetDRCVSLimiterThreshold(float threshold); + +AXResult +AXSetDRCVSOutputGain(AXDRCVSOutput output, + float gain); + +AXResult +AXSetDRCVSSpeakerPosition(AXDRCVSOutput output, + AXDRCVSSpeakerPosition pos); + +AXResult +AXSetDRCVSSurroundDepth(AXDRCVSOutput output, + float depth); + +AXResult +AXSetDRCVSSurroundLevelGain(AXDRCVSSurroundLevelGain gain); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/sndcore2/result.h b/wiiu/wut/include/sndcore2/result.h new file mode 100644 index 0000000000..ea9873fcc3 --- /dev/null +++ b/wiiu/wut/include/sndcore2/result.h @@ -0,0 +1,31 @@ +#pragma once +#include + +/** + * \defgroup sndcore2_result Result + * \ingroup sndcore2 + * + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +//! A value from enum AX_RESULT. +typedef int32_t AXResult; + +enum AX_RESULT +{ + AX_RESULT_SUCCESS = 0, + AX_RESULT_INVALID_DEVICE_TYPE = -1, + AX_RESULT_INVALID_DRC_VS_MODE = -13, + AX_RESULT_VOICE_IS_RUNNING = -18, + AX_RESULT_DELAY_TOO_BIG = -19, +}; + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/sndcore2/voice.h b/wiiu/wut/include/sndcore2/voice.h new file mode 100644 index 0000000000..4eb0defc21 --- /dev/null +++ b/wiiu/wut/include/sndcore2/voice.h @@ -0,0 +1,378 @@ +#pragma once +#include +#include "device.h" +#include "result.h" + +/** + * \defgroup sndcore2_voice Voice + * \ingroup sndcore2 + * + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct AXVoice AXVoice; +typedef struct AXVoiceAdpcmLoopData AXVoiceAdpcmLoopData; +typedef struct AXVoiceAdpcm AXVoiceAdpcm; +typedef struct AXVoiceDeviceBusMixData AXVoiceDeviceBusMixData; +typedef struct AXVoiceDeviceMixData AXVoiceDeviceMixData; +typedef struct AXVoiceLink AXVoiceLink; +typedef struct AXVoiceOffsets AXVoiceOffsets; +typedef struct AXVoiceSrc AXVoiceSrc; +typedef struct AXVoiceVeData AXVoiceVeData; + +//! A value from enum AX_VOICE_FORMAT. +typedef uint16_t AXVoiceFormat; + +//! A value from enum AX_VOICE_LOOP. +typedef uint16_t AXVoiceLoop; + +//! A value from enum AX_VOICE_SRC_TYPE. +typedef uint32_t AXVoiceSrcType; + +//! A value from enum AX_VOICE_STATE. +typedef uint32_t AXVoiceState; + +//! A value from enum AX_VOICE_RENDERER. +typedef uint32_t AXVoiceRenderer; + +//! A value from enum AX_VOICE_RATIO_RESULT. +typedef int32_t AXVoiceSrcRatioResult; + +//! A value from enum AX_VOICE_TYPE. +typedef uint32_t AXVoiceType; + +typedef void(*AXVoiceCallbackFn)(void *); +typedef void(*AXVoiceCallbackExFn)(void *, uint32_t, uint32_t); + +enum AX_VOICE_FORMAT +{ + AX_VOICE_FORMAT_ADPCM = 0, + AX_VOICE_FORMAT_LPCM16 = 10, + AX_VOICE_FORMAT_LPCM8 = 25, +}; + +enum AX_VOICE_LOOP +{ + AX_VOICE_LOOP_DISABLED = 0, + AX_VOICE_LOOP_ENABLED = 1, +}; + +enum AX_VOICE_RENDERER +{ + AX_VOICE_RENDERER_DSP = 0, + AX_VOICE_RENDERER_CPU = 1, + AX_VOICE_RENDERER_AUTO = 2, +}; + +enum AX_VOICE_RATIO_RESULT +{ + AX_VOICE_RATIO_RESULT_SUCCESS = 0, + AX_VOICE_RATIO_RESULT_LESS_THAN_ZERO = -1, + AX_VOICE_RATIO_RESULT_GREATER_THAN_SOMETHING = -2, +}; + +enum AX_VOICE_SRC_TYPE +{ + AX_VOICE_SRC_TYPE_NONE = 0, + AX_VOICE_SRC_TYPE_LINEAR = 1, + AX_VOICE_SRC_TYPE_UNK0 = 2, + AX_VOICE_SRC_TYPE_UNK1 = 3, + AX_VOICE_SRC_TYPE_UNK2 = 4, +}; + +enum AX_VOICE_STATE +{ + AX_VOICE_STATE_STOPPED = 0, + AX_VOICE_STATE_PLAYING = 1, +}; + +enum AX_VOICE_TYPE +{ + // Unknown + AX_VOICE_TYPE_UNKNOWN +}; + +struct AXVoiceLink +{ + AXVoice *next; + AXVoice *prev; +}; +CHECK_OFFSET(AXVoiceLink, 0x0, next); +CHECK_OFFSET(AXVoiceLink, 0x4, prev); +CHECK_SIZE(AXVoiceLink, 0x8); + +struct AXVoiceOffsets +{ + AXVoiceFormat dataType; + AXVoiceLoop loopingEnabled; + uint32_t loopOffset; + uint32_t endOffset; + uint32_t currentOffset; + const void *data; +}; +CHECK_OFFSET(AXVoiceOffsets, 0x0, dataType); +CHECK_OFFSET(AXVoiceOffsets, 0x2, loopingEnabled); +CHECK_OFFSET(AXVoiceOffsets, 0x4, loopOffset); +CHECK_OFFSET(AXVoiceOffsets, 0x8, endOffset); +CHECK_OFFSET(AXVoiceOffsets, 0xc, currentOffset); +CHECK_OFFSET(AXVoiceOffsets, 0x10, data); +CHECK_SIZE(AXVoiceOffsets, 0x14); + +struct AXVoice +{ + //! The index of this voice out of the total voices + uint32_t index; + + //! Current play state of this voice + AXVoiceState state; + + //! Current volume of this voice + uint32_t volume; + + //! The renderer to use for this voice + AXVoiceRenderer renderer; + + //! this is a link used in the stack, we do this in host-memory currently + AXVoiceLink link; + + //! A link to the next callback to invoke + AXVoice *cbNext; + + //! The priority of this voice used for force-acquiring a voice + uint32_t priority; + + //! The callback to call if this is force-free'd by another acquire + AXVoiceCallbackFn callback; + + //! The user context to send to the callbacks + void *userContext; + + //! A bitfield representing different things needing to be synced. + uint32_t syncBits; + + UNKNOWN(0x8); + + //! The current offset data! + AXVoiceOffsets offsets; + + //! An extended version of the callback above + AXVoiceCallbackExFn callbackEx; + + //! The reason for the callback being invoked + uint32_t callbackReason; + + float unk0; + float unk1; +}; +CHECK_OFFSET(AXVoice, 0x0, index); +CHECK_OFFSET(AXVoice, 0x4, state); +CHECK_OFFSET(AXVoice, 0x8, volume); +CHECK_OFFSET(AXVoice, 0xc, renderer); +CHECK_OFFSET(AXVoice, 0x10, link); +CHECK_OFFSET(AXVoice, 0x18, cbNext); +CHECK_OFFSET(AXVoice, 0x1c, priority); +CHECK_OFFSET(AXVoice, 0x20, callback); +CHECK_OFFSET(AXVoice, 0x24, userContext); +CHECK_OFFSET(AXVoice, 0x28, syncBits); +CHECK_OFFSET(AXVoice, 0x34, offsets); +CHECK_OFFSET(AXVoice, 0x48, callbackEx); +CHECK_OFFSET(AXVoice, 0x4c, callbackReason); +CHECK_OFFSET(AXVoice, 0x50, unk0); +CHECK_OFFSET(AXVoice, 0x54, unk1); +CHECK_SIZE(AXVoice, 0x58); + +struct AXVoiceDeviceBusMixData +{ + uint16_t volume; + int16_t delta; +}; +CHECK_OFFSET(AXVoiceDeviceBusMixData, 0x0, volume); +CHECK_OFFSET(AXVoiceDeviceBusMixData, 0x2, delta); +CHECK_SIZE(AXVoiceDeviceBusMixData, 0x4); + +struct AXVoiceDeviceMixData +{ + AXVoiceDeviceBusMixData bus[4]; +}; +CHECK_OFFSET(AXVoiceDeviceMixData, 0x0, bus); +CHECK_SIZE(AXVoiceDeviceMixData, 0x10); + +struct AXVoiceVeData +{ + uint16_t volume; + int16_t delta; +}; +CHECK_OFFSET(AXVoiceVeData, 0x0, volume); +CHECK_OFFSET(AXVoiceVeData, 0x2, delta); +CHECK_SIZE(AXVoiceVeData, 0x4); + +struct AXVoiceAdpcmLoopData +{ + uint16_t predScale; + int16_t prevSample[2]; +}; +CHECK_OFFSET(AXVoiceAdpcmLoopData, 0x0, predScale); +CHECK_OFFSET(AXVoiceAdpcmLoopData, 0x2, prevSample); +CHECK_SIZE(AXVoiceAdpcmLoopData, 0x6); + +struct AXVoiceAdpcm +{ + int16_t coefficients[16]; + uint16_t gain; + uint16_t predScale; + int16_t prevSample[2]; +}; +CHECK_OFFSET(AXVoiceAdpcm, 0x0, coefficients); +CHECK_OFFSET(AXVoiceAdpcm, 0x20, gain); +CHECK_OFFSET(AXVoiceAdpcm, 0x22, predScale); +CHECK_OFFSET(AXVoiceAdpcm, 0x24, prevSample); +CHECK_SIZE(AXVoiceAdpcm, 0x28); + +#pragma pack(push, 1) + +/** + * AXVoice Sample Rate Converter + */ +struct AXVoiceSrc +{ + //! Playback rate, fixed 16.16 + uint32_t ratio; + + //! Used by the resampler, fixed 0.16 + uint16_t currentOffsetFrac; + int16_t lastSample[4]; +}; +CHECK_OFFSET(AXVoiceSrc, 0x0, ratio); +CHECK_OFFSET(AXVoiceSrc, 0x4, currentOffsetFrac); +CHECK_OFFSET(AXVoiceSrc, 0x6, lastSample); +CHECK_SIZE(AXVoiceSrc, 0xe); + +#pragma pack(pop) + +AXVoice * +AXAcquireVoice(uint32_t priority, + AXVoiceCallbackFn callback, + void *userContext); + +AXVoice * +AXAcquireVoiceEx(uint32_t priority, + AXVoiceCallbackExFn callback, + void *userContext); + +BOOL +AXCheckVoiceOffsets(AXVoiceOffsets *offsets); + +void +AXFreeVoice(AXVoice *voice); + +uint32_t +AXGetMaxVoices(); + +uint32_t +AXGetVoiceCurrentOffsetEx(AXVoice *voice, + const void *samples); + +uint32_t +AXGetVoiceLoopCount(AXVoice *voice); + +void +AXGetVoiceOffsets(AXVoice *voice, + AXVoiceOffsets *offsets); + +BOOL +AXIsVoiceRunning(AXVoice *voice); + +void +AXSetVoiceAdpcm(AXVoice *voice, + AXVoiceAdpcm *adpcm); + +void +AXSetVoiceAdpcmLoop(AXVoice *voice, + AXVoiceAdpcmLoopData *loopData); + +void +AXSetVoiceCurrentOffset(AXVoice *voice, + uint32_t offset); + +AXResult +AXSetVoiceDeviceMix(AXVoice *voice, + AXDeviceType type, + uint32_t id, + AXVoiceDeviceMixData *mixData); + +void +AXSetVoiceEndOffset(AXVoice *voice, + uint32_t offset); + +void +AXSetVoiceEndOffsetEx(AXVoice *voice, + uint32_t offset, + const void *samples); + +AXResult +AXSetVoiceInitialTimeDelay(AXVoice *voice, + uint16_t delay); + +void +AXSetVoiceLoopOffset(AXVoice *voice, + uint32_t offset); + +void +AXSetVoiceLoopOffsetEx(AXVoice *voice, + uint32_t offset, + const void *samples); + +void +AXSetVoiceLoop(AXVoice *voice, + AXVoiceLoop loop); + +void +AXSetVoiceOffsets(AXVoice *voice, + AXVoiceOffsets *offsets); + +void +AXSetVoicePriority(AXVoice *voice, + uint32_t priority); + +void +AXSetVoiceRmtIIRCoefs(AXVoice *voice, + uint16_t filter, + ...); + +void +AXSetVoiceSrc(AXVoice *voice, + AXVoiceSrc *src); + +AXVoiceSrcRatioResult +AXSetVoiceSrcRatio(AXVoice *voice, + float ratio); + +void +AXSetVoiceSrcType(AXVoice *voice, + AXVoiceSrcType type); + +void +AXSetVoiceState(AXVoice *voice, + AXVoiceState state); + +void +AXSetVoiceType(AXVoice *voice, + AXVoiceType type); + +void +AXSetVoiceVe(AXVoice *voice, + AXVoiceVeData *veData); + +void +AXSetVoiceVeDelta(AXVoice *voice, + int16_t delta); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/sysapp/launch.h b/wiiu/wut/include/sysapp/launch.h new file mode 100644 index 0000000000..f2817718f5 --- /dev/null +++ b/wiiu/wut/include/sysapp/launch.h @@ -0,0 +1,40 @@ +#pragma once +#include + +/** + * \defgroup sysapp_launch SYSAPP Launch + * \ingroup sysapp + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +void +SYSRelaunchTitle(uint32_t argc, + char *pa_Argv[]); + +void +SYSLaunchMenu(); + +void +SYSLaunchTitle(uint64_t TitleId); + +void +_SYSLaunchMiiStudio(); + +void +_SYSLaunchSettings(); + +void +_SYSLaunchParental(); + +void +_SYSLaunchNotifications(); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/sysapp/switch.h b/wiiu/wut/include/sysapp/switch.h new file mode 100644 index 0000000000..ad4f854486 --- /dev/null +++ b/wiiu/wut/include/sysapp/switch.h @@ -0,0 +1,36 @@ +#pragma once +#include + +/** + * \defgroup sysapp_switch SYSAPP Switch + * \ingroup sysapp + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +//TODO +typedef void sysapp_input_struct; + +void +SYSSwitchToSyncControllerOnHBM(); + +void +SYSSwitchToEManual(); + +void +SYSSwitchToEShop(); + +void +_SYSSwitchToMainApp(); + +void +SYSSwitchToBrowserForViewer(sysapp_input_struct*); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/vpad/input.h b/wiiu/wut/include/vpad/input.h new file mode 100644 index 0000000000..b476a665a7 --- /dev/null +++ b/wiiu/wut/include/vpad/input.h @@ -0,0 +1,213 @@ +#pragma once +#include + +/** + * \defgroup vpad_input VPAD Input + * \ingroup vpad + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct VPADVec2D VPADVec2D; +typedef struct VPADVec3D VPADVec3D; +typedef struct VPADTouchData VPADTouchData; +typedef struct VPADAccStatus VPADAccStatus; +typedef struct VPADGyroStatus VPADGyroStatus; +typedef struct VPADStatus VPADStatus; + +typedef enum VPADButtons +{ + VPAD_BUTTON_A = 0x8000, + VPAD_BUTTON_B = 0x4000, + VPAD_BUTTON_X = 0x2000, + VPAD_BUTTON_Y = 0x1000, + VPAD_BUTTON_LEFT = 0x0800, + VPAD_BUTTON_RIGHT = 0x0400, + VPAD_BUTTON_UP = 0x0200, + VPAD_BUTTON_DOWN = 0x0100, + VPAD_BUTTON_ZL = 0x0080, + VPAD_BUTTON_ZR = 0x0040, + VPAD_BUTTON_L = 0x0020, + VPAD_BUTTON_R = 0x0010, + VPAD_BUTTON_PLUS = 0x0008, + VPAD_BUTTON_MINUS = 0x0004, + VPAD_BUTTON_HOME = 0x0002, + VPAD_BUTTON_SYNC = 0x0001, + VPAD_BUTTON_STICK_R = 0x00020000, + VPAD_BUTTON_STICK_L = 0x00040000, + VPAD_BUTTON_TV = 0x00010000, +} VPADButtons; + +typedef enum VPADTouchPadValidity +{ + //! Both X and Y touchpad positions are accurate + VPAD_VALID = 0x0, + + //! X position is inaccurate + VPAD_INVALID_X = 0x1, + + //! Y position is inaccurate + VPAD_INVALID_Y = 0x2, +} VPADTouchPadValidity; + + +typedef enum VPADReadError +{ + VPAD_READ_SUCCESS = 0, + VPAD_READ_NO_SAMPLES = -1, + VPAD_READ_INVALID_CONTROLLER = -2, +} VPADReadError; + +struct VPADVec2D +{ + float x; + float y; +}; +CHECK_OFFSET(VPADVec2D, 0x00, x); +CHECK_OFFSET(VPADVec2D, 0x04, y); +CHECK_SIZE(VPADVec2D, 0x08); + +struct VPADVec3D +{ + float x; + float y; + float z; +}; +CHECK_OFFSET(VPADVec3D, 0x00, x); +CHECK_OFFSET(VPADVec3D, 0x04, y); +CHECK_OFFSET(VPADVec3D, 0x08, z); +CHECK_SIZE(VPADVec3D, 0x0C); + +struct VPADTouchData +{ + uint16_t x; + uint16_t y; + + //! 0 if screen is not currently being touched + uint16_t touched; + + //! Bitfield of VPADTouchPadValidity to indicate how touch sample accuracy + uint16_t validity; +}; +CHECK_OFFSET(VPADTouchData, 0x00, x); +CHECK_OFFSET(VPADTouchData, 0x02, y); +CHECK_OFFSET(VPADTouchData, 0x04, touched); +CHECK_OFFSET(VPADTouchData, 0x06, validity); +CHECK_SIZE(VPADTouchData, 0x08); + +struct VPADAccStatus +{ + float unk1; + float unk2; + float unk3; + float unk4; + float unk5; + VPADVec2D vertical; +}; +CHECK_OFFSET(VPADAccStatus, 0x14, vertical); +CHECK_SIZE(VPADAccStatus, 0x1c); + +struct VPADGyroStatus +{ + float unk1; + float unk2; + float unk3; + float unk4; + float unk5; + float unk6; +}; +CHECK_SIZE(VPADGyroStatus, 0x18); + +struct VPADStatus +{ + //! Indicates what VPADButtons are held down + uint32_t hold; + + //! Indicates what VPADButtons have been pressed since last sample + uint32_t trigger; + + //! Indicates what VPADButtons have been released since last sample + uint32_t release; + + //! Position of left analog stick + VPADVec2D leftStick; + + //! Position of right analog stick + VPADVec2D rightStick; + + //! Status of DRC accelorometer + VPADAccStatus accelorometer; + + //! Status of DRC gyro + VPADGyroStatus gyro; + + UNKNOWN(2); + + //! Current touch position on DRC + VPADTouchData tpNormal; + + //! Filtered touch position, first level of smoothing + VPADTouchData tpFiltered1; + + //! Filtered touch position, second level of smoothing + VPADTouchData tpFiltered2; + + UNKNOWN(0x28); + + //! Status of DRC magnetometer + VPADVec3D mag; + + //! Current volume set by the slide control + uint8_t slideVolume; + + //! Battery level of controller + uint8_t battery; + + //! Status of DRC microphone + uint8_t micStatus; + + //! Unknown volume related value + uint8_t slideVolumeEx; + + UNKNOWN(0x7); +}; +CHECK_OFFSET(VPADStatus, 0x00, hold); +CHECK_OFFSET(VPADStatus, 0x04, trigger); +CHECK_OFFSET(VPADStatus, 0x08, release); +CHECK_OFFSET(VPADStatus, 0x0C, leftStick); +CHECK_OFFSET(VPADStatus, 0x14, rightStick); +CHECK_OFFSET(VPADStatus, 0x1C, accelorometer); +CHECK_OFFSET(VPADStatus, 0x38, gyro); +CHECK_OFFSET(VPADStatus, 0x52, tpNormal); +CHECK_OFFSET(VPADStatus, 0x5A, tpFiltered1); +CHECK_OFFSET(VPADStatus, 0x62, tpFiltered2); +CHECK_OFFSET(VPADStatus, 0x94, mag); +CHECK_OFFSET(VPADStatus, 0xA0, slideVolume); +CHECK_OFFSET(VPADStatus, 0xA1, battery); +CHECK_OFFSET(VPADStatus, 0xA2, micStatus); +CHECK_OFFSET(VPADStatus, 0xA3, slideVolumeEx); +CHECK_SIZE(VPADStatus, 0xAC); + +//! Deprecated +void +VPADInit(); + +int32_t +VPADRead(uint32_t chan, + VPADStatus *buffers, + uint32_t count, + VPADReadError *error); + +void +VPADGetTPCalibratedPoint(uint32_t chan, + VPADTouchData *calibratedData, + VPADTouchData *uncalibratedData); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/wiiu/wut/include/wut.h b/wiiu/wut/include/wut.h new file mode 100644 index 0000000000..7414e25fed --- /dev/null +++ b/wiiu/wut/include/wut.h @@ -0,0 +1,3 @@ +#pragma once +#include "wut_structsize.h" +#include "wut_types.h" diff --git a/wiiu/wut/include/wut_structsize.h b/wiiu/wut/include/wut_structsize.h new file mode 100644 index 0000000000..b711de6934 --- /dev/null +++ b/wiiu/wut/include/wut_structsize.h @@ -0,0 +1,27 @@ +#pragma once +#include +#include + +// Ensure structs are correct size & offsets +#define CHECK_SIZE(Type, Size) \ + static_assert(sizeof(Type) == Size, \ + #Type " must be " #Size " bytes") + +#define CHECK_OFFSET(Type, Offset, Field) \ + static_assert(offsetof(Type, Field) == Offset, \ + #Type "::" #Field " must be at offset " #Offset) + +// Workaround weird macro concat ## behaviour +#define PP_CAT(a, b) PP_CAT_I(a, b) +#define PP_CAT_I(a, b) PP_CAT_II(~, a ## b) +#define PP_CAT_II(p, res) res + +// Allow us to easily add UNKNOWN / PADDING bytes into our structs, +// generates unique variable names using __COUNTER__ +#define UNKNOWN(Size) char PP_CAT(__unk, __COUNTER__) [Size] +#define PADDING(Size) UNKNOWN(Size) + +// Just some placeholder defines +#define UNKNOWN_ARG uint32_t +#define UNKNOWN_ARGS void +#define UNKNOWN_SIZE(x) diff --git a/wiiu/wut/include/wut_types.h b/wiiu/wut/include/wut_types.h new file mode 100644 index 0000000000..8d25225eba --- /dev/null +++ b/wiiu/wut/include/wut_types.h @@ -0,0 +1,44 @@ +#pragma once +#include +#include + +typedef int BOOL; + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +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 s16 sfp16; +typedef s32 sfp32; +typedef u16 ufp16; +typedef u32 ufp32; + +typedef float f32; +typedef double f64; + +typedef volatile float vf32; +typedef volatile double vf64;