Add option to dump partitions from the creality k1/max
This commit is contained in:
@@ -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.
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user