Skip to content

Commit

Permalink
Merge pull request #919 from bsmiles32/mpk_uid
Browse files Browse the repository at this point in the history
Generate unique mempaks ID when formatting them
  • Loading branch information
richard42 committed Apr 12, 2022
2 parents 73ce3d0 + b2da87b commit 014b2ab
Show file tree
Hide file tree
Showing 5 changed files with 351 additions and 44 deletions.
154 changes: 112 additions & 42 deletions src/device/controllers/paks/mempak.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,61 +23,131 @@

#include "backends/api/storage_backend.h"
#include "device/controllers/game_controller.h"
#include "main/util.h"

#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>

/* 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)
{
enum { MPK_PAGE_SIZE = 256 };
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 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
};

/* Fill Page 0 with pre-initialized content */
memcpy(mem, page_0, MPK_PAGE_SIZE);

/* Fill INODE page 1 and update it's checkum */
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 };

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;

/* 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);

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);
}


Expand Down
10 changes: 9 additions & 1 deletion src/device/controllers/paks/mempak.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,
Expand Down
20 changes: 19 additions & 1 deletion src/main/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,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
*/
Expand Down Expand Up @@ -1013,7 +1016,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);
}
}
}
Expand Down Expand Up @@ -1470,6 +1485,9 @@ m64p_error main_run(void)
break;
}

/* Seed MPK ID gen using current time */
l_mpk_idgen = xoshiro256pp_seed((uint64_t)time(NULL));

/* take the r4300 emulator mode from the config file at this point and cache it in a global variable */
emumode = ConfigGetParamInt(g_CoreConfig, "R4300Emulator");

Expand Down
Loading

0 comments on commit 014b2ab

Please sign in to comment.