From a616e3cdca5d0aaae29bb6f70e923a1393c4fb59 Mon Sep 17 00:00:00 2001 From: Logan McNaughton <848146+loganmc10@users.noreply.github.com> Date: Sun, 29 May 2022 18:33:25 -0600 Subject: [PATCH] update core --- mupen64plus-core/.github/workflows/build.yml | 288 ++++++++++++++++++ mupen64plus-core/projects/unix/Makefile | 58 ++-- .../src/device/controllers/paks/mempak.c | 150 ++++++--- .../src/device/controllers/paks/mempak.h | 10 +- mupen64plus-core/src/main/main.c | 21 +- mupen64plus-core/src/main/util.c | 176 +++++++++++ mupen64plus-core/src/main/util.h | 35 +++ 7 files changed, 678 insertions(+), 60 deletions(-) create mode 100644 mupen64plus-core/.github/workflows/build.yml diff --git a/mupen64plus-core/.github/workflows/build.yml b/mupen64plus-core/.github/workflows/build.yml new file mode 100644 index 0000000..6cddb8f --- /dev/null +++ b/mupen64plus-core/.github/workflows/build.yml @@ -0,0 +1,288 @@ +name: Core + +on: + push: + paths-ignore: + - '**/*.md' + - '.{gitattributes,gitignore,travis.yml}' + - 'appveyor.yml,README' + pull_request: + paths-ignore: + - '**/*.md' + - '.{gitattributes,gitignore,travis.yml}' + - 'appveyor.yml,README' + workflow_dispatch: +jobs: + + Linux: + strategy: + fail-fast: false + matrix: + include: + - cc: GCC + - cc: Clang + name: Linux / ${{ matrix.cc }} / x64 | x86 + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + - name: Get build dependencies and arrange the environment + run: | + sudo dpkg --add-architecture i386 + sudo apt-get update + sudo apt-get -y install libfreetype6-dev libgl1-mesa-dev libglu1-mesa-dev libpng-dev libsdl1.2-dev libsdl2-dev nasm zlib1g-dev + sudo apt-get --reinstall -y install gcc-multilib g++-multilib libc6 libc6-dev-i386 libfreetype6:i386 libgl1-mesa-glx:i386 libglu1-mesa:i386 libpng16-16:i386 libsdl1.2debian:i386 libsdl2-2.0-0:i386 zlib1g:i386 + LINK="sudo ln -s -T" + cd /usr/lib/i386-linux-gnu + if ! [[ -f libfreetype.so ]]; then ${LINK} libfreetype.so.6.17.1 libfreetype.so; fi + if ! [[ -f libGL.so ]]; then ${LINK} libGL.so.1.7.0 libGL.so; fi + if ! [[ -f libGLU.so ]]; then ${LINK} libGLU.so.1.3.1 libGLU.so; fi + if ! [[ -f libpng16.so ]]; then ${LINK} libpng16.so.16.37.0 libpng16.so; fi + if ! [[ -f libSDL.so ]]; then ${LINK} libSDL-1.2.so.0.11.4 libSDL.so; fi + if ! [[ -f libSDL2.so ]]; then ${LINK} libSDL2-2.0.so.0.10.0 libSDL2.so; fi + if ! [[ -f libz.so ]]; then ${LINK} libz.so.1.2.11 libz.so; fi + cd /usr/include/SDL2 + if ! [[ -f _real_SDL_config.h ]]; then ${LINK} ../x86_64-linux-gnu/SDL2/_real_SDL_config.h _real_SDL_config.h; fi + sudo ldconfig + - name: Build and related stuff + run: | + if [[ "${{ matrix.cc }}" == "GCC" ]]; then + CC="gcc" + CXX="g++" + else + CC="clang" + CXX="clang++" + fi + ${CC} --version + for TSK in 1 2 3 4 5 6 7 8 + do + unset PIC + if [[ ${TSK} -le 4 ]]; then + SDL="sdl" + MSG="SDL1.2" + else + SDL="sdl2" + MSG="SDL2" + fi + if [[ "${DYN}" == "0" ]]; then + DYN="1" + MSG="${MSG} / NEW_DYNAREC" + else + DYN="0" + if [[ "${BITS}" == "64" ]]; then BITS="32"; else BITS="64"; fi + fi + if [[ ${BITS} -eq 32 ]]; then + if [[ "${CC}" == "clang" ]]; then export PIC="1"; fi + MSG="x86 / ${MSG}" + else + MSG="x64 / ${MSG}" + fi + echo "" + echo ":: ${{ matrix.cc }} ${MSG} ::" + echo "" + make -C projects/unix clean + echo "" + make CC="${CC}" CXX="${CXX}" BITS="${BITS}" SDL_CONFIG="${SDL}-config" NEW_DYNAREC="${DYN}" -C projects/unix all + echo "" + ls -gG projects/unix/*.so* + ldd projects/unix/libmupen64plus.so.2.0.0 + done + + MSYS2: + strategy: + fail-fast: false + matrix: + include: + - cc: GCC + platform: x64 + cross: x86_64 + bits: 64 + - cc: GCC + platform: x86 + cross: i686 + bits: 32 + name: Windows / MSYS2 ${{ matrix.cc }} / ${{ matrix.platform }} + runs-on: windows-2019 + defaults: + run: + shell: msys2 {0} + steps: + - uses: actions/checkout@v2 + - uses: msys2/setup-msys2@v2 + with: + msystem: MINGW${{ matrix.bits }} + update: true + install: >- + git + make + mingw-w64-${{ matrix.cross }}-gcc + mingw-w64-${{ matrix.cross }}-toolchain + mingw-w64-${{ matrix.cross }}-freetype + mingw-w64-${{ matrix.cross }}-libpng + mingw-w64-${{ matrix.cross }}-nasm + mingw-w64-${{ matrix.cross }}-SDL2 + mingw-w64-${{ matrix.cross }}-zlib + - name: Build and related stuff + run: | + export OPTFLAGS="-O2 -flto" + echo "G_REV=$(git rev-parse --short HEAD)" >> "${GITHUB_ENV}" + CC="gcc" + CXX="g++" + ${CC} --version + mkdir backup + LIB="-old" + for DYN in 0 1 + do + echo "" + echo ":: ${{ matrix.cc }} ${{ matrix.platform }} / SDL2${MSG} ::" + echo "" + make -C projects/unix clean + echo "" + make CC="${CC}" CXX="${CXX}" BITS="${{ matrix.bits }}" NEW_DYNAREC="${DYN}" -C projects/unix all + echo "" + cp projects/unix/*.dll backup/mupen64plus${LIB}.dll + ls -gG backup/mupen64plus${LIB}.dll + ldd backup/mupen64plus${LIB}.dll + unset LIB + MSG=" / NEW_DYNAREC" + done + - name: Copy binaries, dependencies, etc... + run: | + mkdir pkg + if [[ ${{ matrix.bits }} -eq 32 ]]; then LIBGCC="libgcc_s_dw2-1"; else LIBGCC="libgcc_s_seh-1"; fi + for LIB in libbrotlicommon libbrotlidec libbz2-1 libfreetype-6 ${LIBGCC} libglib-2.0-0 libgraphite2 libharfbuzz-0 libiconv-2 libintl-8 libpcre-1 libpng16-16 libstdc++-6 libwinpthread-1 SDL2 zlib1 + do + echo ":: Copying ${LIB}.dll" + cp "/mingw${{ matrix.bits }}/bin/${LIB}.dll" pkg/ + done + if [ -d data ]; then + cd data + for DAT in * + do + echo ":: Copying ${DAT}" + cp -r "${DAT}" ../pkg/ + done + fi + cd ../backup + for BIN in *.dll + do + echo ":: Copying ${BIN}" + cp "${BIN}" ../pkg/ + done + - name: Upload artifact + uses: actions/upload-artifact@v2 + with: + name: mupen64plus-core-msys2-${{ matrix.platform }}-g${{ env.G_REV }} + path: pkg/* + + MSVC: + strategy: + fail-fast: false + matrix: + include: + - toolset: v142 + platform: x64 + - toolset: v141_xp + platform: x86 + name: Windows / MSVC ${{ matrix.toolset }} / ${{ matrix.platform }} + runs-on: windows-2019 + defaults: + run: + shell: cmd + steps: + - uses: actions/checkout@v2 + - uses: microsoft/setup-msbuild@v1.0.3 + # with: + # vs-version: 16.11 + - name: Build and related stuff + run: | + for /f "tokens=1" %%R in ('git rev-parse --short HEAD') do set "G_REV=%%R" + echo G_REV=%G_REV%>> "%GITHUB_ENV%" + set "ARCH=${{ matrix.platform }}" + if [%ARCH%] == [x86] set "ARCH=Win32" + echo. + msbuild --version + echo. + git clone --depth 1 https://github.com/mupen64plus/mupen64plus-win32-deps.git ..\mupen64plus-win32-deps + md backup + for %%B in (Release New_Dynarec_Release) do ( + echo. + msbuild "projects\msvc\mupen64plus-core.vcxproj" /p:Configuration=%%B;Platform=%ARCH%;PlatformToolset=${{ matrix.toolset }} /t:Rebuild + echo. + copy "projects\msvc\%ARCH%\%%B\mupen64plus.dll" backup\ + if not exist "backup\mupen64plus-old.dll" ( + ren "backup\mupen64plus.dll" "mupen64plus-old.dll" + dir "backup\mupen64plus-old.dll" + ) else dir "backup\mupen64plus.dll" + ) + - name: Copy binaries, dependencies, etc... + run: | + md pkg + cd pkg + xcopy "..\backup" . + xcopy "..\data" . + copy "..\..\mupen64plus-win32-deps\freetype-2.10.1\lib\${{ matrix.platform }}\*.dll" . + copy "..\..\mupen64plus-win32-deps\libpng-1.6.37\lib\${{ matrix.platform }}\*.dll" . + copy "..\..\mupen64plus-win32-deps\SDL2-2.0.10\lib\${{ matrix.platform }}\*.dll" . + copy "..\..\mupen64plus-win32-deps\SDL2_net-2.0.1\lib\${{ matrix.platform }}\*.dll" . + copy "..\..\mupen64plus-win32-deps\zlib-1.2.11\lib\${{ matrix.platform }}\*.dll" . + - name: Upload artifact + uses: actions/upload-artifact@v2 + with: + name: mupen64plus-core-msvc-${{ matrix.platform }}-g${{ env.G_REV }} + path: pkg/* + + Nightly-build: + runs-on: ubuntu-latest + needs: [MSYS2, MSVC] + if: github.ref == 'refs/heads/master' + steps: + - uses: actions/checkout@v2 + - name: Download artifacts + uses: actions/download-artifact@v2 + with: + path: binaries + - name: Get some tools + run: | + sudo apt-get update + sudo apt-get -y install hashdeep + - name: Creating new artifacts and update nightly-build + run: | + mkdir pkg + cd binaries + for BIN in * + do + echo ":: Creating ${BIN}.zip" + cd "${BIN}" + zip -r "../../pkg/${BIN}.zip" * + cd .. + done + cd ../pkg + echo "" + for BIN in *.zip + do + ls -gG ${BIN} + tigerdeep -l ${BIN} >> ${BIN:0:16}.tiger.txt + sha256sum ${BIN} >> ${BIN:0:16}.sha256.txt + sha512sum ${BIN} >> ${BIN:0:16}.sha512.txt + done + echo "" + echo "TIGER:" + cat *.tiger.txt + echo "" + echo "SHA256:" + cat *.sha256.txt + echo "" + echo "SHA512:" + cat *.sha512.txt + echo "" + git tag -f nightly-build + git push -f origin nightly-build + - name: Nightly-build + uses: ncipollo/release-action@v1 + with: + prerelease: true + allowUpdates: true + removeArtifacts: true + replacesArtifacts: false + tag: nightly-build + artifacts: pkg/* diff --git a/mupen64plus-core/projects/unix/Makefile b/mupen64plus-core/projects/unix/Makefile index 679219f..6478294 100755 --- a/mupen64plus-core/projects/unix/Makefile +++ b/mupen64plus-core/projects/unix/Makefile @@ -99,25 +99,30 @@ endif ifneq ("$(filter arm%,$(HOST_CPU))","") ifeq ("$(filter arm%b,$(HOST_CPU))","") CPU := ARM - ARCH_DETECTED := 32BITS PIC ?= 1 NEW_DYNAREC := 1 - CFLAGS += -marm - ifneq ("$(filter armv5%,$(HOST_CPU))","") - CFLAGS += -DARMv5_ONLY - $(warning Using ARMv5_ONLY) - endif - ifneq ("$(filter armv6%,$(HOST_CPU))","") - CFLAGS += -DARMv5_ONLY - $(warning Using ARMv5_ONLY) - endif - ifeq ($(NEON), 1) - CFLAGS += -mfpu=neon -mfloat-abi=hard + ifneq ("$(filter arm64,$(HOST_CPU))","") + ARCH_DETECTED := 64BITS + $(warning Architecture "$(HOST_CPU)" not officially supported.) else - ifeq ($(VFP_HARD), 1) - CFLAGS += -mfpu=vfp -mfloat-abi=hard + ARCH_DETECTED := 32BITS + CFLAGS += -marm + ifneq ("$(filter armv5%,$(HOST_CPU))","") + CFLAGS += -DARMv5_ONLY + $(warning Using ARMv5_ONLY) + endif + ifneq ("$(filter armv6%,$(HOST_CPU))","") + CFLAGS += -DARMv5_ONLY + $(warning Using ARMv5_ONLY) + endif + ifeq ($(NEON), 1) + CFLAGS += -mfpu=neon -mfloat-abi=hard else - CFLAGS += -mfpu=vfp -mfloat-abi=softfp + ifeq ($(VFP_HARD), 1) + CFLAGS += -mfpu=vfp -mfloat-abi=hard + else + CFLAGS += -mfpu=vfp -mfloat-abi=softfp + endif endif endif endif @@ -175,9 +180,21 @@ ifeq ($(ARCH_DETECTED), 64BITS_32) ifeq ($(OS), FREEBSD) $(error Do not use the BITS=32 option with FreeBSD, use -m32 and -m elf_i386) endif - ifneq ($(OS),OSX) - CFLAGS += -m32 - LDFLAGS += -Wl,-m,elf_i386 + ifneq ($(OS), OSX) + ifeq ($(OS), MINGW) + CFLAGS += -march=i686 + LDFLAGS += -Wl,-m,i386pe + else + CFLAGS += -m32 + LDFLAGS += -Wl,-m,elf_i386 + endif + endif +endif + +ifeq ($(ARCH_DETECTED), 64BITS) + ifeq ($(OS), MINGW) + CFLAGS += -march=x86-64 + LDFLAGS += -Wl,-m,i386pep endif endif @@ -230,6 +247,11 @@ ifeq ($(OS), OSX) LDFLAGS += -read_only_relocs suppress endif endif + ifeq ($(CPU), ARM) + # assembly compilation not yet supported on macOS with Apple Silicon + NO_ASM = 1 + CFLAGS += -pipe -arch arm64 -mmacosx-version-min=10.16 -isysroot $(OSX_SDK_PATH) + endif endif ifeq ($(OS), MINGW) TARGET = mupen64plus$(POSTFIX).dll diff --git a/mupen64plus-core/src/device/controllers/paks/mempak.c b/mupen64plus-core/src/device/controllers/paks/mempak.c index a0536b5..e57dc5f 100644 --- a/mupen64plus-core/src/device/controllers/paks/mempak.c +++ b/mupen64plus-core/src/device/controllers/paks/mempak.c @@ -23,61 +23,131 @@ #include "backends/api/storage_backend.h" #include "device/controllers/game_controller.h" +#include "main/util.h" +#include +#include #include #include +/* Serialized representation of ID Block + * Only used to ease offsets/pointers computation + * DO NOT DEREFERENCE + */ +#pragma pack(push, 1) +struct id_block_serialized { + uint32_t serial[6]; + uint16_t device_id; + uint8_t banks; + uint8_t version; + uint16_t sum; + uint16_t isum; +}; +#pragma pack(pop) +#if defined(static_assert) +static_assert(sizeof(struct id_block_serialized) == 32, "id_block_serialized must have a size of 32 bytes"); +#endif -void format_mempak(uint8_t* mem) +static void checksum_id_block(unsigned char* ptr, + uint16_t* sum, uint16_t* isum) +{ + size_t i; + uint16_t accu = 0; + for (i = 0; i < offsetof(struct id_block_serialized, sum); i += 2) { + accu += load_beu16((void*)&ptr[i]); + } + *sum = accu; + *isum = UINT16_C(0xfff2) - accu; +} + +static uint8_t checksum_index_table(size_t count, unsigned char* ptr) +{ + unsigned sum = 0; + while (count != 0) { + sum += load_beu8((void*)ptr); + ++ptr; + --count; + } + + return (uint8_t)sum; +} + +static void serialize_id_block(unsigned char *ptr, const uint32_t serial[6], uint16_t device_id, uint8_t banks, uint8_t version) { + + size_t i; + /* _ should never be dereferenced - it is only used to ease pointer/offsets computation */ + struct id_block_serialized* const _ = (struct id_block_serialized*)ptr; + + + for (i = 0; i < 6; ++i) { + store_beu32(serial[i], (void*)&_->serial[i]); + } + store_beu16(device_id, (void*)&_->device_id); + store_beu8(banks, (void*)&_->banks); + store_beu8(version, (void*)&_->version); + + uint16_t sum, isum; + checksum_id_block(ptr, &sum, &isum); + + store_beu16(sum, (void*)&_->sum); + store_beu16(isum, (void*)&_->isum); +} + + + +void format_mempak(uint8_t* mem, + const uint32_t serial[6], + uint16_t device_id, + uint8_t banks, + uint8_t version) { enum { MPK_PAGE_SIZE = 256 }; - size_t i; - static const uint8_t page_0[MPK_PAGE_SIZE] = - { - /* Label area */ - 0x81,0x01,0x02,0x03, 0x04,0x05,0x06,0x07, 0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f, - 0x10,0x11,0x12,0x13, 0x14,0x15,0x16,0x17, 0x18,0x19,0x1a,0x1b, 0x1c,0x1d,0x1e,0x1f, - /* Main ID area */ - 0xff,0xff,0xff,0xff, 0x05,0x1a,0x5f,0x13, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, - 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0x01,0xff, 0x66,0x25,0x99,0xcd, - /* Unused */ - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, - /* ID area backup #1 */ - 0xff,0xff,0xff,0xff, 0x05,0x1a,0x5f,0x13, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, - 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0x01,0xff, 0x66,0x25,0x99,0xcd, - /* ID area backup #2 */ - 0xff,0xff,0xff,0xff, 0x05,0x1a,0x5f,0x13, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, - 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0x01,0xff, 0x66,0x25,0x99,0xcd, - /* Unused */ - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, - /* ID area backup #3 */ - 0xff,0xff,0xff,0xff, 0x05,0x1a,0x5f,0x13, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, - 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0x01,0xff, 0x66,0x25,0x99,0xcd, - /* Unused */ - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00 - }; + uint8_t* const page_0 = mem + 0*MPK_PAGE_SIZE; + uint8_t* const page_1 = mem + 1*MPK_PAGE_SIZE; + uint8_t* const page_2 = mem + 2*MPK_PAGE_SIZE; + uint8_t* const page_3 = mem + 3*MPK_PAGE_SIZE; - /* Fill Page 0 with pre-initialized content */ - memcpy(mem, page_0, MPK_PAGE_SIZE); + /* Page 0 is divided in 8 x 32-byte blocks: + * 0. reserved + * 1. ID + * 2. reserved + * 3. ID backup #1 + * 4. ID backup #2 + * 5. reserved + * 6. ID backup #3 + * 7. reserved + */ + serialize_id_block(page_0 + 1*32, serial, device_id, banks, version); - /* Fill INODE page 1 and update it's checkum */ + memset(page_0 + 0*32, 0, 32); + memset(page_0 + 2*32, 0, 32); + memset(page_0 + 5*32, 0, 32); + memset(page_0 + 7*32, 0, 32); + + memcpy(page_0 + 3*32, page_0 + 1*32, 32); + memcpy(page_0 + 4*32, page_0 + 1*32, 32); + memcpy(page_0 + 6*32, page_0 + 1*32, 32); + + /* Page 1 holds the index table. + * The first 5 inodes are reserved because the first 5 pages are reserved. + * The first inode page index holds the checksum of the 123 normal nodes. + * The remaining 123 pages are marked empty. + */ size_t start_page = 5; - memset(mem + 1*MPK_PAGE_SIZE, 0, 2*start_page); - for (i = 1*MPK_PAGE_SIZE+2*start_page; i < 2*MPK_PAGE_SIZE; i += 2) { - mem[i+0] = 0x00; - mem[i+1] = 0x03; + size_t last_page = 128; + size_t i; + memset(page_1, 0, 2*start_page); + for(i = start_page; i < last_page; ++i) { + store_beu16(UINT16_C(0x0003), page_1 + 2*i); } - mem[1*MPK_PAGE_SIZE + 1] = 0x71; + page_1[1] = checksum_index_table(2*(last_page-start_page), page_1 + 2*start_page); - /* Page 2 is identical to page 1 */ - memcpy(mem + 2*MPK_PAGE_SIZE, mem + 1*MPK_PAGE_SIZE, MPK_PAGE_SIZE); + /* Page 2 is a backup of Page 1 */ + memcpy(page_2, page_1, MPK_PAGE_SIZE); /* Remaining pages DIR+DATA (3...) are initialized with 0x00 */ - memset(mem + 3*MPK_PAGE_SIZE, 0, MEMPAK_SIZE - 3*MPK_PAGE_SIZE); + memset(page_3, 0, MEMPAK_SIZE - 3*MPK_PAGE_SIZE); } diff --git a/mupen64plus-core/src/device/controllers/paks/mempak.h b/mupen64plus-core/src/device/controllers/paks/mempak.h index 39159f0..1cbad59 100644 --- a/mupen64plus-core/src/device/controllers/paks/mempak.h +++ b/mupen64plus-core/src/device/controllers/paks/mempak.h @@ -27,6 +27,10 @@ struct storage_backend_interface; +#define DEFAULT_MEMPAK_DEVICEID UINT16_C(0x0001) +#define DEFAULT_MEMPAK_BANKS UINT8_C(0x01) +#define DEFAULT_MEMPAK_VERSION UINT8_C(0x00) + struct mempak { void* storage; @@ -35,7 +39,11 @@ struct mempak enum { MEMPAK_SIZE = 0x8000 }; -void format_mempak(uint8_t* mem); +void format_mempak(uint8_t* mem, + const uint32_t serial[6], + uint16_t device_id, + uint8_t banks, + uint8_t version); void init_mempak(struct mempak* mpk, void* storage, diff --git a/mupen64plus-core/src/main/main.c b/mupen64plus-core/src/main/main.c index 0cf4f11..fcb77ef 100644 --- a/mupen64plus-core/src/main/main.c +++ b/mupen64plus-core/src/main/main.c @@ -135,6 +135,9 @@ static void* l_paks[GAME_CONTROLLERS_COUNT][PAK_MAX_SIZE]; static const struct pak_interface* l_ipaks[PAK_MAX_SIZE]; static size_t l_pak_type_idx[6]; +/* PRNG state - used for Mempaks ID generation */ +static struct xoshiro256pp_state l_mpk_idgen; + /********************************************************************************************************* * static functions */ @@ -1014,7 +1017,19 @@ static void open_mpk_file(struct file_storage* fstorage) if (ret == (int)file_open_error) { /* if file doesn't exists provide default content */ for(i = 0; i < GAME_CONTROLLERS_COUNT; ++i) { - format_mempak(fstorage->data + i * MEMPAK_SIZE); + + /* Generate a random serial ID */ + uint32_t serial[6]; + size_t k; + for (k = 0; k < 6; ++k) { + serial[k] = xoshiro256pp_next(&l_mpk_idgen); + } + + format_mempak(fstorage->data + i * MEMPAK_SIZE, + serial, + DEFAULT_MEMPAK_DEVICEID, + DEFAULT_MEMPAK_BANKS, + DEFAULT_MEMPAK_VERSION); } } } @@ -1471,6 +1486,10 @@ m64p_error main_run(void) break; } + /* Seed MPK ID gen using current time */ + uint64_t mpk_seed = !netplay_is_init() ? (uint64_t)time(NULL) : 0; + l_mpk_idgen = xoshiro256pp_seed(mpk_seed); + /* take the r4300 emulator mode from the config file at this point and cache it in a global variable */ emumode = ConfigGetParamInt(g_CoreConfig, "R4300Emulator"); diff --git a/mupen64plus-core/src/main/util.c b/mupen64plus-core/src/main/util.c index 78cb546..3fffc2e 100644 --- a/mupen64plus-core/src/main/util.c +++ b/mupen64plus-core/src/main/util.c @@ -257,6 +257,182 @@ void to_big_endian_buffer(void *buffer, size_t length, size_t count) #endif } +/* Simple serialization primitives, + * Use byte access to avoid alignment issues. + */ +uint8_t load_beu8(const unsigned char *ptr) +{ + return (uint8_t)ptr[0]; +} + +uint16_t load_beu16(const unsigned char *ptr) +{ + return ((uint16_t)ptr[0] << 8) + | ((uint16_t)ptr[1] << 0); +} + +uint32_t load_beu32(const unsigned char *ptr) +{ + return ((uint32_t)ptr[0] << 24) + | ((uint32_t)ptr[1] << 16) + | ((uint32_t)ptr[2] << 8) + | ((uint32_t)ptr[3] << 0); +} + +uint64_t load_beu64(const unsigned char *ptr) +{ + return ((uint64_t)ptr[0] << 56) + | ((uint64_t)ptr[1] << 48) + | ((uint64_t)ptr[2] << 40) + | ((uint64_t)ptr[3] << 32) + | ((uint64_t)ptr[4] << 24) + | ((uint64_t)ptr[5] << 16) + | ((uint64_t)ptr[6] << 8) + | ((uint64_t)ptr[7] << 0); +} + + +uint8_t load_leu8(const unsigned char *ptr) +{ + return (uint8_t)ptr[0]; +} + +uint16_t load_leu16(const unsigned char *ptr) +{ + return ((uint16_t)ptr[0] << 0) + | ((uint16_t)ptr[1] << 8); +} + +uint32_t load_leu32(const unsigned char *ptr) +{ + return ((uint32_t)ptr[0] << 0) + | ((uint32_t)ptr[1] << 8) + | ((uint32_t)ptr[2] << 16) + | ((uint32_t)ptr[3] << 24); +} + +uint64_t load_leu64(const unsigned char *ptr) +{ + return ((uint64_t)ptr[0] << 0) + | ((uint64_t)ptr[1] << 8) + | ((uint64_t)ptr[2] << 16) + | ((uint64_t)ptr[3] << 24) + | ((uint64_t)ptr[4] << 32) + | ((uint64_t)ptr[5] << 40) + | ((uint64_t)ptr[6] << 48) + | ((uint64_t)ptr[7] << 56); +} + + + +void store_beu8(uint8_t value, unsigned char *ptr) +{ + ptr[0] = (uint8_t)value; +} + +void store_beu16(uint16_t value, unsigned char *ptr) +{ + ptr[0] = (uint8_t)(value >> 8); + ptr[1] = (uint8_t)(value >> 0); +} + +void store_beu32(uint32_t value, unsigned char *ptr) +{ + ptr[0] = (uint8_t)(value >> 24); + ptr[1] = (uint8_t)(value >> 16); + ptr[2] = (uint8_t)(value >> 8); + ptr[3] = (uint8_t)(value >> 0); +} + +void store_beu64(uint64_t value, unsigned char *ptr) +{ + ptr[0] = (uint8_t)(value >> 56); + ptr[1] = (uint8_t)(value >> 48); + ptr[2] = (uint8_t)(value >> 40); + ptr[3] = (uint8_t)(value >> 32); + ptr[4] = (uint8_t)(value >> 24); + ptr[5] = (uint8_t)(value >> 16); + ptr[6] = (uint8_t)(value >> 8); + ptr[7] = (uint8_t)(value >> 0); +} + + +void store_leu8(uint8_t value, unsigned char *ptr) +{ + ptr[0] = (uint8_t)value; +} + +void store_leu16(uint16_t value, unsigned char *ptr) +{ + ptr[0] = (uint8_t)(value >> 0); + ptr[1] = (uint8_t)(value >> 8); +} + +void store_leu32(uint32_t value, unsigned char *ptr) +{ + ptr[0] = (uint8_t)(value >> 0); + ptr[1] = (uint8_t)(value >> 8); + ptr[2] = (uint8_t)(value >> 16); + ptr[3] = (uint8_t)(value >> 24); +} + +void store_leu64(uint64_t value, unsigned char *ptr) +{ + ptr[0] = (uint8_t)(value >> 0); + ptr[1] = (uint8_t)(value >> 8); + ptr[2] = (uint8_t)(value >> 16); + ptr[3] = (uint8_t)(value >> 24); + ptr[4] = (uint8_t)(value >> 32); + ptr[5] = (uint8_t)(value >> 40); + ptr[6] = (uint8_t)(value >> 48); + ptr[7] = (uint8_t)(value >> 56); +} + + +/********************** + Random utilities + **********************/ + +static inline uint64_t rotl(uint64_t x, int k) { + return (x << k) | (x >> (64 - k)); +} + +struct splitmix64_state { uint64_t x; }; + +static uint64_t splitmix64_next(struct splitmix64_state* s) { + uint64_t z = (s->x += 0x9e3779b97f4a7c15); + z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; + z = (z ^ (z >> 27)) * 0x94d049bb133111eb; + return z ^ (z >> 31); +} + +struct xoshiro256pp_state xoshiro256pp_seed(uint64_t seed) +{ + struct xoshiro256pp_state xs; + struct splitmix64_state ss = { seed }; + + size_t i; + for (i = 0; i < 4; ++i) { + xs.s[i] = splitmix64_next(&ss); + } + + return xs; +} + +uint64_t xoshiro256pp_next(struct xoshiro256pp_state* s) { + uint64_t result = rotl(s->s[0] + s->s[3], 23) + s->s[0]; + + uint64_t t = s->s[1] << 17; + s->s[2] ^= s->s[0]; + s->s[3] ^= s->s[1]; + s->s[1] ^= s->s[2]; + s->s[0] ^= s->s[3]; + s->s[2] ^= t; + s->s[3] = rotl(s->s[3], 45); + + return result; +} + /********************** GUI utilities **********************/ diff --git a/mupen64plus-core/src/main/util.h b/mupen64plus-core/src/main/util.h index 2ce73a7..fc502c1 100644 --- a/mupen64plus-core/src/main/util.h +++ b/mupen64plus-core/src/main/util.h @@ -150,6 +150,41 @@ void swap_buffer(void *buffer, size_t length, size_t count); void to_little_endian_buffer(void *buffer, size_t length, size_t count); void to_big_endian_buffer(void *buffer, size_t length, size_t count); + +/* Simple serialization primitives, + * Loosely modeled after N2827 proposal. + */ +uint8_t load_beu8(const unsigned char *ptr); +uint16_t load_beu16(const unsigned char *ptr); +uint32_t load_beu32(const unsigned char *ptr); +uint64_t load_beu64(const unsigned char *ptr); + +uint8_t load_leu8(const unsigned char *ptr); +uint16_t load_leu16(const unsigned char *ptr); +uint32_t load_leu32(const unsigned char *ptr); +uint64_t load_leu64(const unsigned char *ptr); + +void store_beu8(uint8_t value, unsigned char *ptr); +void store_beu16(uint16_t value, unsigned char *ptr); +void store_beu32(uint32_t value, unsigned char *ptr); +void store_beu64(uint64_t value, unsigned char *ptr); + +void store_leu8(uint8_t value, unsigned char *ptr); +void store_leu16(uint16_t value, unsigned char *ptr); +void store_leu32(uint32_t value, unsigned char *ptr); +void store_leu64(uint64_t value, unsigned char *ptr); + + +/********************** + Random utilities + **********************/ + +struct xoshiro256pp_state { uint64_t s[4]; }; + +struct xoshiro256pp_state xoshiro256pp_seed(uint64_t seed); + +uint64_t xoshiro256pp_next(struct xoshiro256pp_state* s); + /********************** GUI utilities **********************/