main.c
#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <errno.h> #include <getopt.h> #include <unistd.h> #include <libusb-1.0/libusb.h> #define TIMEOUT_MS 5000 #define STAGE1_LOAD_ADDR 0x80000000 #define STAGE2_LOAD_ADDR 0x81000000 #define ARRAY_SIZE(x) (sizeof(x) ? sizeof(x) / sizeof((x)[0]) : 0) enum commands { VR_GET_CPU_INFO = 0, VR_SET_DATA_ADDR, VR_SET_DATA_LEN, VR_FLUSH_CACHES, VR_START1, VR_START2, }; static unsigned int stage1_load_addr = STAGE1_LOAD_ADDR; static unsigned int stage2_load_addr = STAGE2_LOAD_ADDR; static FILE *stage1 = NULL; static FILE *stage2 = NULL; static FILE *devicetree = NULL; static int cmd_get_info(libusb_device_handle *hdl) { int ret = 0; unsigned char info[8] = {0}; ret = libusb_control_transfer(hdl, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, VR_GET_CPU_INFO, 0, 0, info, sizeof(info), TIMEOUT_MS); if (ret != sizeof(info)) { return -EIO; } return 0; } static int cmd_control(libusb_device_handle *hdl, uint32_t cmd, uint32_t attr) { return libusb_control_transfer(hdl, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, cmd, (attr >> 16) & 0xffff, attr & 0xffff, NULL, 0, TIMEOUT_MS); } static int cmd_load_data(libusb_device_handle *hdl, FILE *f, uint32_t addr, size_t *data_size) { int ret = 0; int bytes_transferred = 0; size_t size = 0, to_read = 0, to_write = 0; unsigned char *data = NULL; char *ptr = NULL; fseek(f, 0, SEEK_END); size = ftell(f); fseek(f, 0, SEEK_SET); if (data_size) { *data_size = size; } data = malloc(size); if (!data) { return -ENOMEM; } ptr = (char *)data; to_read = size; do { size_t bytes_read = fread(ptr, 1, to_read, f); if (!bytes_read) { ret = -EIO; goto out_free; } ptr += bytes_read; to_read -= bytes_read; } while (to_read > 0); ret = cmd_control(hdl, VR_SET_DATA_LEN, size); if (ret) { goto out_free; } ret = cmd_control(hdl, VR_SET_DATA_ADDR, addr); if (ret) { goto out_free; } ptr = (char *)data; to_write = size; do { ret = libusb_bulk_transfer(hdl, LIBUSB_ENDPOINT_OUT | 1, ptr, (int)to_write, &bytes_transferred, TIMEOUT_MS); if (ret) { goto out_free; } to_write -= bytes_transferred; ptr += bytes_transferred; } while (to_write > 0); printf("Uploaded %lu bytes at address 0x%08x\n", size, addr); out_free: free(data); return ret; } int main(int argc, char **argv) { char *end = NULL; int ret = 0, c = 0; size_t kernel_size = 0; unsigned int i = 0, j = 0; libusb_context *usb_ctx = NULL; libusb_device_handle *hdl = NULL; if (argc == 1) { printf("usage: %s stage1 stage2 devicetree\n", argv[0]); return -1; } stage1 = fopen(argv[1], "rb"); if (!stage1) { printf("Failed to open %s file\n", argv[1]); goto Err; } if (argc > 2) { stage2 = fopen(argv[2], "rb"); } if (argc > 3) { devicetree = fopen(argv[3], "rb"); } ret = libusb_init(&usb_ctx); if (ret) { printf("Failed to init libusb\n"); goto Err; } hdl = libusb_open_device_with_vid_pid(usb_ctx, 0xa108, 0xc309); if (!hdl) { printf("Failed to open GKD Pixel\n"); goto Err; } ret = libusb_claim_interface(hdl, 0); if (ret) { printf("Failed to claim interface 0\n"); goto Err; } if (cmd_get_info(hdl)) { printf("Failed to read CPU info\n"); goto Err; } printf("Found GKD Pixel\n"); ret = cmd_load_data(hdl, stage1, stage1_load_addr, NULL); if (ret) { printf("Failed to upload stage1 file\n"); goto Err; } ret = cmd_control(hdl, VR_START1, stage1_load_addr); if (ret) { printf("Failed to execute stage1 bootloader\n"); goto Err; } printf("Run stage1 at 0x%08x\n", stage1_load_addr); if (!stage2) { goto Err; } printf("Waiting for stage1 bootloader to complete operation...\n"); for (i = 0; i < 100; i++) { if (!cmd_get_info(hdl)) { break; } usleep(10000); } if (i == 100) { printf("Stage1 bootloader did not return\n"); goto Err; } ret = cmd_load_data(hdl, stage2, stage2_load_addr, &kernel_size); if (ret) { printf("Failed to upload stage2 program\n"); goto Err; } if (devicetree) { ret = cmd_load_data(hdl, devicetree, stage2_load_addr + kernel_size, NULL); if (ret) { printf("Failed to upload devicetree\n"); goto Err; } } ret = cmd_control(hdl, VR_FLUSH_CACHES, 0); if (ret) { printf("Failed to flush caches\n"); goto Err; } ret = cmd_control(hdl, VR_START2, stage2_load_addr); if (ret) { printf("Failed to execute program\n"); goto Err; } printf("Run stage2 at 0x%08x\n", stage1_load_addr); Err: if (hdl) { libusb_close(hdl); } if (usb_ctx) { libusb_exit(usb_ctx); } if (stage1) { fclose(stage1); } if (stage2) { fclose(stage2); } if (devicetree) { fclose(devicetree); } return 0; }