Skip to content

Commit

Permalink
- Parse El Torito boot record.
Browse files Browse the repository at this point in the history
  • Loading branch information
Extrems committed Jan 19, 2025
1 parent b58f1d3 commit ec8d5aa
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 9 deletions.
2 changes: 1 addition & 1 deletion cube/swiss/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ INCLUDES := include $(SOURCES) ..
# options for code generation
#---------------------------------------------------------------------------------

CFLAGS = -g -O2 -Wall -Wno-format-truncation -fno-strict-aliasing -D_GNU_SOURCE $(MACHDEP) $(INCLUDE) -D'GIT_COMMIT="$(shell git rev-parse --short HEAD)"' -D'GIT_REVISION="$(shell git rev-list HEAD | wc -l)"'
CFLAGS = -g -O2 -Wall -Wno-format-truncation -Wno-scalar-storage-order -fno-strict-aliasing -D_GNU_SOURCE $(MACHDEP) $(INCLUDE) -D'GIT_COMMIT="$(shell git rev-parse --short HEAD)"' -D'GIT_REVISION="$(shell git rev-list HEAD | wc -l)"'
CXXFLAGS = $(CFLAGS)

ASFLAGS = $(MACHDEP) -mregnames -D_LANGUAGE_ASSEMBLY $(INCLUDE)
Expand Down
57 changes: 57 additions & 0 deletions cube/swiss/include/eltorito.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* eltorito.h
*
* Copyright (C) 2005-2006 The GameCube Linux Team
* Copyright (C) 2005,2006 Albert Herranz
* Copyright (C) 2020-2021 Extrems
*
* 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 2
* of the License, or (at your option) any later version.
*
*/

#ifndef __ELTORITO_H
#define __ELTORITO_H

#include <stdint.h>

#define DI_SECTOR_SIZE 2048

/*
* DVD data structures
*/

struct di_boot_record {
uint8_t zero;
uint8_t standard_id[5]; /* "CD001" */
uint8_t version; /* 1 */
uint8_t boot_system_id[32]; /* "EL TORITO SPECIFICATION" */
uint8_t boot_id[32];
uint32_t boot_catalog_offset; /* in media sectors */
uint8_t align_1[21];
} __attribute__ ((__packed__, __scalar_storage_order__ ("little-endian")));

struct di_validation_entry {
uint8_t header_id; /* 1 */
uint8_t platform_id; /* 0=80x86,1=PowerPC,2=Mac */
uint16_t reserved;
uint8_t id_string[24];
uint16_t checksum;
uint8_t key_55; /* 55 */
uint8_t key_AA; /* AA */
} __attribute__ ((__packed__, __scalar_storage_order__ ("little-endian")));

struct di_default_entry {
uint8_t boot_indicator; /* 0x88=bootable */
uint8_t boot_media_type; /* 0=no emulation */
uint16_t load_segment; /* multiply by 10 to get actual address */
uint8_t system_type;
uint8_t unused_1;
uint16_t sector_count; /* emulated sectors to load at segment */
uint32_t load_rba; /* in media sectors */
uint8_t unused_2[20];
} __attribute__ ((__packed__, __scalar_storage_order__ ("little-endian")));

#endif /* __ELTORITO_H */
40 changes: 36 additions & 4 deletions cube/swiss/source/gcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <xxhash.h>
#include "dvd.h"
#include "elf.h"
#include "eltorito.h"
#include "gcm.h"
#include "main.h"
#include "nkit.h"
Expand Down Expand Up @@ -213,6 +214,30 @@ u32 calc_elf_segments_size(file_handle *file, u32 file_offset, u32 *file_size) {
return size;
}

u32 get_iso_boot_record(file_handle *file) {
u32 file_offset = 17 * DI_SECTOR_SIZE;

struct di_boot_record boot_record;
devices[DEVICE_CUR]->seekFile(file, file_offset, DEVICE_HANDLER_SEEK_SET);
if(devices[DEVICE_CUR]->readFile(file, &boot_record, sizeof(boot_record)) != sizeof(boot_record)) return 0;
if(memcmp(boot_record.boot_system_id, "EL TORITO SPECIFICATION", 23)) return 0;
file_offset = boot_record.boot_catalog_offset * DI_SECTOR_SIZE;

struct di_validation_entry validation_entry;
devices[DEVICE_CUR]->seekFile(file, file_offset, DEVICE_HANDLER_SEEK_SET);
if(devices[DEVICE_CUR]->readFile(file, &validation_entry, sizeof(validation_entry)) != sizeof(validation_entry)) return 0;
if(validation_entry.header_id != 1 || validation_entry.key_55 != 0x55 || validation_entry.key_AA != 0xAA) return 0;
file_offset += sizeof(validation_entry);

struct di_default_entry default_entry;
devices[DEVICE_CUR]->seekFile(file, file_offset, DEVICE_HANDLER_SEEK_SET);
if(devices[DEVICE_CUR]->readFile(file, &default_entry, sizeof(default_entry)) != sizeof(default_entry)) return 0;
if(default_entry.boot_indicator != 0x88) return 0;
file_offset = default_entry.load_rba * DI_SECTOR_SIZE;

return file_offset;
}

// Returns the number of filesToPatch and fills out the filesToPatch array passed in (pre-allocated)
int parse_gcm(file_handle *file, file_handle *file2, ExecutableFile *filesToPatch) {
char filename[256];
Expand All @@ -239,10 +264,17 @@ int parse_gcm(file_handle *file, file_handle *file2, ExecutableFile *filesToPatc
sprintf(filesToPatch[numFiles].name, "apploader.img");
numFiles++;

if(diskHeader->DOLOffset != 0) {
dolOffset = diskHeader->DOLOffset;
if(dolOffset == 0 && diskHeader->FSTOffset + diskHeader->FSTSize <= 0x8000) {
dolOffset = get_iso_boot_record(file);
if(GCMDisk.DOLOffset == 0) {
GCMDisk.DOLOffset = dolOffset;
}
}
if(dolOffset != 0) {
if(is_datel_disc(diskHeader)) {
filesToPatch[numFiles].file = file;
filesToPatch[numFiles].offset = diskHeader->DOLOffset;
filesToPatch[numFiles].offset = dolOffset;
filesToPatch[numFiles].size = 0x400000;
filesToPatch[numFiles].hash = get_gcm_boot_hash(diskHeader, file->meta);
filesToPatch[numFiles].type = PATCH_BIN;
Expand All @@ -255,13 +287,13 @@ int parse_gcm(file_handle *file, file_handle *file2, ExecutableFile *filesToPatc
// Multi-DOL games may re-load the main DOL, so make sure we patch it too.
// Calc size
DOLHEADER dolhdr;
devices[DEVICE_CUR]->seekFile(file,diskHeader->DOLOffset,DEVICE_HANDLER_SEEK_SET);
devices[DEVICE_CUR]->seekFile(file,dolOffset,DEVICE_HANDLER_SEEK_SET);
if(devices[DEVICE_CUR]->readFile(file,&dolhdr,DOLHDRLENGTH) != DOLHDRLENGTH) {
DrawPublish(DrawMessageBox(D_FAIL, "Failed to read Main DOL Header"));
while(1);
}
filesToPatch[numFiles].file = file;
filesToPatch[numFiles].offset = dolOffset = diskHeader->DOLOffset;
filesToPatch[numFiles].offset = dolOffset;
filesToPatch[numFiles].size = dolSize = DOLSize(&dolhdr);
filesToPatch[numFiles].hash = get_gcm_boot_hash(diskHeader, file->meta);
filesToPatch[numFiles].type = PATCH_DOL;
Expand Down
15 changes: 11 additions & 4 deletions cube/swiss/source/swiss.c
Original file line number Diff line number Diff line change
Expand Up @@ -1011,6 +1011,8 @@ void load_app(ExecutableFile *fileToPatch)
void* buffer;
u32 sizeToRead;
int type;
char* argz = NULL;
size_t argz_len = 0;

// Get top of memory
u32 topAddr = getTopAddr();
Expand All @@ -1033,6 +1035,9 @@ void load_app(ExecutableFile *fileToPatch)
memcpy(VAR_AREA,(void*)&GCMDisk,0x20);

if(fileToPatch != NULL && fileToPatch->file != NULL) {
argz = getExternalPath(fileToPatch->file->name);
argz_len = strlen(argz) + 1;

// For a DOL from a TGC, redirect the FST to the TGC FST.
if(fileToPatch->tgcBase + fileToPatch->tgcFileStartArea != 0) {
// Read FST to top of Main Memory (round to 32 byte boundary)
Expand Down Expand Up @@ -1247,18 +1252,19 @@ void load_app(ExecutableFile *fileToPatch)
BINtoARAM(buffer, sizeToRead, 0x80003100, 0x80003100);
}
else if(type == PATCH_DOL || type == PATCH_DOL_PRS) {
DOLtoARAM(buffer, NULL, 0);
DOLtoARAM(buffer, argz, argz_len);
}
else if(type == PATCH_ELF) {
ELFtoARAM(buffer, NULL, 0);
ELFtoARAM(buffer, argz, argz_len);
}
SYS_ResetSystem(SYS_HOTRESET, 0, FALSE);
__builtin_unreachable();

fail:
free(buffer);
DrawDispose(progBox);
free(buffer);
fail_early:
free(argz);
if(message) {
uiDrawObj_t *msgBox = DrawPublish(DrawMessageBox(D_FAIL, message));
wait_press_A();
Expand Down Expand Up @@ -1413,10 +1419,11 @@ void boot_dol(file_handle* file, int argc, char *argv[])
else {
DOLtoARAM(buffer, argz, argz_len);
}
free(argz);
free(buffer);

devices[DEVICE_CUR]->closeFile(imageFile);
free(imageFile);
free(buffer);
}

/* Manage file - The user will be asked what they want to do with the currently selected file - copy/move/delete*/
Expand Down

0 comments on commit ec8d5aa

Please sign in to comment.