Improved CIC detection algorithm

Now it incorporates the same algorithm as is included in the N64 IPL2. IPL3 that have checksum collision are now correctly detected.
This commit is contained in:
Mateusz Faderewski 2023-12-07 00:36:16 +01:00
parent cfe4f01e30
commit 8e50e4c1e1
4 changed files with 118 additions and 94 deletions

View File

@ -17,7 +17,6 @@ SRCS = \
main.c \
boot/boot.c \
boot/cic.c \
boot/crc32.c \
boot/reboot.S \
flashcart/64drive/64drive_ll.c \
flashcart/64drive/64drive.c \

View File

@ -1,36 +1,129 @@
#include "cic.h"
#include "crc32.h"
typedef struct {
const uint32_t crc32;
const cic_type_t type;
} ipl3_crc32_t;
static inline uint32_t _get (uint8_t *p, int index) {
int i = index * 4;
return (p[i] << 24 | p[i + 1] << 16 | p[i + 2] << 8 | p[i + 3]);
}
static const ipl3_crc32_t ipl3_crc32[] = {
{ .crc32 = 0x587BD543, .type = CIC_5101 },
{ .crc32 = 0x0E018159, .type = CIC_5167 },
{ .crc32 = 0x6170A4A1, .type = CIC_6101 },
{ .crc32 = 0x009E9EA3, .type = CIC_7102 },
{ .crc32 = 0x90BB6CB5, .type = CIC_6102_7101 },
{ .crc32 = 0x0B050EE0, .type = CIC_x103 },
{ .crc32 = 0x98BC2C86, .type = CIC_x105 },
{ .crc32 = 0xACC8580A, .type = CIC_x106 },
{ .crc32 = 0xBC605D0A, .type = CIC_8301 },
{ .crc32 = 0x502C4466, .type = CIC_8302 },
{ .crc32 = 0x0C965795, .type = CIC_8303 },
{ .crc32 = 0x10C68B18, .type = CIC_8401 },
{ .crc32 = 0x8FEBA21E, .type = CIC_8501 },
static inline uint32_t _add (uint32_t a1, uint32_t a2) {
return a1 + a2;
}
static inline uint32_t _sub (uint32_t a1, uint32_t a2) {
return a1 - a2;
}
static inline uint32_t _mul (uint32_t a1, uint32_t a2) {
return a1 * a2;
}
static inline uint32_t _rol (uint32_t a, uint32_t s) {
return ((a) << (s)) | ((a) >> (-(s) & 31));
}
static inline uint32_t _ror (uint32_t a, uint32_t s) {
return ((a) >> (s)) | ((a) << (-(s) & 31));
}
static uint32_t _sum (uint32_t a0, uint32_t a1, uint32_t a2) {
uint64_t prod = ((uint64_t) (a0)) * (a1 == 0 ? a2 : a1);
uint32_t hi = (prod >> 32) & 0xFFFFFFFF;
uint32_t lo = prod & 0xFFFFFFFF;
uint32_t diff = hi - lo;
return (diff == 0) ? a0 : diff;
};
static uint64_t cic_calculate_ipl3_checksum (uint8_t *ipl3, uint8_t seed) {
const uint32_t MAGIC = 0x6C078965;
uint32_t data, prev, next;
data = prev = next = _get(ipl3, 0);
uint32_t init = _add(_mul(MAGIC, seed), 1) ^ data;
uint32_t buf[16];
for (int i = 0; i < 16; i++) {
buf[i] = init;
}
for (int i = 1; i <= 1008; i++) {
prev = data;
data = next;
buf[0] = _add(buf[0], _sum(_sub(1007, i), data, i));
buf[1] = _sum(buf[1], data, i);
buf[2] = buf[2] ^ data;
buf[3] = _add(buf[3], _sum(_add(data, 5), MAGIC, i));
buf[4] = _add(buf[4], _ror(data, prev & 0x1F));
buf[5] = _add(buf[5], _rol(data, prev >> 27));
buf[6] = (data < buf[6]) ? (_add(buf[3], buf[6]) ^ _add(data, i)) : (_add(buf[4], data) ^ buf[6]);
buf[7] = _sum(buf[7], _rol(data, prev & 0x1F), i);
buf[8] = _sum(buf[8], _ror(data, prev >> 27), i);
buf[9] = (prev < data) ? _sum(buf[9], data, i) : _add(buf[9], data);
if (i == 1008) {
break;
}
next = _get(ipl3, i);
buf[10] = _sum(_add(buf[10], data), next, i);
buf[11] = _sum(buf[11] ^ data, next, i);
buf[12] = _add(buf[12], buf[8] ^ data);
buf[13] = _add(buf[13], _add(_ror(data, data & 0x1F), _ror(next, next & 0x1F)));
buf[14] = _sum(_sum(buf[14], _ror(data, prev & 0x1F), i), _ror(next, data & 0x1F), i);
buf[15] = _sum(_sum(buf[15], _rol(data, prev >> 27), i), _rol(next, data >> 27), i);
}
uint32_t final_buf[4];
for (int i = 0; i < 4; i++) {
final_buf[i] = buf[0];
}
for (int i = 0; i < 16; i++) {
uint32_t data = buf[i];
final_buf[0] = _add(final_buf[0], _ror(data, data & 0x1F));
final_buf[1] = (data < final_buf[0]) ? _add(final_buf[1], data) : _sum(final_buf[1], data, i);
final_buf[2] = (((data & 0x02) >> 1) == (data & 0x01)) ? _add(final_buf[2], data) : _sum(final_buf[2], data, i);
final_buf[3] = ((data & 0x01) == 0x01) ? (final_buf[3] ^ data) : _sum(final_buf[3], data, i);
}
uint32_t final_sum = _sum(final_buf[0], final_buf[1], 16);
uint32_t final_xor = final_buf[3] ^ final_buf[2];
uint64_t checksum = (((((uint64_t) (final_sum)) & 0xFFFF)) << 32) | (final_xor);
return checksum;
}
cic_type_t cic_detect (uint8_t *ipl3) {
uint32_t crc32 = crc32_calculate(ipl3, IPL3_LENGTH);
for (int i = 0; i < sizeof(ipl3_crc32) / sizeof(ipl3_crc32_t); i++) {
if (ipl3_crc32[i].crc32 == crc32) {
return ipl3_crc32[i].type;
}
switch (cic_calculate_ipl3_checksum(ipl3, 0x3F)) {
case 0x45CC73EE317AULL: return CIC_6101; // 6101
case 0x44160EC5D9AFULL: return CIC_7102; // 7102
case 0xA536C0F1D859ULL: return CIC_6102_7101; // 6102 / 7101
}
switch (cic_calculate_ipl3_checksum(ipl3, 0x78)) {
case 0x586FD4709867ULL: return CIC_x103; // 6103 / 7103
}
switch (cic_calculate_ipl3_checksum(ipl3, 0x85)) {
case 0x2BBAD4E6EB74ULL: return CIC_x106; // 6106 / 7106
}
switch (cic_calculate_ipl3_checksum(ipl3, 0x91)) {
case 0x8618A45BC2D3ULL: return CIC_x105; // 6105 / 7105
}
switch (cic_calculate_ipl3_checksum(ipl3, 0xAC)) {
case 0x5930D81014DAULL: return CIC_5101; // Aleck 64
}
switch (cic_calculate_ipl3_checksum(ipl3, 0xDD)) {
case 0x6EE8D9E84970ULL: return CIC_8401; // NDXJ0
case 0x6C216495C8B9ULL: return CIC_8301; // NDDJ0
case 0xE27F43BA93ACULL: return CIC_8302; // NDDJ1
case 0x32B294E2AB90ULL: return CIC_8303; // NDDJ2
case 0x083C6C77E0B1ULL: return CIC_5167; // 64DD Cartridge conversion
}
switch (cic_calculate_ipl3_checksum(ipl3, 0xDE)) {
case 0x05BA2EF0A5F1ULL: return CIC_8501; // NDDE0
}
return CIC_UNKNOWN;

View File

@ -1,50 +0,0 @@
#include "crc32.h"
static const uint32_t crc32_table[256] = {
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
};
uint32_t crc32_calculate (void *buffer, size_t length) {
uint32_t crc32 = 0xFFFFFFFFUL;
uint8_t *byte_pointer = (uint8_t *) (buffer);
while (length--) {
crc32 = (crc32 >> 8) ^ crc32_table[(crc32 & 0xFF) ^ (*byte_pointer++)];
}
return ~(crc32);
}

View File

@ -1,18 +0,0 @@
/**
* @file crc32.h
* @brief Flashcart Boot Checksum
* @ingroup boot
*/
#ifndef CRC32_H__
#define CRC32_H__
#include <stddef.h>
#include <stdint.h>
uint32_t crc32_calculate (void *buffer, size_t length);
#endif