356 lines
No EOL
15 KiB
C
356 lines
No EOL
15 KiB
C
#include "dcc/dn_dcc_proto.h"
|
|
#include "dcc/plat.h"
|
|
#include "devices.h"
|
|
|
|
#ifdef CDEFS
|
|
const char CFLAGS[] = "C:DumpNow DCC Loader. (c) 2026 Wrapper.;Compile flags: " CDEFS ";Compile Date: " __DATE__;
|
|
#endif
|
|
|
|
static uint8_t read_buffer[DCC_BUFFER_SIZE + 0x4000];
|
|
#if !USE_BREAKPOINTS && !DISABLE_COMPRESS
|
|
static uint8_t compress_buffer[DCC_BUFFER_SIZE + 0x8000];
|
|
#endif
|
|
|
|
size_t strlen(const char *str);
|
|
|
|
static inline uint8_t dcc_send_data(uint8_t *data, uint32_t size, uint8_t algo) {
|
|
uint32_t dcc_comp_packet_size;
|
|
|
|
switch (algo) {
|
|
case CMD_READ_COMP_RLE:
|
|
#if !USE_BREAKPOINTS && !DISABLE_COMPRESS
|
|
dcc_comp_packet_size = DN_Packet_Compress(data, size, compress_buffer);
|
|
DN_Packet_Send(compress_buffer, dcc_comp_packet_size);
|
|
break;
|
|
#endif
|
|
|
|
case CMD_READ_COMP_NONE:
|
|
DN_Packet_Send_DirectUncompressed(data, ALIGN4(size));
|
|
break;
|
|
|
|
#if HAVE_LZ4 && !USE_BREAKPOINTS && !DISABLE_COMPRESS
|
|
case CMD_READ_COMP_LZ4:
|
|
dcc_comp_packet_size = DN_Packet_Compress2(data, size, compress_buffer);
|
|
DN_Packet_Send(compress_buffer, dcc_comp_packet_size);
|
|
break;
|
|
#endif
|
|
|
|
#if HAVE_ZLIB && !USE_BREAKPOINTS && !DISABLE_COMPRESS
|
|
case CMD_READ_COMP_ZLIB:
|
|
dcc_comp_packet_size = DN_Packet_Compress3(data, size, compress_buffer);
|
|
DN_Packet_Send(compress_buffer, dcc_comp_packet_size);
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
DN_Packet_Send_One(CMD_READ_RESP_FAIL(DCC_INVALID_ARGS));
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
#if DEBUG_PORT
|
|
static int DN_DebugPort_Out(int ch, lwprintf_t* lwp) {
|
|
if (ch != 0x00)
|
|
WRITE_U32(0x44444440, ch);
|
|
return ch;
|
|
}
|
|
#endif
|
|
|
|
// dcc code
|
|
void dcc_main(uint32_t StartAddress, uint32_t PageSize) {
|
|
DCCMemory dev_mem[16] = { 0 };
|
|
uint8_t mem_has_oob[16] = { 0 };
|
|
uint32_t dcc_init_buf[2048];
|
|
uint32_t dcc_init_offset = 0;
|
|
uint32_t temp_ext_mem;
|
|
DCC_RETURN res;
|
|
|
|
/* 00 - Init debug stuff */
|
|
#if DEBUG_PORT
|
|
lwprintf_init(DN_DebugPort_Out);
|
|
#endif
|
|
|
|
/* 01 - Probe flash devices */
|
|
PLAT_DBG_LOG("[DUMPNOW_DCC]: Begin initializing memory devices\n");
|
|
|
|
for (int i = 0; i < 16; i++) {
|
|
if (!devices[i].driver) break; // Break when reaching the end of list
|
|
|
|
/* Probe device */
|
|
res = devices[i].driver->initialize(&dev_mem[i], devices[i].base_offset, PageSize);
|
|
PLAT_DBG_LOG("[DUMPNOW_DCC]: Memory device %d initialization returned 0x%02x\n", i + 1, res);
|
|
|
|
if (res != DCC_OK)
|
|
dev_mem[i].type = MEMTYPE_NONE;
|
|
|
|
/* Print appropriate value */
|
|
switch (dev_mem[i].type) {
|
|
/* Anything without spare */
|
|
case MEMTYPE_NOR:
|
|
case MEMTYPE_SUPERAND:
|
|
temp_ext_mem = DCC_MEM_EXTENDED(1, dev_mem[i].page_size, dev_mem[i].block_size, dev_mem[i].size >> 20);
|
|
mem_has_oob[i] = 0;
|
|
|
|
/* Extended memory logic */
|
|
WRITE_EXTMEM:
|
|
/* Set name flag if memory name is defined */
|
|
if (strlen(dev_mem[i].name)) temp_ext_mem |= 0x80;
|
|
|
|
/* First device info */
|
|
dcc_init_buf[dcc_init_offset++] = DCC_MEM_OK | (temp_ext_mem << 16);
|
|
dcc_init_buf[dcc_init_offset++] = dev_mem[i].manufacturer | (dev_mem[i].device_id << 16);
|
|
|
|
/* Print additional information */
|
|
if (strlen(dev_mem[i].name)) {
|
|
int sLen = strlen(dev_mem[i].name);
|
|
uint8_t *dcc_init_buf_uint8 = (uint8_t *)dcc_init_buf;
|
|
|
|
/* 8-bit length then name (WORD aligned) */
|
|
dcc_init_buf[dcc_init_offset] = sLen;
|
|
memcpy(dcc_init_buf_uint8 + (dcc_init_offset << 2) + 1, dev_mem[i].name, sLen);
|
|
|
|
dcc_init_offset += ALIGN4(1 + sLen) >> 2;
|
|
}
|
|
|
|
/* Second device info */
|
|
dcc_init_buf[dcc_init_offset++] = temp_ext_mem;
|
|
break;
|
|
|
|
/* Regular NAND */
|
|
case MEMTYPE_NAND:
|
|
if (strlen(dev_mem[i].name)) goto NAND_EXTMEM; // Extended device info if we have additional information
|
|
|
|
/* Device info */
|
|
dcc_init_buf[dcc_init_offset++] = DCC_MEM_OK | (dev_mem[i].page_size << 16);
|
|
dcc_init_buf[dcc_init_offset++] = dev_mem[i].manufacturer | (dev_mem[i].device_id << 16);
|
|
mem_has_oob[i] = 1;
|
|
break;
|
|
|
|
/* Anything with spare */
|
|
case MEMTYPE_ONENAND:
|
|
case MEMTYPE_AND:
|
|
case MEMTYPE_AG_AND:
|
|
NAND_EXTMEM:
|
|
temp_ext_mem = DCC_MEM_EXTENDED(0, dev_mem[i].page_size, dev_mem[i].block_size, dev_mem[i].size >> 20);
|
|
mem_has_oob[i] = 1;
|
|
goto WRITE_EXTMEM;
|
|
|
|
/* When device probe fails, it goes here */
|
|
default:
|
|
dcc_init_buf[dcc_init_offset++] = DCC_MEM_OK | (DCC_MEM_NONE << 16);
|
|
dcc_init_buf[dcc_init_offset++] = dev_mem[i].probe_error_code;
|
|
mem_has_oob[i] = 0;
|
|
|
|
}
|
|
}
|
|
|
|
/* 02 - Print buffer size */
|
|
dcc_init_buf[dcc_init_offset++] = DCC_MEM_OK | (DCC_MEM_BUFFER(0) << 16);
|
|
dcc_init_buf[dcc_init_offset++] = DCC_BUFFER_SIZE;
|
|
|
|
DN_Packet_Send((uint8_t *)dcc_init_buf, dcc_init_offset << 2);
|
|
|
|
uint32_t flashDevID;
|
|
uint32_t dataOffset;
|
|
uint32_t dataSize;
|
|
uint32_t dataBlockSize;
|
|
uint32_t oobBlockSize;
|
|
|
|
/* 03 - The loop */
|
|
PLAT_DBG_LOG("[DUMPNOW_DCC]: Ready to accept commands\n");
|
|
|
|
while (1) {
|
|
wdog_reset();
|
|
uint32_t cmd = DN_Packet_DCC_Read();
|
|
|
|
switch (cmd & 0xff) {
|
|
/* Extended operation */
|
|
case CMD_EXTENDED:
|
|
for (int c = 0; c < (cmd >> 0x10); c += 4) {
|
|
DN_Packet_DCC_Read();
|
|
}
|
|
|
|
// TODO: Extended command support
|
|
DN_Packet_Send_One(CMD_WRITE_ERASE_STATUS(0x38, 0x6));
|
|
break;
|
|
|
|
/* Get devices information */
|
|
case CMD_GETINFO:
|
|
DN_Packet_Send((uint8_t *)dcc_init_buf, dcc_init_offset << 2);
|
|
break;
|
|
|
|
/* Get memory size */
|
|
case CMD_GETMEMSIZE:
|
|
flashDevID = (cmd >> 8) & 0xff;
|
|
if (flashDevID == 0) {
|
|
DN_Packet_Send_One(CMD_WRITE_ERASE_STATUS(0x21, 0));
|
|
} else if (flashDevID <= 0x10 && dev_mem[flashDevID - 1].type != MEMTYPE_NONE) {
|
|
DN_Packet_Send_One(CMD_WRITE_ERASE_STATUS(0x21, dev_mem[flashDevID - 1].size >> 20));
|
|
} else {
|
|
DN_Packet_Send_One(CMD_WRITE_ERASE_STATUS(DCC_FLASH_NOENT, flashDevID));
|
|
}
|
|
break;
|
|
|
|
/* Flash read */
|
|
case CMD_READ:
|
|
flashDevID = (cmd >> 8) & 0xff;
|
|
dataOffset = DN_Packet_DCC_Read();
|
|
dataSize = DN_Packet_DCC_Read();
|
|
uint8_t readCompAlgo = (cmd >> 24) & 0xff;
|
|
uint32_t readSize;
|
|
|
|
/* Check for read size not exceeding buffer */
|
|
if (dataSize > DCC_BUFFER_SIZE) {
|
|
DN_Packet_Send_One(CMD_READ_RESP_FAIL(DCC_INVALID_ARGS));
|
|
continue;
|
|
}
|
|
|
|
if (flashDevID == 0) { // Read from RAM
|
|
Jump_Read_NOR:
|
|
if (!dcc_send_data((uint8_t *)(dataOffset), dataSize, readCompAlgo))
|
|
continue;
|
|
|
|
} else if (flashDevID <= 0x10 && dev_mem[flashDevID - 1].type != MEMTYPE_NONE) {
|
|
switch (dev_mem[flashDevID - 1].type) {
|
|
case MEMTYPE_NAND:
|
|
case MEMTYPE_ONENAND:
|
|
case MEMTYPE_SUPERAND:
|
|
case MEMTYPE_AND:
|
|
case MEMTYPE_AG_AND:
|
|
/* Perform driver read routines */
|
|
res = devices[flashDevID - 1].driver->read(&dev_mem[flashDevID - 1], dataOffset, dataSize, read_buffer, &readSize);
|
|
if (res != DCC_OK) { // Check if error
|
|
DN_Packet_Send_One(CMD_READ_RESP_FAIL(res));
|
|
continue;
|
|
}
|
|
|
|
/* Compression */
|
|
if (!dcc_send_data(read_buffer, readSize, readCompAlgo))
|
|
continue;
|
|
|
|
break;
|
|
case MEMTYPE_NOR:
|
|
default:
|
|
/* NOR reads directly */
|
|
dataOffset &= (dev_mem[flashDevID - 1].size - 1);
|
|
dataOffset += dev_mem[flashDevID - 1].base_offset;
|
|
goto Jump_Read_NOR;
|
|
}
|
|
} else {
|
|
/* No flash found */
|
|
DN_Packet_Send_One(CMD_READ_RESP_FAIL(DCC_FLASH_NOENT));
|
|
}
|
|
|
|
break;
|
|
|
|
/* Flash erase */
|
|
case CMD_ERASE:
|
|
flashDevID = (cmd >> 8) & 0xff;
|
|
dataOffset = DN_Packet_DCC_Read();
|
|
dataSize = DN_Packet_DCC_Read();
|
|
dataBlockSize = dev_mem[flashDevID - 1].block_size;
|
|
|
|
if (flashDevID == 0) flashDevID = 1;
|
|
|
|
if (flashDevID <= 0x10 && dev_mem[flashDevID - 1].type != MEMTYPE_NONE) {
|
|
if (((dataOffset % dataBlockSize) != 0) || ((dataSize % dataBlockSize) != 0)) {
|
|
DN_Packet_Send_One(CMD_WRITE_ERASE_STATUS(DCC_INVALID_ARGS, flashDevID));
|
|
continue;
|
|
}
|
|
|
|
if (devices[flashDevID - 1].driver->erase) {
|
|
res = devices[flashDevID - 1].driver->erase(&dev_mem[flashDevID - 1], dataOffset, dataSize);
|
|
DN_Packet_Send_One(CMD_WRITE_ERASE_STATUS(res, flashDevID));
|
|
} else {
|
|
DN_Packet_Send_One(CMD_WRITE_ERASE_STATUS(DCC_ROFS_ERROR, flashDevID));
|
|
}
|
|
} else {
|
|
DN_Packet_Send_One(CMD_WRITE_ERASE_STATUS(DCC_FLASH_NOENT, flashDevID));
|
|
}
|
|
break;
|
|
|
|
/* Flash write */
|
|
case CMD_WRITE:
|
|
flashDevID = (cmd >> 16) & 0xff;
|
|
dataOffset = DN_Packet_DCC_Read();
|
|
dataBlockSize = dev_mem[flashDevID - 1].block_size;
|
|
oobBlockSize = mem_has_oob[flashDevID - 1] ? (dev_mem[flashDevID - 1].block_size >> 5) : 0;
|
|
|
|
DecompressContext decompCtx;
|
|
uint32_t writeCompAlgo = DN_Packet_DCC_Read();
|
|
uint8_t writeDataType = (cmd >> 8) & 0x7f;
|
|
uint8_t writeUseECC = (cmd >> 8) & 0x80;
|
|
uint32_t crcDataComputed = 0xffffffff;
|
|
uint32_t writeDataBufOffset = 0;
|
|
|
|
if (flashDevID == 0) flashDevID = 1;
|
|
|
|
if (flashDevID <= 0x10 && dev_mem[flashDevID - 1].type != MEMTYPE_NONE) {
|
|
if ((dataOffset % dataBlockSize) != 0) {
|
|
DN_Packet_Send_One(CMD_WRITE_ERASE_STATUS(DCC_INVALID_ARGS, flashDevID));
|
|
continue;
|
|
}
|
|
|
|
switch (writeCompAlgo) {
|
|
case CMD_WRITE_COMP_NONE:
|
|
if (writeDataType & 2) { // Data
|
|
DN_Packet_Read(read_buffer + writeDataBufOffset, dataBlockSize);
|
|
crcDataComputed = DN_Calculate_CRC32(crcDataComputed, read_buffer + writeDataBufOffset, dataBlockSize);
|
|
writeDataBufOffset += dataBlockSize;
|
|
}
|
|
if ((writeDataType & 1) && oobBlockSize > 0) { // OOB
|
|
DN_Packet_Read(read_buffer + writeDataBufOffset, oobBlockSize);
|
|
crcDataComputed = DN_Calculate_CRC32(crcDataComputed, read_buffer + writeDataBufOffset, oobBlockSize);
|
|
writeDataBufOffset += oobBlockSize;
|
|
}
|
|
break;
|
|
|
|
case CMD_WRITE_COMP_RLE:
|
|
dataSize = DN_Packet_DCC_Read();
|
|
DN_Packet_Reader_Init(&decompCtx, read_buffer, dataSize);
|
|
while (decompCtx.decomp_data_size > 0) {
|
|
DN_Packet_Reader_Process(&decompCtx, DN_Packet_DCC_Read());
|
|
}
|
|
|
|
if (decompCtx.out_buffer_offset < (dataBlockSize + oobBlockSize)) {
|
|
DN_Packet_Send_One(DCC_E_UNDERRUN(decompCtx.out_buffer_offset));
|
|
continue;
|
|
}
|
|
|
|
crcDataComputed = DN_Calculate_CRC32(crcDataComputed, read_buffer, dataSize);
|
|
break;
|
|
|
|
default:
|
|
DN_Packet_Send_One(CMD_WRITE_ERASE_STATUS(DCC_CHECKSUM_ERROR, flashDevID));
|
|
continue;
|
|
}
|
|
|
|
uint32_t checksum = DN_Packet_DCC_Read();
|
|
|
|
if (checksum != crcDataComputed) {
|
|
DN_Packet_Send_One(CMD_WRITE_ERASE_STATUS(DCC_CHECKSUM_ERROR, flashDevID));
|
|
continue;
|
|
}
|
|
|
|
if (devices[flashDevID - 1].driver->configure)
|
|
devices[flashDevID - 1].driver->configure(&dev_mem[flashDevID - 1], CONFIG_ECC, writeUseECC);
|
|
|
|
if (devices[flashDevID - 1].driver->write) {
|
|
res = devices[flashDevID - 1].driver->write(&dev_mem[flashDevID - 1], dataOffset, read_buffer, dataBlockSize);
|
|
DN_Packet_Send_One(CMD_WRITE_ERASE_STATUS(res, flashDevID));
|
|
} else {
|
|
DN_Packet_Send_One(CMD_WRITE_ERASE_STATUS(DCC_ROFS_ERROR, flashDevID));
|
|
}
|
|
} else {
|
|
DN_Packet_Send_One(CMD_WRITE_ERASE_STATUS(DCC_FLASH_NOENT, flashDevID));
|
|
}
|
|
break;
|
|
|
|
/* Catch-all for unknown commands */
|
|
default:
|
|
DN_Packet_Send_One(DCC_BAD_COMMAND(cmd & 0xff));
|
|
}
|
|
}
|
|
} |