unscramble bootfile of CD-ROM XA discs during HLE bootstrap

This commit is contained in:
Anthony Pesch 2017-12-02 15:45:13 -05:00
parent b7cb524c02
commit c618cd595c
5 changed files with 100 additions and 2 deletions

View File

@ -207,6 +207,7 @@ set(RELIB_SOURCES
src/guest/arm7/arm7.c
src/guest/bios/bios.c
src/guest/bios/flash.c
src/guest/bios/scramble.c
src/guest/bios/syscalls.c
src/guest/gdrom/cdi.c
src/guest/gdrom/chd.c

View File

@ -4,6 +4,7 @@
#include "guest/aica/aica.h"
#include "guest/bios/bios.h"
#include "guest/bios/flash.h"
#include "guest/bios/scramble.h"
#include "guest/bios/syscalls.h"
#include "guest/dreamcast.h"
#include "guest/gdrom/gdrom.h"
@ -285,6 +286,18 @@ void bios_boot(struct bios *bios) {
return;
}
/* CD-ROM XA discs have their binary scrambled. the bios descrambles this
later on in the boot, but it should be fine to descramble now */
struct gd_status_info stat;
gdrom_get_status(gd, &stat);
if (stat.format == GD_DISC_CDROM_XA) {
uint8_t *tmp2 = malloc(len);
descramble(tmp2, tmp, len);
free(tmp);
tmp = tmp2;
}
sh4_memcpy_to_guest(dc->mem, BOOT2_ADDR, tmp, read);
free(tmp);
}
@ -319,7 +332,7 @@ void bios_boot(struct bios *bios) {
sh4_write32(dc->mem, VECTOR_SYSTEM, SYSCALL_SYSTEM);
}
/* start executing at license screen code inside of ip.bin */
/* start executing at license screen code inside of IP.BIN */
ctx->pc = 0xac008300;
}

72
src/guest/bios/scramble.c Normal file
View File

@ -0,0 +1,72 @@
#include "guest/bios/scramble.h"
#include "core/core.h"
#define MIN_CHUNK_SIZE 32
#define MAX_CHUNK_SIZE (2048 * 1024)
#define MAX_SLICES (MAX_CHUNK_SIZE / MIN_CHUNK_SIZE)
static int scramble_init(int n) {
return n & 0xffff;
}
static int scramble_next(int *seed, int i) {
unsigned key;
*seed = (*seed * 2109 + 9273) & 0x7fff;
key = (*seed + 0xc000) & 0xffff;
return ((unsigned)i * (unsigned)key) >> 16;
}
static void descramble_chunk(int *seed, uint8_t *dst, const uint8_t *src,
int size) {
CHECK((size % MIN_CHUNK_SIZE) == 0 && size <= MAX_CHUNK_SIZE);
/* descramble each chunk in MIN_CHUNK_SIZE slices */
size /= MIN_CHUNK_SIZE;
/* lookup table maps scrambled slice index to descrambled index */
int table[MAX_SLICES];
for (int i = 0; i < size; i++) {
table[i] = i;
}
for (int i = size - 1; i >= 0; i--) {
int x = scramble_next(seed, i);
/* swap table index */
int tmp = table[i];
table[i] = table[x];
table[x] = tmp;
/* write slice out to descrambled index */
memcpy(dst + MIN_CHUNK_SIZE * table[i], src, MIN_CHUNK_SIZE);
src += MIN_CHUNK_SIZE;
}
}
void descramble(uint8_t *dst, const uint8_t *src, int size) {
int seed = scramble_init(size);
/* descramble the data starting with the largest chunk size (2mb) */
int chunk_size = MAX_CHUNK_SIZE;
while (chunk_size >= MIN_CHUNK_SIZE) {
/* continue descrambling with the current chunk size until the remaining
data is too small */
while (size >= chunk_size) {
descramble_chunk(&seed, dst, src, chunk_size);
size -= chunk_size;
dst += chunk_size;
src += chunk_size;
}
/* attempt to use the the next smallest chunk size */
chunk_size >>= 1;
}
/* any remaining data isn't scrambled, just copy it */
if (size) {
memcpy(dst, src, size);
}
}

View File

@ -0,0 +1,8 @@
#ifndef SCRAMBLE_H
#define SCRAMBLE_H
#include <stdint.h>
void descramble(uint8_t *dst, const uint8_t *src, int size);
#endif

View File

@ -1,6 +1,7 @@
#include "guest/bios/syscalls.h"
#include "guest/bios/bios.h"
#include "guest/bios/flash.h"
#include "guest/bios/scramble.h"
#include "guest/gdrom/gdrom.h"
#include "guest/holly/holly.h"
#include "guest/memory.h"
@ -29,6 +30,7 @@ enum {
void bios_system_vector(struct bios *bios) {
struct dreamcast *dc = bios->dc;
struct gdrom *gd = dc->gdrom;
struct sh4_context *ctx = &dc->sh4->ctx;
uint32_t fn = ctx->r[4];
@ -138,6 +140,7 @@ static uint32_t bios_gdrom_send_cmd(struct bios *bios, uint32_t cmd_code,
static void bios_gdrom_mainloop(struct bios *bios) {
struct dreamcast *dc = bios->dc;
struct gdrom *gd = dc->gdrom;
struct holly *hl = dc->holly;
if (bios->status != GDC_STATUS_ACTIVE) {
return;
@ -265,7 +268,8 @@ static void bios_gdrom_mainloop(struct bios *bios) {
} break;
case GDC_INIT: {
/* this seems to always immediately follow GDROM_INIT */
/* sanity check in case dma transfers are made async in the future */
CHECK_EQ(*hl->SB_GDST, 0);
} break;
case GDC_SEEK: {