Add option to dump partitions from the creality k1/max

This commit is contained in:
ballaswag
2023-09-26 23:15:12 -07:00
parent 1bfdf69b1e
commit 5d5a1234fe
3 changed files with 110 additions and 7 deletions
+41 -2
View File
@@ -1,4 +1,4 @@
# ingenic-usbboot
# Creality K1 (X2000E) usbboot tool
## Building
`make`
@@ -12,7 +12,7 @@ To Enter USB Boot mode for the K1, hold the boot button, while holding boot hold
BIG caveat, I haven't gotten keyboard input to work through serial, I can only see the uboot logs. Please reach out if you figure out how to get keyboard input over serial for uboot.
## Unbricking Creality K1 Mainboard
## Unbricking Creality K1 Mainboard (USE AT YOUR OWN RISK)
The Creality K1 comes with a set of backup partitions. The OTA partition stores either the string `ota:kernel` or `ota:kernel2` to indicate which set of partitions to boot. This tool allows you to quickly switch between the two. This should fix a bricked Creality K1 mainboard given the backup partitions are functional. For cases where the partition table, main, and backup partitions are corrupted, read through this [guide](https://github.com/ballaswag/k1-discovery/blob/main/k1-ingenic-cloner-instruction.pdf) for a better chance of recoverying the mainboad.
```
@@ -27,6 +27,45 @@ Switched OTA to ota:kernel
```
## Dumping Partitions
Use this to dump your existing partitions in the K1. Example K1 partition table.
```
uboot(gpt/uboot): Offset 0x000000000, Length 0x0000100000
ota: Offset 0x000100000, Length 0x0000100000
sn_mac: Offset 0x000200000, Length 0x0000100000
rtos: Offset 0x000300000, Length 0x0000400000
rtos2: Offset 0x000700000, Length 0x0000400000
kernel: Offset 0x000b00000, Length 0x0000800000
kernel2: Offset 0x001300000, Length 0x0000800000
rootfs: Offset 0x001b00000, Length 0x0012c00000
rootfs2: Offset 0x014700000, Length 0x0012c00000
rootfs_data: Offset 0x027300000, Length 0x0006400000
userdata: Offset 0x02d700000, Length 0x01a4a00000
Total disk size:0x00000001d2104200, sectors:0x0000000000e90821
```
```
## start uboot
$ sudo ./usbboot --uboot
## dump the kernel partition to file ./kernel.out
$ sudo ./usbboot -o 0x000b00000 -s 0x0000800000 --dump-partition ./kernel.out
dumping parition at offset 0xb00000, size 0x800000
25.00% completed (1.00MB/s)
50.00% completed (1.00MB/s)
75.00% completed (1.00MB/s)
100.00% completed (1.00MB/s)
## dump the rootfs partition to ./rootfs.out
$ sudo ./usbboot -o 0x001b00000 -s 0x0012c00000 --dump-partition ./rootfs.out
dumping parition at offset 0x1b00000, size 0x12c00000
0.67% completed (0.67MB/s)
1.33% completed (1.00MB/s)
2.00% completed (1.00MB/s)
...
```
## SPL/u-boot
The general idea is to write and execute loader codes at different memory spaces during the different stages of boot. SPL is a smaller piece of code that lives in TCSM/SRAM and executed to initialize DRAM. Then the bigger uboot code can be loaded and executed from DRAM.
BIN
View File
Binary file not shown.
+68 -4
View File
@@ -363,6 +363,44 @@ void mmc_read(uint32_t offset, uint32_t length, unsigned char* out) {
}
}
void mmc_read_partition(uint32_t offset, uint32_t length, const char* fname) {
enable_mmc();
if(length == 0)
die("invalid partition length: %d", length);
printf("dumping parition at offset 0x%x, size 0x%x\n", offset, length);
uint32_t chunk_size = 1024 * 1024 * 2; // 2mb
unsigned char chunk[chunk_size];
FILE* f = fopen(fname, "wb");
if(f == NULL)
die("Can't open file '%s' for writing", fname);
uint32_t cursor = offset;
uint32_t end = offset + length;
while (cursor < end) {
uint32_t read_size = (end - cursor) >= chunk_size
? chunk_size
: (end - cursor);
uint32_t start = (uint32_t)time(NULL);
mmc_read(cursor, read_size, chunk);
uint32_t duration = (uint32_t)time(NULL) - start;
cursor += read_size;
printf("%.2f%% completed (%.2fMB/s)\n",
(cursor - offset) / (float)length * 100,
(read_size / 1024 / 1024) / (float)duration);
if (fwrite(chunk, read_size, 1, f) != 1)
die("Failed to write data to %x", fname);
}
fclose(f);
}
void mmc_write(uint32_t offset, uint32_t length, unsigned char* in) {
WriteCmd *write = (WriteCmd*) malloc(sizeof(WriteCmd));
memset(write, 0, sizeof(WriteCmd));
@@ -536,7 +574,7 @@ int main(int argc, char* argv[])
OPT_CPUINFO,
OPT_START1, OPT_START2, OPT_FLUSH_CACHES,
OPT_RENUMERATE, OPT_WAIT, OPT_SWAP_OTA,
OPT_FORCE_SWAP_OTA
OPT_FORCE_SWAP_OTA, OPT_DUMP_PARITION
};
static const struct option long_options[] = {
@@ -549,6 +587,8 @@ int main(int argc, char* argv[])
{"cpuinfo", no_argument, 0, OPT_CPUINFO},
{"addr", required_argument, 0, 'a'},
{"length", required_argument, 0, 'l'},
{"partition-size", required_argument, 0, 's'},
{"partition-offset", required_argument, 0, 'o'},
{"upload", required_argument, 0, 'u'},
{"download", required_argument, 0, 'd'},
{"start1", required_argument, 0, OPT_START1},
@@ -558,6 +598,7 @@ int main(int argc, char* argv[])
{"wait", required_argument, 0, OPT_WAIT},
{"swap-ota", no_argument, 0, OPT_SWAP_OTA},
{"force-swap-ota", no_argument, 0, OPT_FORCE_SWAP_OTA},
{"dump-partition", required_argument, 0, OPT_DUMP_PARITION},
{"help", no_argument, 0, 'h'},
{"verbose", no_argument, 0, 'v'},
{0, 0, 0, 0}
@@ -565,7 +606,9 @@ int main(int argc, char* argv[])
int opt;
int data_length = -1;
while((opt = getopt_long(argc, argv, "bhvc:1:2:a:l:u:d:", long_options, NULL)) != -1) {
uint32_t partition_offset = 0;
uint32_t partition_size = 0;
while((opt = getopt_long(argc, argv, "bhvc:1:2:a:l:s:o:u:d:", long_options, NULL)) != -1) {
unsigned long param;
char* end;
switch(opt) {
@@ -579,7 +622,18 @@ int main(int argc, char* argv[])
param = strtoul(optarg, &end, 0);
if(*end)
die("Invalid argument '%s'", optarg);
break;
case 's':
partition_size = strtoul(optarg, &end, 0);
if(*end)
die("Invalid argument '%s'", optarg);
break;
case 'o':
partition_offset = strtoul(optarg, &end, 0);
if(*end)
die("Invalid argument '%s'", optarg);
break;
default:
break;
}
@@ -651,10 +705,20 @@ int main(int argc, char* argv[])
verbose("Force OTA to boot ota:kernel");
swap_ota_partition(true);
break;
case OPT_DUMP_PARITION:
if (partition_size <= 0)
die("must provide a positive partition length with option --partition-size");
verbose("Dump a partition to file");
mmc_read_partition(partition_offset, partition_size, optarg);
break;
case 'o':
case 's':
break;
default:
/* should only happen due to a bug */
die("Bad option");
break;
die("Bad option");
break;
}
}