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 ## Building
`make` `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. 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. 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 ## 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. 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.
+69 -5
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) { void mmc_write(uint32_t offset, uint32_t length, unsigned char* in) {
WriteCmd *write = (WriteCmd*) malloc(sizeof(WriteCmd)); WriteCmd *write = (WriteCmd*) malloc(sizeof(WriteCmd));
memset(write, 0, sizeof(WriteCmd)); memset(write, 0, sizeof(WriteCmd));
@@ -536,7 +574,7 @@ int main(int argc, char* argv[])
OPT_CPUINFO, OPT_CPUINFO,
OPT_START1, OPT_START2, OPT_FLUSH_CACHES, OPT_START1, OPT_START2, OPT_FLUSH_CACHES,
OPT_RENUMERATE, OPT_WAIT, OPT_SWAP_OTA, OPT_RENUMERATE, OPT_WAIT, OPT_SWAP_OTA,
OPT_FORCE_SWAP_OTA OPT_FORCE_SWAP_OTA, OPT_DUMP_PARITION
}; };
static const struct option long_options[] = { static const struct option long_options[] = {
@@ -549,6 +587,8 @@ int main(int argc, char* argv[])
{"cpuinfo", no_argument, 0, OPT_CPUINFO}, {"cpuinfo", no_argument, 0, OPT_CPUINFO},
{"addr", required_argument, 0, 'a'}, {"addr", required_argument, 0, 'a'},
{"length", required_argument, 0, 'l'}, {"length", required_argument, 0, 'l'},
{"partition-size", required_argument, 0, 's'},
{"partition-offset", required_argument, 0, 'o'},
{"upload", required_argument, 0, 'u'}, {"upload", required_argument, 0, 'u'},
{"download", required_argument, 0, 'd'}, {"download", required_argument, 0, 'd'},
{"start1", required_argument, 0, OPT_START1}, {"start1", required_argument, 0, OPT_START1},
@@ -557,7 +597,8 @@ int main(int argc, char* argv[])
{"renumerate", no_argument, 0, OPT_RENUMERATE}, {"renumerate", no_argument, 0, OPT_RENUMERATE},
{"wait", required_argument, 0, OPT_WAIT}, {"wait", required_argument, 0, OPT_WAIT},
{"swap-ota", no_argument, 0, OPT_SWAP_OTA}, {"swap-ota", no_argument, 0, OPT_SWAP_OTA},
{"force-swap-ota", no_argument, 0, OPT_FORCE_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'}, {"help", no_argument, 0, 'h'},
{"verbose", no_argument, 0, 'v'}, {"verbose", no_argument, 0, 'v'},
{0, 0, 0, 0} {0, 0, 0, 0}
@@ -565,7 +606,9 @@ int main(int argc, char* argv[])
int opt; int opt;
int data_length = -1; 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; unsigned long param;
char* end; char* end;
switch(opt) { switch(opt) {
@@ -579,7 +622,18 @@ int main(int argc, char* argv[])
param = strtoul(optarg, &end, 0); param = strtoul(optarg, &end, 0);
if(*end) if(*end)
die("Invalid argument '%s'", optarg); die("Invalid argument '%s'", optarg);
break; 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: default:
break; break;
} }
@@ -651,10 +705,20 @@ int main(int argc, char* argv[])
verbose("Force OTA to boot ota:kernel"); verbose("Force OTA to boot ota:kernel");
swap_ota_partition(true); swap_ota_partition(true);
break; 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: default:
/* should only happen due to a bug */ /* should only happen due to a bug */
die("Bad option"); die("Bad option");
break; break;
} }
} }