Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions runtime-ext/base.ld
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,15 @@ PHDRS {

SECTIONS {
# .init, .text and .rodata are specified in Makefile LDFLAGS
.dvd_trampolines 0x81782d60 : { *(.dvd_trampolines) } :dvd
.sd_vtable 0x81782e00 : { *(.sd_vtable) } :dvd
.dvd_convert_path_to_entrynum 0x81782e60 : { *(.dvd_convert_path_to_entrynum) } :dvd
.dvd_open 0x81782ea0 : { *(.dvd_open) } :dvd
.dvd_fast_open 0x81782ee0 : { *(.dvd_fast_open) } :dvd
.dvd_read_prio 0x81782f20 : { *(.dvd_read_prio) } :dvd
.dvd_close 0x81782f60 : { *(.dvd_close) } :dvd
.riivo_disc 0x81782fa0 : { *(.riivo_disc) } :dvd
.internal_version 0x81782d50 : { KEEP(*(.internal_version)); } :dvd
.dvd_trampolines 0x81782d60 : { KEEP(*(.dvd_trampolines)); } :dvd
.sd_vtable 0x81782e00 : { KEEP(*(.sd_vtable)); } :dvd
.dvd_convert_path_to_entrynum 0x81782e60 : { KEEP(*(.dvd_convert_path_to_entrynum)); } :dvd
.dvd_open 0x81782ea0 : { KEEP(*(.dvd_open)); } :dvd
.dvd_fast_open 0x81782ee0 : { KEEP(*(.dvd_fast_open)); } :dvd
.dvd_read_prio 0x81782f20 : { KEEP(*(.dvd_read_prio)); } :dvd
.dvd_close 0x81782f60 : { KEEP(*(.dvd_close)); } :dvd
.riivo_disc 0x81782fa0 : { KEEP(*(.riivo_disc)); } :dvd

PROVIDE(dvd_convert_path_to_entrynum_trampoline = ADDR(.dvd_trampolines));
PROVIDE(dvd_fast_open_trampoline = ADDR(.dvd_trampolines) + 32);
Expand Down
22 changes: 8 additions & 14 deletions runtime-ext/source/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,12 @@
#include "dvd.h"
#include "trampoline.h"
#include <errno.h>
#include <version.h>

#define EXPORT_FUNCTION(secname, decl_args, call_args, implname) \
__attribute__((section(secname))) s32 __##implname decl_args \
{ \
return implname call_args; \
#define EXPORT_FUNCTION(secname, decl_args, call_args, implname) \
__attribute__((section(secname), used)) s32 __##implname decl_args \
{ \
return implname call_args; \
}

EXPORT_FUNCTION(".dvd_convert_path_to_entrynum", (const char *path), (path), custom_convert_path_to_entry_num_impl);
Expand All @@ -43,6 +44,8 @@ EXPORT_FUNCTION(".dvd_fast_open", (s32 entry_num, FileInfo *file_info), (entry_n
EXPORT_FUNCTION(".dvd_read_prio", (FileInfo * file_info, void *buffer, s32 length, s32 offset, s32 prio), (file_info, buffer, length, offset, prio), custom_read_prio_impl);
EXPORT_FUNCTION(".dvd_close", (FileInfo * file_info), (file_info), custom_close_impl);

__attribute__((section(".internal_version"), used)) struct rrc_version _rrc_internal_version = RRC_INTERNAL_VERSION;

struct sd_vtable
{
void *open;
Expand All @@ -64,7 +67,7 @@ int SD_errno()
return errno;
}

__attribute__((section(".sd_vtable"))) static struct sd_vtable __sd_vtable = {
__attribute__((section(".sd_vtable"), used)) static struct sd_vtable __sd_vtable = {
.open = SD_open,
.close = SD_close,
.read = SD_read,
Expand All @@ -81,15 +84,6 @@ __attribute__((section(".sd_vtable"))) static struct sd_vtable __sd_vtable = {

int _start()
{
// Prevent linker from DCE'ing the symbols
*(volatile u32 *)__custom_convert_path_to_entry_num_impl;
*(volatile u32 *)__custom_open_impl;
*(volatile u32 *)__custom_fast_open_impl;
*(volatile u32 *)__custom_read_prio_impl;
*(volatile u32 *)__custom_close_impl;
*(volatile u32 *)((volatile struct sd_vtable *)&__sd_vtable)->open;
*(volatile u32 *)(_rrc_trampoline_scratch_space);

// Get the compiler to remove all unnecessary libogc deinitialization code, this function is never actually called
while (1)
;
Expand Down
15 changes: 2 additions & 13 deletions source/version.h → shared/version.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
version.h - version structure and related functions
version.h - version structure

Copyright (C) 2025 Retro Rewind Team
Copyright (C) 2026 Retro Rewind Team

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Expand All @@ -20,9 +20,6 @@
#ifndef RRC_VERSION_H
#define RRC_VERSION_H

#include <gctypes.h>
#include "result.h"

#define _RRC_INTERNAL_VERSION_MAJOR 0
#define _RRC_INTERNAL_VERSION_MINOR 9
#define _RRC_INTERNAL_VERSION_PATCH 0
Expand All @@ -38,12 +35,4 @@ struct rrc_version
int patch;
};

/// Returns true if version a is older than version b, false otherwise
bool rrc_version_is_older(const struct rrc_version *a, const struct rrc_version *b);

/// Parses a version string of the format "major.minor.patch" into a rrc_version struct. Returns an error if the format is invalid.
struct rrc_result rrc_version_from_string(const char *version_str, struct rrc_version *out_version);

bool rrc_version_equals(const struct rrc_version *a, const struct rrc_version *b);

#endif /* RRC_VERSION_H */
13 changes: 13 additions & 0 deletions source/loader/loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include <riivo.h>
#include "../util.h"
#include "../settingsfile.h"
#include "../versionutils.h"
#include <bitflags.h>

bool rrc_signature_written()
Expand Down Expand Up @@ -157,6 +158,18 @@ void rrc_loader_load(struct rrc_dol *dol, struct rrc_settingsfile *settings, voi
rrc_con_update("Load Runtime Extensions", 70);
rrc_binary_load_runtime_ext(region);

struct rrc_version *runtime_ext_internal_version = (struct rrc_version *)RRC_RUNTIME_EXT_INTERNAL_VERSION;
if (!rrc_version_equals(runtime_ext_internal_version, &RRC_INTERNAL_VERSION))
{
struct rrc_result err = rrc_result_create_error_version_mismatch("runtime-ext version does not match channel\n"
"version!\n\n"
"Consider manually updating the channel at this time,\n"
"or join our discord if you need further help:\n"
"https://discord.gg/retrorewind");
rrc_result_error_check_error_fatal(err);
return;
}

rrc_con_update("Load Patch Information", 80);
struct parse_riivo_output riivo_out;
res = rrc_riivo_patch_loader_parse(settings, &mem1_hi, &mem2_hi, dol, &riivo_out);
Expand Down
2 changes: 2 additions & 0 deletions source/loader/loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ bool rrc_signature_written();
#define RRC_RIIVO_DISC_PTR 0x81782fa0
// Must be kept in sync with the .dvd_trampolines section address in runtime-ext's linker script
#define RRC_TRAMPOLINE_START 0x81782d60
// Must be kept in sync with the .internal_version section address in runtime-ext's linker script
#define RRC_RUNTIME_EXT_INTERNAL_VERSION 0x81782d50

// The absolute highest address that the runtime-ext DOL may use.
// We have an assert that makes sure we never copy past this.
Expand Down
10 changes: 10 additions & 0 deletions source/result.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,14 @@ struct rrc_result rrc_result_create_error_corrupted_rr_xml(const char *context)
return res;
}

struct rrc_result rrc_result_create_error_version_mismatch(const char *context)
{

union rrc_result_error_inner einner = {0};
struct rrc_result res = {.err = alloc_error(ESOURCE_VERSION_MISMATCH, einner, context)};
return res;
}

char *rrc_result_strerror(struct rrc_result result)
{
if (!rrc_result_is_error(result))
Expand Down Expand Up @@ -137,6 +145,8 @@ char *rrc_result_strerror(struct rrc_result result)
}
case ESOURCE_CORRUPTED_RR_XML:
return "Invalid or corrupted RetroRewind6.xml.";
case ESOURCE_VERSION_MISMATCH:
return "Version mismatch.";
default:
return NULL;
}
Expand Down
6 changes: 5 additions & 1 deletion source/result.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ enum rrc_result_error_source
ESOURCE_SD_CARD,
/* Failure to initialise network */
ESOURCE_WIISOCKET_INIT,
ESOURCE_CORRUPTED_RR_XML
ESOURCE_CORRUPTED_RR_XML,
/* Version mismatch (currently for runtime-ext and channel) */
ESOURCE_VERSION_MISMATCH
};

/* Because each library uses their own set of error codes, we need to support all
Expand Down Expand Up @@ -132,6 +134,8 @@ struct rrc_result rrc_result_create_error_misc_update(const char *context);

struct rrc_result rrc_result_create_error_corrupted_rr_xml(const char *context);

struct rrc_result rrc_result_create_error_version_mismatch(const char *context);

/* Returns true if this result is an error, false otherwise. */
inline bool rrc_result_is_error(struct rrc_result result)
{
Expand Down
2 changes: 1 addition & 1 deletion source/update/update.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
#include "../time.h"
#include "../prompt.h"
#include "../shutdown.h"
#include "../version.h"
#include "../versionutils.h"
#include "../sd.h"

#define _RRC_UPDATE_ZIP_NAME "rr.update.zip"
Expand Down
2 changes: 1 addition & 1 deletion source/update/update.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#include <dir.h>
#include <curl/curl.h>
#include "../result.h"
#include "../version.h"
#include "../versionutils.h"

#define RRC_UPDATE_LARGE_THRESHOLD (long)(1000 * 1000 * 100) /* 100MB */
#define RRC_VERSIONFILE "/" RRC_RETRO_REWIND_BASE_DIR "/version.txt"
Expand Down
2 changes: 1 addition & 1 deletion source/update/versionsfile.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
#define RRC_VERSIONSFILE_H

#include "../result.h"
#include "../version.h"
#include "../versionutils.h"

struct rrc_versionsfile_deleted_file
{
Expand Down
8 changes: 4 additions & 4 deletions source/version.c → source/versionutils.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
version.c - version structure and related functions
versionutils.c - utility function implementations for working with `rrc_version`s

Copyright (C) 2025 Retro Rewind Team
Copyright (C) 2026 Retro Rewind Team

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Expand All @@ -17,7 +17,7 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

#include "version.h"
#include "versionutils.h"
#include <string.h>
#include <stdlib.h>

Expand Down Expand Up @@ -92,4 +92,4 @@ struct rrc_result rrc_version_from_string(const char *version_str, struct rrc_ve
bool rrc_version_equals(const struct rrc_version *a, const struct rrc_version *b)
{
return (a->major == b->major) && (a->minor == b->minor) && (a->patch == b->patch);
}
}
35 changes: 35 additions & 0 deletions source/versionutils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
versionutils.h - utility function declarations for working with `rrc_version`s

Copyright (C) 2026 Retro Rewind Team

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

#ifndef RRC_VERSIONUTILS_H
#define RRC_VERSIONUTILS_H

#include <gctypes.h>
#include <version.h>
#include "result.h"

/// Returns true if version a is older than version b, false otherwise
bool rrc_version_is_older(const struct rrc_version *a, const struct rrc_version *b);

/// Parses a version string of the format "major.minor.patch" into a rrc_version struct. Returns an error if the format is invalid.
struct rrc_result rrc_version_from_string(const char *version_str, struct rrc_version *out_version);

bool rrc_version_equals(const struct rrc_version *a, const struct rrc_version *b);

#endif /* RRC_VERSIONUTILS_H */
Loading