├── spl.bin ├── usbboot ├── uboot.bin ├── uboot.png ├── Makefile ├── README.md └── usbboot.c /spl.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballaswag/ingenic-usbboot/HEAD/spl.bin -------------------------------------------------------------------------------- /usbboot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballaswag/ingenic-usbboot/HEAD/usbboot -------------------------------------------------------------------------------- /uboot.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballaswag/ingenic-usbboot/HEAD/uboot.bin -------------------------------------------------------------------------------- /uboot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballaswag/ingenic-usbboot/HEAD/uboot.png -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | DEFINES= 2 | CC?=gcc 3 | CFLAGS=-g -std=c99 -Wall $(DEFINES) `pkg-config --cflags libusb-1.0` 4 | LDFLAGS=`pkg-config --libs libusb-1.0` 5 | SRC=$(wildcard *.c) 6 | EXEC=$(SRC:.c=) 7 | 8 | all: $(EXEC) 9 | 10 | %: %.c 11 | $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) 12 | 13 | clean: 14 | rm -fr $(EXEC) 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Creality K1 (X2000E) usbboot tool 2 | ## Building 3 | 4 | `make` 5 | 6 | ## Running 7 | To see console output, a USB to TTL adapter is needed. For the Creality K1 board, the serial pinout is by the reset/boot botton. 8 | 9 | To Enter USB Boot mode for the K1, hold the boot button, while holding boot hold down reset, let go reset then boot. 10 | 11 | ```$ sudo ./usbboot --uboot``` 12 | 13 | ## Unbricking Creality K1 Mainboard (USE AT YOUR OWN RISK) 14 | 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. 15 | 16 | ``` 17 | $ sudo ./usbboot --uboot 18 | $ sudo ./usbboot --swap-ota 19 | Current OTA points at kernel. Switching OTA to kernel2 20 | Switched OTA to ota:kernel2 21 | 22 | $ sudo ./usbboot --swap-ota 23 | Current OTA points at kernel2. Switching OTA to kernel 24 | Switched OTA to ota:kernel 25 | 26 | ``` 27 | 28 | ## Dumping Partitions 29 | Use this to dump your existing partitions in the K1. Example K1 partition table. 30 | ``` 31 | uboot(gpt/uboot): Offset 0x000000000, Length 0x0000100000 32 | ota: Offset 0x000100000, Length 0x0000100000 33 | sn_mac: Offset 0x000200000, Length 0x0000100000 34 | rtos: Offset 0x000300000, Length 0x0000400000 35 | rtos2: Offset 0x000700000, Length 0x0000400000 36 | kernel: Offset 0x000b00000, Length 0x0000800000 37 | kernel2: Offset 0x001300000, Length 0x0000800000 38 | rootfs: Offset 0x001b00000, Length 0x0012c00000 39 | rootfs2: Offset 0x014700000, Length 0x0012c00000 40 | rootfs_data: Offset 0x027300000, Length 0x0006400000 41 | userdata: Offset 0x02d700000, Length 0x01a4a00000 42 | 43 | Total disk size:0x00000001d2104200, sectors:0x0000000000e90821 44 | ``` 45 | 46 | ``` 47 | ## start uboot 48 | $ sudo ./usbboot --uboot 49 | 50 | ## dump the kernel partition to file ./kernel.out 51 | $ sudo ./usbboot -o 0x000b00000 -s 0x0000800000 --dump-partition ./kernel.out 52 | dumping parition at offset 0xb00000, size 0x800000 53 | 25.00% completed (1.00MB/s) 54 | 50.00% completed (1.00MB/s) 55 | 75.00% completed (1.00MB/s) 56 | 100.00% completed (1.00MB/s) 57 | 58 | ## dump the rootfs partition to ./rootfs.out 59 | $ sudo ./usbboot -o 0x001b00000 -s 0x0012c00000 --dump-partition ./rootfs.out 60 | dumping parition at offset 0x1b00000, size 0x12c00000 61 | 0.67% completed (0.67MB/s) 62 | 1.33% completed (1.00MB/s) 63 | 2.00% completed (1.00MB/s) 64 | ... 65 | ``` 66 | 67 | ## SPL/u-boot 68 | 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. 69 | 70 | The bootrom sets the stack pointer at 0xb2401000 (TCSM/SRAM), this is referenced as the `CONFIG_SPL_TEXT_BASE` in various Ingenic uboot configurations for the x2000 series. In USB mode, it allows reading and writing to memory regions over vendor defined requests (see usbboot source code for reference). The SPL in this repository has a specific format, the first 384 bytes define things such as cpu frequency, ddr frequency, uart port, and etc. This is important because the SPL code needs these to initialize the hardware. If this part is missing, the board will reboot when executing the SPL. The SPL code starts at 0xb2401800. 71 | 72 | Once SPL completes, the DRAM is initialized. At this point, uboot can be loaded into DRAM and executed at 0x80100000, this is referenced `CONFIG_SYS_TEXT_BASE` in the u-boot configurations. 73 | 74 | Also note that UARTs and such are also initialized via the SPL and not the uboot. If you're having issue where serial consoles are not working and pins are not behaving as you expect, make sure to check that the SPL is configured and builtin properly. 75 | 76 | ![k1 uboot](https://github.com/ballaswag/ingenic-usbboot/blob/main/uboot.png) 77 | -------------------------------------------------------------------------------- /usbboot.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * __________ __ ___. 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 | * \/ \/ \/ \/ \/ 8 | * $Id$ 9 | * 10 | * Copyright (C) 2021 Aidan MacDonald 11 | * 12 | * Directly adapted from jz4760_tools/usbboot.c, 13 | * Copyright (C) 2015 by Amaury Pouly 14 | * 15 | * This program is free software; you can redistribute it and/or 16 | * modify it under the terms of the GNU General Public License 17 | * as published by the Free Software Foundation; either version 2 18 | * of the License, or (at your option) any later version. 19 | * 20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 21 | * KIND, either express or implied. 22 | * 23 | ****************************************************************************/ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #define VR_GET_CPU_INFO 0 35 | #define VR_SET_DATA_ADDRESS 1 36 | #define VR_SET_DATA_LENGTH 2 37 | #define VR_FLUSH_CACHES 3 38 | #define VR_PROGRAM_START1 4 39 | #define VR_PROGRAM_START2 5 40 | #define VR_GET_ACK 0x10 41 | #define VR_INIT 0x11 42 | #define VR_WRITE 0x12 43 | #define VR_READ 0x13 44 | #define VR_UPDATE_CFG 0x14 45 | 46 | #define MAGIC_DEBUG ('D' << 24) | ('B' << 16) | ('G' << 8) | 0 47 | #define MAGIC_MMC ('M' << 24) | ('M' << 16) | ('C' << 8) | 0 48 | #define MAGIC_POLICY ('P' << 24) | ('O' << 16) | ('L' << 8) | ('I' << 0) 49 | 50 | typedef struct ParameterInfo { 51 | uint32_t magic; 52 | uint32_t size; 53 | uint32_t data[0]; 54 | } ParameterInfo; 55 | 56 | struct mmc_erase_range { 57 | uint32_t start; 58 | uint32_t end; 59 | }; 60 | 61 | typedef struct mmc_param { 62 | int mmc_open_card; 63 | int mmc_erase; 64 | uint32_t mmc_erase_range_count; 65 | uint32_t blob[59]; // don't care, not formatting 66 | } mmc_param; 67 | 68 | typedef struct debug_param { 69 | uint32_t log_enabled; 70 | uint32_t transfer_data_chk; 71 | uint32_t write_back_chk; 72 | uint32_t transfer_size; 73 | uint32_t stage2_timeout; 74 | } debug_param; 75 | 76 | typedef struct policy_param { 77 | int use_nand_mgr; 78 | int use_nand_mtd; 79 | int use_mmc0; 80 | int use_mmc1; 81 | int use_mmc2; 82 | uint32_t use_sfc_nor; 83 | uint32_t use_sfc_nand; 84 | uint32_t use_spi_nand; 85 | uint32_t use_spi_nor; 86 | uint32_t offsets[32]; 87 | } policy_param;; 88 | 89 | 90 | // burner commands 91 | typedef struct update_cmd { 92 | uint32_t length; 93 | uint32_t unused[9]; // pad to 40 bytes 94 | } UpdateCmd; 95 | 96 | typedef struct write_cmd { 97 | uint64_t partition; 98 | uint32_t ops; 99 | uint32_t offset; 100 | uint32_t length; 101 | uint32_t crc; 102 | uint32_t unused[4]; 103 | } WriteCmd; 104 | 105 | typedef struct read_cmd { 106 | uint64_t partition; 107 | uint32_t ops; 108 | uint32_t offset; 109 | uint32_t length; 110 | uint32_t unused[5]; 111 | } ReadCmd; 112 | 113 | 114 | /* Global variables */ 115 | bool g_verbose = false; 116 | libusb_device_handle* g_usb_dev = NULL; 117 | int g_vid = 0, g_pid = 0; 118 | 119 | /* Utility functions */ 120 | void die(const char* msg, ...) 121 | { 122 | va_list ap; 123 | va_start(ap, msg); 124 | vfprintf(stderr, msg, ap); 125 | fprintf(stderr, "\n"); 126 | va_end(ap); 127 | exit(1); 128 | } 129 | 130 | void verbose(const char* msg, ...) 131 | { 132 | if(!g_verbose) 133 | return; 134 | 135 | va_list ap; 136 | va_start(ap, msg); 137 | vprintf(msg, ap); 138 | printf("\n"); 139 | va_end(ap); 140 | } 141 | 142 | void open_usb(void) 143 | { 144 | if(g_usb_dev) { 145 | verbose("Closing USB device"); 146 | libusb_close(g_usb_dev); 147 | } 148 | 149 | if(g_vid == 0 || g_pid == 0) 150 | die("Can't open USB device: vendor/product ID not specified"); 151 | 152 | verbose("Opening USB device %04x:%04x", g_vid, g_pid); 153 | g_usb_dev = libusb_open_device_with_vid_pid(NULL, g_vid, g_pid); 154 | if(!g_usb_dev) 155 | die("Could not open USB device"); 156 | 157 | int ret = libusb_claim_interface(g_usb_dev, 0); 158 | if(ret != 0) { 159 | libusb_close(g_usb_dev); 160 | die("Could not claim interface: %d", ret); 161 | } 162 | } 163 | 164 | void ensure_usb(void) 165 | { 166 | if(!g_usb_dev) 167 | open_usb(); 168 | } 169 | 170 | /* USB communication functions */ 171 | void jz_get_cpu_info(void) 172 | { 173 | ensure_usb(); 174 | verbose("Issue GET_CPU_INFO"); 175 | 176 | uint8_t buf[9]; 177 | int ret = libusb_control_transfer(g_usb_dev, 178 | LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 179 | VR_GET_CPU_INFO, 0, 0, buf, 8, 1000); 180 | if(ret != 0) 181 | die("Can't get CPU info: %d", ret); 182 | 183 | buf[8] = 0; 184 | printf("CPU info: %s\n", buf); 185 | } 186 | 187 | void jz_upload(const char* filename, int length) 188 | { 189 | if(length < 0) 190 | die("invalid upload length: %d", length); 191 | 192 | ensure_usb(); 193 | verbose("Transfer %d bytes from device to host", length); 194 | 195 | void* data = malloc(length); 196 | int xfered = 0; 197 | int ret = libusb_bulk_transfer(g_usb_dev, LIBUSB_ENDPOINT_IN | 1, 198 | data, length, &xfered, 10000); 199 | if(ret != 0) 200 | die("Transfer failed: %d", ret); 201 | if(xfered != length) 202 | die("Transfer error: got %d bytes, expected %d", xfered, length); 203 | 204 | FILE* f = fopen(filename, "wb"); 205 | if(f == NULL) 206 | die("Can't open file '%s' for writing", filename); 207 | 208 | if(fwrite(data, length, 1, f) != 1) 209 | die("Error writing transfered data to file"); 210 | 211 | fclose(f); 212 | free(data); 213 | } 214 | 215 | void bulk_transfer_out(void* data, int length) { 216 | verbose("Transfer %d bytes from host to device", length); 217 | int xfered = 0; 218 | int ret = libusb_bulk_transfer(g_usb_dev, LIBUSB_ENDPOINT_OUT | 1, 219 | data, length, &xfered, 10000); 220 | if(ret != 0) 221 | die("Transfer failed: %d", ret); 222 | if(xfered != length) 223 | die("Transfer error: %d bytes recieved, expected %d", xfered, length); 224 | } 225 | 226 | #define jz_vendor_out_func(name, type, fmt) \ 227 | void name(unsigned long param) { \ 228 | ensure_usb(); \ 229 | verbose("Issue " #type fmt, param); \ 230 | int ret = libusb_control_transfer(g_usb_dev, \ 231 | LIBUSB_ENDPOINT_OUT|LIBUSB_REQUEST_TYPE_VENDOR|LIBUSB_RECIPIENT_DEVICE, \ 232 | VR_##type, param >> 16, param & 0xffff, NULL, 0, 1000); \ 233 | if(ret != 0) \ 234 | die("Request " #type " failed: %d", ret); \ 235 | } 236 | 237 | jz_vendor_out_func(jz_set_data_address, SET_DATA_ADDRESS, " 0x%08lx") 238 | jz_vendor_out_func(jz_set_data_length, SET_DATA_LENGTH, " 0x%0lx") 239 | jz_vendor_out_func(_jz_flush_caches, FLUSH_CACHES, "") 240 | jz_vendor_out_func(jz_program_start1, PROGRAM_START1, " 0x%08lx") 241 | jz_vendor_out_func(jz_program_start2, PROGRAM_START2, " 0x%08lx") 242 | jz_vendor_out_func(jz_init, INIT, " 0x%08lx") 243 | #define jz_flush_caches() _jz_flush_caches(0) 244 | 245 | void jz_generic_out(uint8_t op, 246 | unsigned long param, 247 | unsigned char *data, 248 | uint16_t len) { 249 | ensure_usb(); 250 | verbose("Issue 0x%x", op); 251 | int ret = libusb_control_transfer(g_usb_dev, 252 | LIBUSB_ENDPOINT_OUT|LIBUSB_REQUEST_TYPE_VENDOR|LIBUSB_RECIPIENT_DEVICE, 253 | op, param >> 16, param & 0xffff, data, len, 1000); 254 | if(ret != len) 255 | die("Request 0x%x failed, only transfered: %d", op, ret); 256 | } 257 | 258 | void jz_download(const char* filename) 259 | { 260 | FILE* f = fopen(filename, "rb"); 261 | if(f == NULL) 262 | die("Can't open file '%s' for reading", filename); 263 | 264 | fseek(f, 0, SEEK_END); 265 | int length = ftell(f); 266 | fseek(f, 0, SEEK_SET); 267 | 268 | void* data = malloc(length); 269 | if(fread(data, length, 1, f) != 1) 270 | die("Error reading data from file"); 271 | fclose(f); 272 | 273 | jz_set_data_length(length); 274 | bulk_transfer_out(data, length); 275 | 276 | free(data); 277 | } 278 | 279 | void jz_get_ack() { 280 | ensure_usb(); 281 | verbose("Issue VR_GET_ACK"); 282 | 283 | uint8_t buf[4]; 284 | int ret = libusb_control_transfer(g_usb_dev, 285 | LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 286 | VR_GET_ACK, 0, 0, buf, 4, 1000); 287 | if(ret != 4) 288 | die("Can't get ACK: %d", ret); 289 | } 290 | 291 | void enable_mmc() { 292 | ensure_usb(); 293 | 294 | ParameterInfo *policy_param_info = (ParameterInfo*) malloc(sizeof(ParameterInfo) + sizeof(policy_param)); 295 | policy_param_info->magic = MAGIC_POLICY; 296 | policy_param_info->size = sizeof(policy_param); 297 | memset(policy_param_info->data, 0, sizeof(policy_param)); 298 | policy_param *policy_cfg = (policy_param*)policy_param_info->data; 299 | policy_cfg->use_mmc0 = 1; 300 | 301 | ParameterInfo *dbg_param_info = (ParameterInfo*) malloc(sizeof(ParameterInfo) + sizeof(debug_param)); 302 | dbg_param_info->magic = MAGIC_DEBUG; 303 | dbg_param_info->size = sizeof(debug_param); 304 | debug_param *dbg = (debug_param*)dbg_param_info->data; 305 | dbg->log_enabled = 1; 306 | dbg->transfer_data_chk = 0; 307 | dbg->write_back_chk = 0; 308 | dbg->transfer_size = 0; 309 | dbg->stage2_timeout = 0; 310 | 311 | ParameterInfo *mmc_param_info = (ParameterInfo*) malloc(sizeof(ParameterInfo) + sizeof(mmc_param)); 312 | mmc_param_info->magic = MAGIC_MMC; 313 | mmc_param_info->size = sizeof(mmc_param); 314 | memset(mmc_param_info->data, 0, sizeof(mmc_param)); 315 | 316 | uint32_t data_size = 3 * 8 + policy_param_info->size + dbg_param_info->size + mmc_param_info->size; 317 | unsigned char data[data_size]; 318 | unsigned char *p = data; 319 | uint32_t offset = 0; 320 | memcpy(p + offset, dbg_param_info, 4 + 4 + dbg_param_info->size); 321 | offset += 4 + 4 + dbg_param_info->size; 322 | memcpy(p + offset, mmc_param_info, 4 + 4 + mmc_param_info->size); 323 | offset += 4 + 4 + mmc_param_info->size; 324 | memcpy(p + offset, policy_param_info, 4 + 4 + policy_param_info->size); 325 | 326 | UpdateCmd *update = (UpdateCmd*) malloc(sizeof(UpdateCmd)); 327 | memset(update, 0, sizeof(UpdateCmd)); 328 | update->length = data_size; 329 | 330 | jz_generic_out(VR_UPDATE_CFG, 0, (unsigned char*)update, sizeof(UpdateCmd)); 331 | 332 | bulk_transfer_out(p, data_size); 333 | 334 | free(policy_param_info); 335 | free(dbg_param_info); 336 | free(mmc_param_info); 337 | free(update); 338 | 339 | jz_get_ack(); 340 | jz_init(0); 341 | jz_get_ack(); 342 | } 343 | 344 | void mmc_read(uint32_t offset, uint32_t length, unsigned char* out) { 345 | ReadCmd *read = (ReadCmd*) malloc(sizeof(ReadCmd)); 346 | memset(read, 0, sizeof(ReadCmd)); 347 | read->ops = 0x020000; // mmc 348 | read->offset = offset; 349 | read->length = length; 350 | 351 | jz_generic_out(VR_READ, 0, (unsigned char*)read, sizeof(ReadCmd)); 352 | free(read); 353 | 354 | while (1) { 355 | int xfered = 0; 356 | int ret = libusb_bulk_transfer(g_usb_dev, LIBUSB_ENDPOINT_IN | 1, 357 | out, length, &xfered, 10000); 358 | if(ret != 0) 359 | die("OTA read failed: %d", ret); 360 | 361 | if(xfered == length) 362 | break; 363 | } 364 | } 365 | 366 | void mmc_read_partition(uint32_t offset, uint32_t length, const char* fname) { 367 | enable_mmc(); 368 | if(length == 0) 369 | die("invalid partition length: %d", length); 370 | 371 | printf("dumping parition at offset 0x%x, size 0x%x\n", offset, length); 372 | 373 | uint32_t chunk_size = 1024 * 1024 * 2; // 2mb 374 | unsigned char chunk[chunk_size]; 375 | 376 | FILE* f = fopen(fname, "wb"); 377 | if(f == NULL) 378 | die("Can't open file '%s' for writing", fname); 379 | 380 | uint32_t cursor = offset; 381 | uint32_t end = offset + length; 382 | while (cursor < end) { 383 | uint32_t read_size = (end - cursor) >= chunk_size 384 | ? chunk_size 385 | : (end - cursor); 386 | 387 | uint32_t start = (uint32_t)time(NULL); 388 | mmc_read(cursor, read_size, chunk); 389 | uint32_t duration = (uint32_t)time(NULL) - start; 390 | 391 | cursor += read_size; 392 | 393 | printf("%.2f%% completed (%.2fMB/s)\n", 394 | (cursor - offset) / (float)length * 100, 395 | (read_size / 1024 / 1024) / (float)duration); 396 | 397 | if (fwrite(chunk, read_size, 1, f) != 1) 398 | die("Failed to write data to %x", fname); 399 | } 400 | 401 | fclose(f); 402 | } 403 | 404 | void mmc_write(uint32_t offset, uint32_t length, unsigned char* in) { 405 | WriteCmd *write = (WriteCmd*) malloc(sizeof(WriteCmd)); 406 | memset(write, 0, sizeof(WriteCmd)); 407 | write->ops = 0x020000; // mmc 408 | write->offset = offset; 409 | write->length = length; 410 | 411 | jz_generic_out(VR_WRITE, 0, (unsigned char*)write, sizeof(WriteCmd)); 412 | free(write); 413 | 414 | bulk_transfer_out(in, length); 415 | } 416 | 417 | void swap_ota_partition(bool force) { 418 | ensure_usb(); 419 | enable_mmc(); 420 | 421 | uint32_t ota_len = 512; 422 | unsigned char ota[ota_len]; 423 | 424 | mmc_read(0x100000, ota_len, ota); 425 | 426 | char ota_in[ota_len]; 427 | memset(ota_in, 0, ota_len); 428 | 429 | if (strncmp((char*)ota, "ota:kernel2", 11) == 0) { 430 | printf("Current OTA points at kernel2. Switching OTA to kernel\n"); 431 | strcpy(ota_in, "ota:kernel\n\n"); 432 | } else if (strncmp((char*)ota, "ota:kernel\n", 11) == 0) { 433 | printf("Current OTA points at kernel. Switching OTA to kernel2\n"); 434 | strcpy(ota_in, "ota:kernel2\n\n"); 435 | } else { 436 | if (!force) { 437 | die("Exiting! Your OTA contains unexpected values, swapping OTA might not fix your issue."); 438 | } 439 | 440 | printf("Unknown value in OTA. Forcing OTA to use ota:kernel\n"); 441 | strcpy(ota_in, "ota:kernel\n\n"); 442 | } 443 | 444 | mmc_write(0x100000, ota_len, (unsigned char*)ota_in); 445 | printf("Switched OTA to %s", ota_in); 446 | } 447 | 448 | /* Default settings */ 449 | struct cpu_profile { 450 | const char* name; 451 | int vid, pid; 452 | unsigned long s1_load_addr, s1_exec_addr; 453 | unsigned long s2_load_addr, s2_exec_addr; 454 | }; 455 | 456 | static const struct cpu_profile cpu_profiles[] = { 457 | {"x2000", 458 | 0xa108, 0xeaef, 459 | 0xb2401000, 0xb2401800, 460 | 0x80100000, 0x80100000}, 461 | {NULL} 462 | }; 463 | 464 | /* Simple "download and run" functions for dev purposes */ 465 | unsigned long s1_load_addr = 0, s1_exec_addr = 0; 466 | unsigned long s2_load_addr = 0, s2_exec_addr = 0; 467 | 468 | void apply_cpu_profile(const char* name) 469 | { 470 | const struct cpu_profile* p = &cpu_profiles[0]; 471 | for(p = &cpu_profiles[0]; p->name != NULL; ++p) { 472 | if(strcmp(p->name, name) != 0) 473 | continue; 474 | 475 | g_vid = p->vid; 476 | g_pid = p->pid; 477 | s1_load_addr = p->s1_load_addr; 478 | s1_exec_addr = p->s1_exec_addr; 479 | s2_load_addr = p->s2_load_addr; 480 | s2_exec_addr = p->s2_exec_addr; 481 | return; 482 | } 483 | 484 | die("CPU '%s' not known", name); 485 | } 486 | 487 | void run_stage1(const char* filename) 488 | { 489 | if(s1_load_addr == 0 || s1_exec_addr == 0) 490 | die("No stage1 binary settings -- did you specify --cpu?"); 491 | jz_set_data_address(s1_load_addr); 492 | jz_download(filename); 493 | jz_program_start1(s1_exec_addr); 494 | } 495 | 496 | void run_stage2(const char* filename) 497 | { 498 | if(s2_load_addr == 0 || s2_exec_addr == 0) 499 | die("No stage2 binary settings -- did you specify --cpu?"); 500 | jz_set_data_address(s2_load_addr); 501 | jz_download(filename); 502 | jz_flush_caches(); 503 | jz_program_start2(s2_exec_addr); 504 | } 505 | 506 | void start_x2000_uboot() { 507 | run_stage1("./spl.bin"); 508 | sleep(1); 509 | run_stage2("./uboot.bin"); 510 | } 511 | 512 | /* Main functions */ 513 | void usage() 514 | { 515 | printf("\ 516 | Usage: usbboot [options]\n\ 517 | \n\ 518 | Basic options:\n\ 519 | --uboot Start uboot\n\ 520 | --cpu Select device CPU type\n\ 521 | --stage1 Download and execute stage1 binary\n\ 522 | --stage2 Download and execute stage2 binary\n\ 523 | \n\ 524 | Advanced options:\n\ 525 | --vid Specify USB vendor ID\n\ 526 | --pid Specify USB product ID\n\ 527 | --swap-ota Switch OTA between kernel/kernel2\n\ 528 | --force-swap-ota Ignore unknown OTA value, write ota:kernel to OTA\n\ 529 | --cpuinfo Ask device for CPU info\n\ 530 | --addr Set data address\n\ 531 | --length Set data length\n\ 532 | --upload Transfer data from device (needs prior --length)\n\ 533 | --download Transfer data to device\n\ 534 | --start1 Execute stage1 code at address\n\ 535 | --start2 Execute stage2 code at address\n\ 536 | --flush-caches Flush device CPU caches\n\ 537 | --renumerate Close and re-open the USB device\n\ 538 | --wait