summaryrefslogtreecommitdiffstats
path: root/utils
diff options
context:
space:
mode:
Diffstat (limited to 'utils')
-rw-r--r--utils/rk27utils/README37
-rw-r--r--utils/rk27utils/rk27load/Makefile7
-rw-r--r--utils/rk27utils/rk27load/checksum.c35
-rw-r--r--utils/rk27utils/rk27load/checksum.h1
-rw-r--r--utils/rk27utils/rk27load/common.c16
-rw-r--r--utils/rk27utils/rk27load/common.h1
-rw-r--r--utils/rk27utils/rk27load/main.c165
-rw-r--r--utils/rk27utils/rk27load/rk27load.h11
-rw-r--r--utils/rk27utils/rk27load/scramble.c46
-rw-r--r--utils/rk27utils/rk27load/scramble.h1
-rw-r--r--utils/rk27utils/rk27load/stage1/Makefile48
-rw-r--r--utils/rk27utils/rk27load/stage1/main.S42
-rw-r--r--utils/rk27utils/rk27load/stage1/stage1.lds23
-rw-r--r--utils/rk27utils/rk27load/stage1_upload.c113
-rw-r--r--utils/rk27utils/rk27load/stage1_upload.h3
-rw-r--r--utils/rk27utils/rk27load/stage2/Makefile48
-rw-r--r--utils/rk27utils/rk27load/stage2/crt0.S55
-rw-r--r--utils/rk27utils/rk27load/stage2/irq.S103
-rw-r--r--utils/rk27utils/rk27load/stage2/main.S89
-rw-r--r--utils/rk27utils/rk27load/stage2/stage2.lds40
-rw-r--r--utils/rk27utils/rk27load/stage2_upload.c102
-rw-r--r--utils/rk27utils/rk27load/stage2_upload.h3
-rw-r--r--utils/rk27utils/rk27load/stage3_upload.c93
-rw-r--r--utils/rk27utils/rk27load/stage3_upload.h1
-rw-r--r--utils/rk27utils/rkboottool/Makefile7
-rw-r--r--utils/rk27utils/rkboottool/rkboottool.c360
-rw-r--r--utils/rk27utils/rkusbtool/Makefile7
-rw-r--r--utils/rk27utils/rkusbtool/rkusbtool.c388
28 files changed, 1845 insertions, 0 deletions
diff --git a/utils/rk27utils/README b/utils/rk27utils/README
new file mode 100644
index 0000000000..a43d69a88f
--- /dev/null
+++ b/utils/rk27utils/README
@@ -0,0 +1,37 @@
+This is the collection of small utilities needed to hack Rockchip rk27xx
+series based DAPs. This tools were tested on linux only.
+
+
+rk27load
+This directory contains tool which can send arbitrary image(s) to the device
+in rockchip recovery mode (VID:PID 0x071B:0x3201).
+
+The first image can not exceed 510 bytes (+2 bytes checksum) and entry
+point is 0x18020e00. Usually this code is used to configure SDRAM controller.
+One can use first stage image extracted from Rock27Boot.bin file (a bit
+more sofisticated) or the one provided in rk27load/stage1 directory.
+
+The second image is loaded at the begining of the dram (0x60000000)
+and executed. For some reason (which is still unclear) the size of
+2nd stage image is limited to about 3-4 kB.
+
+You can find example of custom 2nd stage image in rk27load/stage2 directory.
+The purpose of this image is to configure bulk transfer and allow to
+load usercode without size restriction mentioned above (the max size
+is 8MB actually). The entry point of usercode is 0x60000000.
+
+You need libusb 1.0 + header files in order to compile this utility.
+You need working arm-eabi crosscompiler in order to compile stage1/stage2
+bootloader binaries (but You should have one already if You tinker whith this)
+
+
+rkboottool
+This directory contains tool which allows to extract (and decrypt) images
+stored in Rock27Boot.bin recovery file.
+
+
+rkusbtool
+This directory contains tool which sends custom scsi commands to the
+rockchip player.
+
+You need libusb-1.0 + header files in order to compile this utility.
diff --git a/utils/rk27utils/rk27load/Makefile b/utils/rk27utils/rk27load/Makefile
new file mode 100644
index 0000000000..f777e76c36
--- /dev/null
+++ b/utils/rk27utils/rk27load/Makefile
@@ -0,0 +1,7 @@
+all: rk27load
+
+rk27load: main.c scramble.c checksum.c common.c stage1_upload.c stage2_upload.c stage3_upload.c
+ gcc -g -std=c99 -o $@ -W -Wall -lusb-1.0 -I/usr/include/libusb-1.0/ $^
+
+clean:
+ rm -fr *.o rk27load
diff --git a/utils/rk27utils/rk27load/checksum.c b/utils/rk27utils/rk27load/checksum.c
new file mode 100644
index 0000000000..f0fe59350e
--- /dev/null
+++ b/utils/rk27utils/rk27load/checksum.c
@@ -0,0 +1,35 @@
+#include <stdint.h>
+#include "checksum.h"
+
+uint16_t checksum(void *buff, uint32_t size)
+{
+ uint32_t r2 = 0xffff;
+ uint32_t r3 = 0;
+ uint32_t i, j;
+
+ for (i=0; i<size; i++) {
+ r3 = 0x80;
+ for (j=0; j<8; j++) {
+ if ((r2 & 0x8000) != 0) {
+ r2 <<= 17;
+ r2 >>= 16;
+ r2 ^= 0x1000;
+ r2 ^= 0x21;
+ }
+ else {
+ r2 <<= 17;
+ r2 >>= 16;
+ }
+
+ if ((((uint8_t *)buff)[i] & r3) != 0) {
+ r2 ^= 0x1000;
+ r2 ^= 0x21;
+ }
+
+ r3 >>= 1;
+ }
+ }
+
+ return r2 & 0xffff;
+}
+
diff --git a/utils/rk27utils/rk27load/checksum.h b/utils/rk27utils/rk27load/checksum.h
new file mode 100644
index 0000000000..468ca6643e
--- /dev/null
+++ b/utils/rk27utils/rk27load/checksum.h
@@ -0,0 +1 @@
+uint16_t checksum(void *buff, uint32_t size);
diff --git a/utils/rk27utils/rk27load/common.c b/utils/rk27utils/rk27load/common.c
new file mode 100644
index 0000000000..b97cfbcd79
--- /dev/null
+++ b/utils/rk27utils/rk27load/common.c
@@ -0,0 +1,16 @@
+#include <stdint.h>
+#include <stdio.h>
+
+#include "common.h"
+
+uint32_t filesize(FILE * f)
+{
+ uint32_t filesize;
+
+ fseek(f, 0, SEEK_END);
+ filesize = ftell(f);
+ fseek(f, 0, SEEK_SET);
+
+ return filesize;
+}
+
diff --git a/utils/rk27utils/rk27load/common.h b/utils/rk27utils/rk27load/common.h
new file mode 100644
index 0000000000..f22ec7de40
--- /dev/null
+++ b/utils/rk27utils/rk27load/common.h
@@ -0,0 +1 @@
+uint32_t filesize(FILE * f);
diff --git a/utils/rk27utils/rk27load/main.c b/utils/rk27utils/rk27load/main.c
new file mode 100644
index 0000000000..d183ae2df1
--- /dev/null
+++ b/utils/rk27utils/rk27load/main.c
@@ -0,0 +1,165 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <libusb.h>
+
+#include "rk27load.h"
+#include "common.h"
+#include "stage1_upload.h"
+#include "stage2_upload.h"
+#include "stage3_upload.h"
+
+#define VERSION "v0.2"
+
+enum {
+ NONE = 0,
+ ENCODE_S1 = 1,
+ ENCODE_S2 = 2
+};
+
+static void usage(char *name)
+{
+ printf("usage: (sudo) %s [-e1 -e2] -s1 stage1.bin -s2 stage2.bin -s3 usercode.bin\n", name);
+ printf("stage1.bin - binary of the stage1 (sdram init)\n");
+ printf("stage2.bin - binary of the stage2 bootloader\n");
+ printf("usercode.bin - binary of the custom usercode\n");
+ printf("\n");
+ printf("options:\n");
+ printf("-e1 - encode stage1 bootloader\n");
+ printf("-e2 - encode stage2 bootloader\n");
+}
+
+int main(int argc, char **argv)
+{
+ libusb_device_handle *hdev;
+ char *filenames[3];
+ int i=1, action=0, ret=0;
+
+ while (i < argc)
+ {
+ if (strcmp(argv[i],"-e1") == 0)
+ {
+ action |= ENCODE_S1;
+ i++;
+ }
+ else if (strcmp(argv[i],"-e2") == 0)
+ {
+ action |= ENCODE_S2;
+ i++;
+ }
+ else if (strcmp(argv[i],"-s1") == 0)
+ {
+ i++;
+ if (i == argc)
+ {
+ usage(argv[0]);
+ return -1;
+ }
+ filenames[0] = argv[i];
+ printf("%s", argv[i]);
+ i++;
+ }
+ else if (strcmp(argv[i],"-s2") == 0)
+ {
+ i++;
+ if (i == argc)
+ {
+ usage(argv[0]);
+ return -2;
+ }
+ filenames[1] = argv[i];
+ i++;
+ }
+ else if (strcmp(argv[i],"-s3") == 0)
+ {
+ i++;
+ if (i == argc)
+ {
+ usage(argv[0]);
+ return -3;
+ }
+ filenames[2] = argv[i];
+ i++;
+ }
+ else
+ {
+ usage(argv[0]);
+ return -4;
+ }
+ }
+
+
+ fprintf(stderr,"rk27load " VERSION "\n");
+ fprintf(stderr,"(C) Marcin Bukat 2011\n");
+ fprintf(stderr,"Based on rk27load ver. 0.1 written by AleMaxx (alemaxx at hotmail.de)\n\n");
+ fprintf(stderr,"This is free software; see the source for copying conditions. There is NO\n");
+ fprintf(stderr,"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
+
+ /* initialize libusb */
+ libusb_init(NULL);
+
+ /* configure device */
+ fprintf(stderr, "[info]: Initializing device... ");
+ hdev = libusb_open_device_with_vid_pid(NULL, VENDORID, PRODUCTID);
+
+ if (hdev == NULL)
+ {
+ fprintf(stderr, "\n[error]: Could not find rockchip device\n");
+ ret = -2;
+ goto finish;
+ }
+
+ ret = libusb_set_configuration(hdev, 1);
+ if (ret < 0)
+ {
+ fprintf(stderr, "\n[error]: Could not select configuration (1)\n");
+ ret = -3;
+ goto finish;
+ }
+
+ ret = libusb_claim_interface(hdev, 0);
+ if (ret < 0)
+ {
+ fprintf(stderr, "\n[error]: Could not claim interface #0\n");
+ ret = -4;
+ goto finish;
+ }
+
+ ret = libusb_set_interface_alt_setting(hdev, 0, 0);
+ if (ret < 0)
+ {
+ fprintf(stderr, "\n[error]: Could not set alternate interface #0\n");
+ ret = -5;
+ goto finish;
+ }
+
+ fprintf(stderr, "done\n");
+
+
+ ret = upload_stage1_code(hdev, filenames[0], (action & ENCODE_S1));
+ if (ret < 0)
+ goto finish;
+
+ ret = upload_stage2_code(hdev, filenames[1], (action & ENCODE_S2));
+ if (ret < 0)
+ goto finish;
+
+ ret = upload_stage3_code(hdev, filenames[2]);
+ if (ret < 0)
+ goto finish;
+
+ /* done */
+ ret = 0;
+
+ finish:
+ if (hdev != NULL)
+ libusb_close(hdev);
+
+ if (ret < 0)
+ fprintf(stderr, "[error]: Error %d\n", ret);
+
+ return ret;
+}
diff --git a/utils/rk27utils/rk27load/rk27load.h b/utils/rk27utils/rk27load/rk27load.h
new file mode 100644
index 0000000000..8239176a0d
--- /dev/null
+++ b/utils/rk27utils/rk27load/rk27load.h
@@ -0,0 +1,11 @@
+#define USB_TIMEOUT 512
+
+#define VENDORID 0x71b
+#define PRODUCTID 0x3201
+
+#define USB_EP0 0x41
+
+#define VCMD_UPLOAD 0x0c
+#define VCMD_INDEX_STAGE1 0x471
+#define VCMD_INDEX_STAGE2 0x472
+
diff --git a/utils/rk27utils/rk27load/scramble.c b/utils/rk27utils/rk27load/scramble.c
new file mode 100644
index 0000000000..7e5b1518d7
--- /dev/null
+++ b/utils/rk27utils/rk27load/scramble.c
@@ -0,0 +1,46 @@
+#include <stdint.h>
+#include "scramble.h"
+
+void scramble(uint8_t *in, uint8_t *out, const int size)
+{
+ /* table extracted from bootrom */
+ static const uint8_t key[] = {
+ 0x7C, 0x4E, 0x03, 0x04,
+ 0x55, 0x05, 0x09, 0x07,
+ 0x2D, 0x2C, 0x7B, 0x38,
+ 0x17, 0x0D, 0x17, 0x11
+ };
+
+ int i, i3, x, val, idx;
+
+ uint8_t key1[0x100];
+ uint8_t key2[0x100];
+
+ for (i=0; i<0x100; i++) {
+ key1[i] = i;
+ key2[i] = key[i&0xf];
+ }
+
+ i3 = 0;
+ for (i=0; i<0x100; i++) {
+ x = key1[i];
+ i3 = key1[i] + i3;
+ i3 += key2[i];
+ i3 &= 0xff;
+ key1[i] = key1[i3];
+ key1[i3] = x;
+ }
+
+ idx = 0;
+ for (i=0; i<size; i++) {
+ x = key1[(i+1) & 0xff];
+ val = x;
+ idx = (x + idx) & 0xff;
+ key1[(i+1) & 0xff] = key1[idx];
+ key1[idx] = (x & 0xff);
+ val = (key1[(i+1)&0xff] + x) & 0xff;
+ val = key1[val];
+ out[i] = val ^ in[i];
+ }
+}
+
diff --git a/utils/rk27utils/rk27load/scramble.h b/utils/rk27utils/rk27load/scramble.h
new file mode 100644
index 0000000000..ed4b291316
--- /dev/null
+++ b/utils/rk27utils/rk27load/scramble.h
@@ -0,0 +1 @@
+void scramble(uint8_t *in, uint8_t *out, const int size);
diff --git a/utils/rk27utils/rk27load/stage1/Makefile b/utils/rk27utils/rk27load/stage1/Makefile
new file mode 100644
index 0000000000..5291685032
--- /dev/null
+++ b/utils/rk27utils/rk27load/stage1/Makefile
@@ -0,0 +1,48 @@
+
+TARGET = stage1
+
+TOOLCHAIN = arm-elf-eabi-
+
+CC = $(TOOLCHAIN)gcc
+CPP = $(TOOLCHAIN)cpp
+LD = $(TOOLCHAIN)gcc
+AS = $(TOOLCHAIN)as
+OBJCOPY = $(TOOLCHAIN)objcopy
+OBJDUMP = $(TOOLCHAIN)objdump
+
+CFLAGS = -Wundef -marm -march=armv5te -nostdlib -mfpu=fpa -O0 -c
+#ASFLAGS = -mcpu=arm926ej-s
+
+OBJS = main.o
+LDSCRIPT= stage1.lds
+
+#LIBDIRS = -L../arm/lib/gcc/arm-elf/4.1.0/ -L../lib
+#LIBS = -lgcc
+LIBS =
+LDFLAGS = -Wundef -marm -march=armv5te -T$(LDSCRIPT) -nostartfiles \
+ -mfpu=fpa -nostdlib -Xlinker -Map=$(TARGET).map
+
+all : $(TARGET).bin
+ ls -ls $(TARGET).bin
+
+%.o : %.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(INCDIRS) $< -o $@
+
+%.o : %.S
+ $(CC) $(CFLAGS) -c $< -o $@
+
+$(TARGET).elf : $(OBJS)
+ $(LD) $(LDFLAGS) $(OBJS) $(LIBDIRS) $(LIBS) -o $(TARGET).elf
+
+$(TARGET).bin : $(TARGET).elf
+ $(OBJCOPY) -O binary $(TARGET).elf $(TARGET).bin
+
+dasm : $(TARGET).bin
+ $(OBJDUMP) -m arm -D $(TARGET).elf | cat > $(TARGET).asm
+
+clean :
+ rm -f $(OBJS)
+ rm -f $(TARGET).elf
+ rm -f $(TARGET).bin
+ rm -f $(TARGET).asm
+ rm -f $(TARGET).map
diff --git a/utils/rk27utils/rk27load/stage1/main.S b/utils/rk27utils/rk27load/stage1/main.S
new file mode 100644
index 0000000000..44e7e2f914
--- /dev/null
+++ b/utils/rk27utils/rk27load/stage1/main.S
@@ -0,0 +1,42 @@
+.section .text,"ax",%progbits
+.global start
+
+start:
+ msr cpsr_c, #0xd3 /* enter supervisor mode, disable IRQ/FIQ */
+
+pll_setup:
+ mov r0, #0x18000000
+ add r0, r0, #0x1c000
+
+ /* setup ARM core freq = 200MHz */
+ /* AHB bus freq (HCLK) = 100MHz */
+ /* APB bus freq (PCLK) = 50MHz */
+ ldr r1, [r0,#0x14] /* SCU_DIVCON1 */
+ orr r1, #9 /* ARM slow mode, HCLK:PCLK = 2:1 */
+ str r1, [r0,#0x14]
+
+ ldr r1,=0x01970c70 /* (1<<24) | (1<<23) | (23<<16) | (199<<4) */
+ str r1, [r0,#0x08]
+
+ ldr r2,=0x40000
+1:
+ ldr r1, [r0,#0x2c] /* SCU_STATUS */
+ tst r1, #1 /* ARM pll lock */
+ bne 1f
+ subs r2, #1
+ bne 1b
+1:
+ ldr r1, [r0,#0x14] /* SCU_DIVCON1 */
+ bic r1, #5 /* leave ARM slow mode, ARMclk:HCLK = 2:1 */
+ str r1, [r0,#0x14]
+
+sdram_config:
+ add r0, r0, #0x94000 /* SDRAM base */
+
+ mov r1, #1
+ str r1, [r0,#0x10c] /* MCSDR_BASIC Round-robin, SDRAM width 16bits */
+
+ add r1, #0x10
+ str r1, [r0,#0x108] /* MCSDR_ADDCFG 12 bits row/9 bits col addr */
+
+ mov pc, lr /* we are done, return to bootrom code */
diff --git a/utils/rk27utils/rk27load/stage1/stage1.lds b/utils/rk27utils/rk27load/stage1/stage1.lds
new file mode 100644
index 0000000000..4af8b93c55
--- /dev/null
+++ b/utils/rk27utils/rk27load/stage1/stage1.lds
@@ -0,0 +1,23 @@
+ENTRY(start)
+OUTPUT_FORMAT(elf32-littlearm)
+OUTPUT_ARCH(arm)
+/* STARTUP(crt0.o) */
+
+/* this is where bootrom loads sdram init code */
+MEMORY
+{
+ IRAM : ORIGIN = 0x18200E00, LENGTH = 0x00000200
+}
+
+SECTIONS
+{
+ .text : {
+ *(.text*)
+ *(.glue_7*)
+ } > IRAM
+
+ .data : {
+ *(.rodata*)
+ *(.data*)
+ } > IRAM
+}
diff --git a/utils/rk27utils/rk27load/stage1_upload.c b/utils/rk27utils/rk27load/stage1_upload.c
new file mode 100644
index 0000000000..8eb4ae9e37
--- /dev/null
+++ b/utils/rk27utils/rk27load/stage1_upload.c
@@ -0,0 +1,113 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libusb.h>
+
+#include "rk27load.h"
+#include "common.h"
+#include "scramble.h"
+#include "checksum.h"
+#include "stage1_upload.h"
+
+/* ### upload sdram init code ### */
+int upload_stage1_code(libusb_device_handle *hdev, char *fn_stage1,
+ bool do_scramble)
+{
+ FILE *f;
+ int ret;
+ uint8_t *code;
+ uint32_t codesize;
+ uint16_t cks;
+
+ if ((f = fopen(fn_stage1, "rb")) == NULL)
+ {
+ fprintf(stderr, "[error]: Could not open file \"%s\"\n", fn_stage1);
+ return -10;
+ }
+
+ codesize = filesize(f);
+
+ if (codesize > 0x1fe)
+ {
+ fprintf(stderr, "[error]: Code too big for stage1\n");
+ return -11;
+ }
+
+ fprintf(stderr, "[stage1]: Loading %d bytes (%s) of code... ", codesize, fn_stage1);
+
+ code = (uint8_t *)malloc(0x200);
+ if (code == NULL)
+ {
+ fprintf(stderr, "\n[error]: Out of memory\n");
+ fclose(f);
+ return -12;
+ }
+
+ memset(code, 0, 0x200);
+ if (fread(code, 1, codesize, f) != codesize)
+ {
+ fprintf(stderr, "\n[error]: I/O error\n");
+ fclose(f);
+ free(code);
+ return -13;
+ }
+
+ fprintf(stderr, "done\n");
+ fclose(f);
+
+ /* encode data if requested */
+ if (do_scramble)
+ {
+
+ fprintf(stderr, "[stage1]: Encoding %d bytes of data ... ", codesize);
+ scramble(code, code, codesize);
+ fprintf(stderr, "done\n");
+ }
+
+
+ fprintf(stderr, "[stage1]: codesize = %d (0x%x)\n", codesize, codesize);
+
+ fprintf(stderr, "[stage1]: Calculating checksum... ");
+ cks = checksum((void *)code, codesize);
+ fprintf(stderr, "0x%04x\n", cks);
+ code[0x1fe] = (cks >> 8) & 0xff;
+ code[0x1ff] = cks & 0xff;
+ codesize += 2;
+
+ fprintf(stderr, "[stage1]: Uploading code (%d bytes)... ", codesize);
+
+ ret = libusb_control_transfer(hdev, /* device handle */
+ USB_EP0, /* bmRequestType */
+ VCMD_UPLOAD, /* bRequest */
+ 0, /* wValue */
+ VCMD_INDEX_STAGE1, /* wIndex */
+ code, /* data */
+ codesize, /* wLength */
+ USB_TIMEOUT /* timeout */
+ );
+ if (ret < 0)
+ {
+ fprintf(stderr, "\n[error]: Code upload request failed (ret=%d)\n", ret);
+ free(code);
+ return -14;
+ }
+
+ if (ret != (int)codesize)
+ {
+ fprintf(stderr, "\n[error]: Sent %d of %d total\n", ret, codesize);
+ free(code);
+ return -15;
+ }
+
+ sleep(1); /* wait for code to finish */
+ fprintf(stderr, "done\n");
+
+ /* free code */
+ free(code);
+
+ return 0;
+}
+
diff --git a/utils/rk27utils/rk27load/stage1_upload.h b/utils/rk27utils/rk27load/stage1_upload.h
new file mode 100644
index 0000000000..efb1c3407e
--- /dev/null
+++ b/utils/rk27utils/rk27load/stage1_upload.h
@@ -0,0 +1,3 @@
+int upload_stage1_code(libusb_device_handle * hdev, char *fn_stage1,
+ bool do_scramble);
+
diff --git a/utils/rk27utils/rk27load/stage2/Makefile b/utils/rk27utils/rk27load/stage2/Makefile
new file mode 100644
index 0000000000..4b216db2f3
--- /dev/null
+++ b/utils/rk27utils/rk27load/stage2/Makefile
@@ -0,0 +1,48 @@
+
+TARGET = stage2
+
+TOOLCHAIN = arm-elf-eabi-
+
+CC = $(TOOLCHAIN)gcc
+CPP = $(TOOLCHAIN)cpp
+LD = $(TOOLCHAIN)gcc
+AS = $(TOOLCHAIN)as
+OBJCOPY = $(TOOLCHAIN)objcopy
+OBJDUMP = $(TOOLCHAIN)objdump
+
+CFLAGS = -Wundef -marm -march=armv5te -nostdlib -mfpu=fpa -O0 -c
+#ASFLAGS = -mcpu=arm926ej-s
+
+OBJS = crt0.o main.o irq.o
+LDSCRIPT= stage2.lds
+
+#LIBDIRS = -L../arm/lib/gcc/arm-elf/4.1.0/ -L../lib
+#LIBS = -lgcc
+LIBS =
+LDFLAGS = -Wundef -marm -march=armv5te -T$(LDSCRIPT) -nostartfiles \
+ -mfpu=fpa -nostdlib -Xlinker -Map=$(TARGET).map
+
+all : $(TARGET).bin
+ ls -ls $(TARGET).bin
+
+%.o : %.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(INCDIRS) $< -o $@
+
+%.o : %.S
+ $(CC) $(CFLAGS) -c $< -o $@
+
+$(TARGET).elf : $(OBJS)
+ $(LD) $(LDFLAGS) $(OBJS) $(LIBDIRS) $(LIBS) -o $(TARGET).elf
+
+$(TARGET).bin : $(TARGET).elf
+ $(OBJCOPY) -O binary $(TARGET).elf $(TARGET).bin
+
+dasm : $(TARGET).bin
+ $(OBJDUMP) -m arm -D $(TARGET).elf | cat > $(TARGET).asm
+
+clean :
+ rm -f $(OBJS)
+ rm -f $(TARGET).elf
+ rm -f $(TARGET).bin
+ rm -f $(TARGET).asm
+ rm -f $(TARGET).map
diff --git a/utils/rk27utils/rk27load/stage2/crt0.S b/utils/rk27utils/rk27load/stage2/crt0.S
new file mode 100644
index 0000000000..c85477546d
--- /dev/null
+++ b/utils/rk27utils/rk27load/stage2/crt0.S
@@ -0,0 +1,55 @@
+//
+// startup code
+//
+//
+
+#define PSR_MODE 0x0000001f
+#define PSR_USR_MODE 0x00000010
+#define PSR_IRQ_MODE 0x00000012
+#define PSR_SVC_MODE 0x00000013
+
+#define PSR_INT_MASK 0x000000c0
+#define PSR_FIQ_DIS 0x00000040
+#define PSR_IRQ_DIS 0x00000080
+
+.section .init.text,"ax",%progbits
+.global start
+.extern _interrupt_disable
+
+// -----------------------------------------------------
+// startup code (setup stacks, branch to main)
+// -----------------------------------------------------
+start:
+ // setup IRQ stack
+ mov r0, #(PSR_IRQ_MODE|PSR_FIQ_DIS|PSR_IRQ_DIS)
+ msr cpsr, r0
+ ldr sp,=irqstackend
+
+ // setup SVC stack
+ mov r0, #(PSR_SVC_MODE|PSR_FIQ_DIS|PSR_IRQ_DIS)
+ msr cpsr, r0
+ ldr sp,=stackend
+
+ // disbale interrupts
+ mrs r0, cpsr
+ orr r0, r0, #0xc0
+ msr cpsr_c, r0
+
+ // remap
+ mov r0, #0x18000000
+ add r0, r0, #0x1C000
+ ldr r1,=0xdeadbeef
+ str r1, [r0, #4]
+
+ // relocate itself
+ ldr r0,=_relocstart
+ ldr r1,=_relocend
+ ldr r2,=0x0
+1:
+ cmp r1,r0
+ ldrhi r3,[r0],#4
+ strhi r3,[r2],#4
+ bhi 1b
+
+ // continue running in SVC (supervisor mode)
+ ldr pc,=0x0
diff --git a/utils/rk27utils/rk27load/stage2/irq.S b/utils/rk27utils/rk27load/stage2/irq.S
new file mode 100644
index 0000000000..043bf185a5
--- /dev/null
+++ b/utils/rk27utils/rk27load/stage2/irq.S
@@ -0,0 +1,103 @@
+ .section .text
+ .align 4
+
+ .global irq_handler
+ #define BUFF_ADDR 0x60800000
+
+irq_handler:
+ stmfd sp!, {r0-r7, ip, lr}
+
+ // get interrupt number
+ mov r4, #0x18000000
+ add r4, r4, #0x80000
+ ldr r5, [r4, #0x104]
+ and r5, r5, #0x1f
+ cmp r5, #0x10 // UDC interrupt
+
+ bleq udc_irq
+
+ // clear pending interrupt
+ mov r3, #1
+ mov r2, r3, LSL r5
+ str r2, [r4, #0x118]
+
+ ldmfd sp!, {r0-r7, ip, lr}
+ subs pc, lr, #4
+
+udc_irq:
+ stmfd sp!, {r4-r8, lr}
+
+ // handle usb interrupt
+ ldr r4,=0x180A0000
+ ldr r5, [r4, #0x18] // UDC_INTFLAG
+
+ // ep0 in intr
+ tst r5, #0x04
+ beq bulk_recv_intr
+
+ // write_reg32(UDC_TX0STAT, read_reg32(UDC_TX0STAT) & ~0x7FF);
+ ldr r5, [r4, #0x40]
+ mov r5, r5, lsr #10
+ mov r5, r5, lsl #10 // clear clower 10 bits
+ str r5, [r4, #0x40]
+
+ // write_reg32(UDC_DMA0LM_OADDR, (uint32_t)(state.ctrlep_data));
+ mov r5, #0x60000000
+ str r5, [r4, #0x3c]
+
+ // write_reg32(UDC_DMA0CTLO, read_reg32(UDC_DMA0CTLO) | ENP_DMA_START);
+ mov r5, #1
+ str r5, [r4, #0x38]
+
+ ldmfd sp!, {r4-r8, pc}
+
+// bulk out interrupt
+bulk_recv_intr:
+ tst r5, #0x100
+ ldmeqfd sp!, {r4-r8, pc}
+
+ // read UDC_RX1STAT
+ ldr r5, [r4, #0x54]
+ mov r5, r5, lsl #21
+ mov r5, r5, lsr #21 // r5 = length
+
+ ldr r6,=usb_sz
+ ldr r6, [r6]
+ ldr r7, [r6] // r7 = total_code_length expected
+
+ subs r7, r7, r5
+ bne usb_bulk_out1_recv
+
+ // copy from buff to the begining of the ram
+ ldr r0,=BUFF_ADDR
+ ldr r1,[r0,#-4] // size
+
+ ldr r1,=0x800000 // buffer size
+
+ add r1,r1,r0 // end address
+ ldr r2,=0x60000000 // destination
+1:
+ cmp r1,r0
+ ldrhi r3,[r0],#4
+ strhi r3,[r2],#4
+ bhi 1b
+
+ // execute user code
+ ldr r0,=0x60000000
+ bx r0 // jump to 0x60000000
+
+usb_bulk_out1_recv:
+ str r7, [r6] // size = size - received
+
+ ldr r6,=usb_write_addr
+ ldr r7, [r6]
+
+ add r7, r7, r5
+ str r7, [r6] // usb_write_addr += length
+
+ str r7, [r4, #0x60] // DMA1LM_OADDR = usb_write_addr
+
+ mov r5, #1
+ str r5, [r4, #0x5c] // DMA1_CTL0 = ENP_DMA_START
+
+ ldmfd sp!, {r4-r8, pc}
diff --git a/utils/rk27utils/rk27load/stage2/main.S b/utils/rk27utils/rk27load/stage2/main.S
new file mode 100644
index 0000000000..c8474b0579
--- /dev/null
+++ b/utils/rk27utils/rk27load/stage2/main.S
@@ -0,0 +1,89 @@
+
+ .section .text
+ .align 4
+
+ .arm
+
+ .global main
+ .global _interrupt_disable
+ .global _interrupt_enable
+
+ .global usb_write_addr
+ .global usb_sz
+
+ #define BUFF_ADDR 0x60800000
+
+// -----------------------------------------------------
+// vector table
+// -----------------------------------------------------
+ ldr pc, =main
+ ldr pc, =main
+ ldr pc, =main
+ ldr pc, =main
+ ldr pc, =main
+ ldr pc, =main
+ ldr pc, =irq_handler
+ ldr pc, =main
+
+// -----------------------------------------------------
+// main
+// -----------------------------------------------------
+main:
+ // turn on usb interrupts
+ mov r0, #0x18000000
+ add r0, r0, #0x80000
+ ldr r1, [r0, #0x10c]
+ orr r1, r1, #0x10000
+ str r1, [r0, #0x10c]
+
+ // enable usb-bulk
+ add r0, r0, #0x20000 // R0 = 0x180A0000 (UDC_BASE)
+
+ // enable EP1, write_reg32(UDC_RX1CON, (0x1 << 8) | RxACKINTEN | RxEPEN);
+ mov r1, #0x190 // bits 8,7,4 -> 0x190
+ str r1, [r0, #0x58]
+
+ // setup receive buffer (must be aligned on dword boundary)
+ ldr r1,=usb_write_addr // write_reg32(UDC_DMA1LM_OADDR, (uint32_t)rx_buff);
+ ldr r1, [r1]
+ str r1, [r0, #0x60] // UDC_DMA1LM_OADDR = usb_write_addr
+
+ // write_reg32(UDC_DMA1CTRLO, read_reg32(UDC_DMA1CTRLO) | ENP_DMA_START);
+ ldr r1, [r0, #0x5c]
+ orr r1, r1, #2
+ str r1, [r0, #0x5c]
+
+ // enable bulk_out1 interrupt
+ ldr r1, [r0, #0x14] // UDC_ENINT
+ orr r1, r1, #0x100 // EN_BOUT1_INTR
+ str r1, [r0, #0x14]
+
+ bl _interrupt_enable
+idle:
+ b idle
+
+// -----------------------------------------------------
+// _interrupt_enable - enables interrupts
+// -----------------------------------------------------
+_interrupt_enable:
+ mrs r0, cpsr
+ bic r0, r0, #0x80
+ msr cpsr_c, r0
+ mov pc, lr
+
+// -----------------------------------------------------
+// _interrupt_disable - disables interrupts
+// -----------------------------------------------------
+_interrupt_disable:
+ mrs r0, cpsr
+ orr r0, r0, #0xc0
+ msr cpsr_c, r0
+ mov pc, lr
+
+
+ .section .data
+usb_write_addr:
+ .word (BUFF_ADDR-4)
+
+usb_sz:
+ .word (BUFF_ADDR-4)
diff --git a/utils/rk27utils/rk27load/stage2/stage2.lds b/utils/rk27utils/rk27load/stage2/stage2.lds
new file mode 100644
index 0000000000..2c07b201f7
--- /dev/null
+++ b/utils/rk27utils/rk27load/stage2/stage2.lds
@@ -0,0 +1,40 @@
+ENTRY(start)
+OUTPUT_FORMAT(elf32-littlearm)
+OUTPUT_ARCH(arm)
+/* STARTUP(crt0.o) */
+
+MEMORY
+{
+ DRAM : ORIGIN = 0x60000000, LENGTH = 0x01000000
+ IRAM : ORIGIN = 0x00000000, LENGTH = 0x00002000
+}
+
+SECTIONS
+{
+ .init.text : {
+ *(.init.text)
+ } > DRAM
+
+ .text : {
+ *(.text*)
+ *(.glue_7*)
+ } > IRAM AT > DRAM
+
+ .data : {
+ *(.data*)
+ } > IRAM AT > DRAM
+
+ _relocstart = LOADADDR(.text);
+ _relocend = LOADADDR(.data) + SIZEOF(.data);
+
+ .stack (NOLOAD) : {
+ . = ALIGN(0x100);
+ *(.stack)
+ stackbegin = .;
+ . += 0x200;
+ stackend = .;
+ irqstackbegin = .;
+ . += 0x200;
+ irqstackend = .;
+ } > IRAM
+}
diff --git a/utils/rk27utils/rk27load/stage2_upload.c b/utils/rk27utils/rk27load/stage2_upload.c
new file mode 100644
index 0000000000..820ad4463c
--- /dev/null
+++ b/utils/rk27utils/rk27load/stage2_upload.c
@@ -0,0 +1,102 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libusb.h>
+
+#include "rk27load.h"
+#include "common.h"
+#include "scramble.h"
+#include "checksum.h"
+#include "stage2_upload.h"
+
+int upload_stage2_code(libusb_device_handle *hdev, char *fn_stage2,
+ bool do_scramble)
+{
+ FILE *f;
+ uint32_t codesize;
+ uint8_t *code;
+ uint16_t cks;
+ int ret;
+
+ if ((f = fopen(fn_stage2, "rb")) == NULL)
+ {
+ fprintf(stderr, "[error]: Could not open file \"%s\"\n", fn_stage2);
+ return -21;
+ }
+
+ codesize = filesize(f);
+
+ fprintf(stderr, "[stage1]: Loading %d bytes (%s) of code... ", codesize, fn_stage2);
+
+ code = (uint8_t *) malloc(codesize + 0x400);
+ if (code == NULL)
+ {
+ fprintf(stderr, "\n[error]: Out of memory\n");
+ fclose(f);
+ return -22;
+
+ }
+
+ memset(code, 0, codesize + 0x400);
+
+ if (fread(code, 1, codesize, f) != codesize)
+ {
+ fprintf(stderr, "\n[error]: I/O error\n");
+ fclose(f);
+ free(code);
+ return -23;
+ }
+ fprintf(stderr, "done\n");
+ fclose(f);
+
+ codesize = ((codesize + 0x201) & 0xfffffe00) - 2;
+
+ if (do_scramble)
+ {
+ /* encode data if its user code */
+ fprintf(stderr, "[stage2]: Encoding %d bytes data... ", codesize);
+ scramble(code, code, codesize);
+ fprintf(stderr, "done\n");
+ }
+
+ fprintf(stderr, "[stage2]: Calculating checksum... ");
+ cks = checksum(code, codesize);
+ code[codesize + 0] = (cks >> 8) & 0xff;
+ code[codesize + 1] = cks & 0xff;
+ codesize += 2;
+ fprintf(stderr, "0x%04x\n", cks);
+
+ fprintf(stderr, "[stage2]: Uploading code (%d bytes)... ", codesize);
+
+ ret = libusb_control_transfer(hdev, /* device handle */
+ USB_EP0, /* bmRequestType */
+ VCMD_UPLOAD, /* bRequest */
+ 0, /* wValue */
+ VCMD_INDEX_STAGE2, /* wIndex */
+ code, /* data */
+ codesize, /* wLength */
+ USB_TIMEOUT /* timeout */
+ );
+
+ if (ret < 0)
+ {
+ fprintf(stderr, "\n[error]: Code upload request failed (ret=%d)\n", ret);
+ free(code);
+ return -24;
+ }
+
+ if (ret != (int)codesize)
+ {
+ fprintf(stderr, "[error]: Sent %d of %d total\n", ret, codesize);
+ free(code);
+ return -25;
+ }
+
+ fprintf(stderr, "done\n");
+
+ free(code);
+ return 0;
+}
+
diff --git a/utils/rk27utils/rk27load/stage2_upload.h b/utils/rk27utils/rk27load/stage2_upload.h
new file mode 100644
index 0000000000..852d17adb2
--- /dev/null
+++ b/utils/rk27utils/rk27load/stage2_upload.h
@@ -0,0 +1,3 @@
+int upload_stage2_code(libusb_device_handle * hdev, char *fn_stage2,
+ bool do_scramble);
+
diff --git a/utils/rk27utils/rk27load/stage3_upload.c b/utils/rk27utils/rk27load/stage3_upload.c
new file mode 100644
index 0000000000..6f10a7c995
--- /dev/null
+++ b/utils/rk27utils/rk27load/stage3_upload.c
@@ -0,0 +1,93 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libusb.h>
+
+#include "rk27load.h"
+#include "common.h"
+#include "scramble.h"
+#include "checksum.h"
+#include "stage3_upload.h"
+
+int upload_stage3_code(libusb_device_handle *hdev, char *fn_stage3)
+{
+ FILE *f;
+ uint32_t codesize;
+ uint32_t remain;
+ uint8_t *code;
+ uint16_t send_size = 0x200;
+ uint32_t i = 0;
+ int ret, transfered;
+
+ if ((f = fopen(fn_stage3, "rb")) == NULL)
+ {
+ fprintf(stderr, "[error]: Could not open file \"%s\"\n", fn_stage3);
+ return -31;
+ }
+
+ codesize = filesize(f);
+
+ fprintf(stderr, "[stage3]: Loading user code (%d bytes)... ", codesize);
+
+ /* allocate buffer */
+ code = (uint8_t *) malloc(codesize + 0x204);
+ if (code == NULL)
+ {
+ fprintf(stderr, "\n[error]: Out of memory\n");
+ fclose(f);
+ return -32;
+ }
+
+ memset(code, 0, codesize + 0x204);
+ /* read usercode into buffer */
+ if (fread(&code[4], 1, codesize, f) != codesize)
+ {
+ fprintf(stderr, "\n[error]: I/O error\n");
+ fclose(f);
+ free(f);
+ return -33;
+ }
+ fprintf(stderr, "done\n");
+
+ fclose(f);
+
+ /* put code size at the first 4 bytes */
+ codesize += 4;
+ code[0] = codesize & 0xff;
+ code[1] = (codesize >> 8) & 0xff;
+ code[2] = (codesize >> 16) & 0xff;
+ code[3] = (codesize >> 24) & 0xff;
+
+ fprintf(stderr, "[stage3]: Uploading user code (%d bytes)... ", codesize);
+
+ remain = codesize;
+
+ while (remain > 0)
+ {
+ if (remain < 0x200)
+ send_size = remain;
+
+ ret = libusb_bulk_transfer(hdev, /* handle */
+ 1, /* EP */
+ &code[i * 0x200], /* data */
+ send_size, /* length */
+ &transfered, /* xfered */
+ USB_TIMEOUT /* timeout */
+ );
+
+ if (ret != LIBUSB_SUCCESS)
+ {
+ fprintf(stderr, "\n[error]: Bulk transfer error (%d, %d)\n", ret, i);
+ free(code);
+ return -34;
+ }
+
+ remain -= send_size;
+ i++;
+ }
+
+ fprintf(stderr,"done (sent %d blocks)\n", i);
+ return 0;
+}
+
diff --git a/utils/rk27utils/rk27load/stage3_upload.h b/utils/rk27utils/rk27load/stage3_upload.h
new file mode 100644
index 0000000000..03f9f0e46a
--- /dev/null
+++ b/utils/rk27utils/rk27load/stage3_upload.h
@@ -0,0 +1 @@
+int upload_stage3_code(libusb_device_handle *hdev, char *fn_stage3);
diff --git a/utils/rk27utils/rkboottool/Makefile b/utils/rk27utils/rkboottool/Makefile
new file mode 100644
index 0000000000..895dfc87cc
--- /dev/null
+++ b/utils/rk27utils/rkboottool/Makefile
@@ -0,0 +1,7 @@
+all: rkboottool
+
+rkboottool: rkboottool.c
+ gcc -g -std=c99 -o $@ -W -Wall $^
+
+clean:
+ rm -fr rkboottool
diff --git a/utils/rk27utils/rkboottool/rkboottool.c b/utils/rk27utils/rkboottool/rkboottool.c
new file mode 100644
index 0000000000..ad08b0b5f6
--- /dev/null
+++ b/utils/rk27utils/rkboottool/rkboottool.c
@@ -0,0 +1,360 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define VERSION "v0.3"
+
+/* time field stucture */
+struct rktime_t
+{
+ uint16_t year;
+ uint16_t month;
+ uint16_t day;
+ uint16_t hour;
+ uint16_t minute;
+ uint16_t second;
+};
+
+/* Rock27Boot.bin header structure */
+struct rkboot_info_t
+{
+ char sign[32];
+ uint8_t check_values[16];
+ struct rktime_t time;
+ uint32_t ui_master_version;
+ uint32_t ui_slave_version;
+ uint32_t s1_offset;
+ int32_t s1_len;
+ uint32_t s2_offset;
+ int32_t s2_len;
+ uint32_t s3_offset;
+ int32_t s3_len;
+ uint32_t s4_offset;
+ int32_t s4_len;
+ uint32_t version_flag;
+};
+
+/* actions */
+enum {
+ NONE = 0,
+ INFO = 1,
+ EXTRACT = 2,
+ SCRAMBLE = 4
+};
+
+/* scramble mode */
+enum {
+ CONTINOUS_ENC, /* scramble whole block at once */
+ PAGE_ENC /* nand bootloader is scrambled in 0x200 chunks */
+};
+
+/* scrambling/descrambling reverse engineered by AleMaxx */
+static void encode_page(uint8_t *inpg, uint8_t *outpg, const int size)
+{
+
+uint8_t key[] = {
+ 0x7C, 0x4E, 0x03, 0x04,
+ 0x55, 0x05, 0x09, 0x07,
+ 0x2D, 0x2C, 0x7B, 0x38,
+ 0x17, 0x0D, 0x17, 0x11
+};
+ int i, i3, x, val, idx;
+
+ uint8_t key1[0x100];
+ uint8_t key2[0x100];
+
+ for (i=0; i<0x100; i++) {
+ key1[i] = i;
+ key2[i] = key[i&0xf];
+ }
+
+ i3 = 0;
+ for (i=0; i<0x100; i++) {
+ x = key1[i];
+ i3 = key1[i] + i3;
+ i3 += key2[i];
+ i3 &= 0xff;
+ key1[i] = key1[i3];
+ key1[i3] = x;
+ }
+
+ idx = 0;
+ for (i=0; i<size; i++) {
+ x = key1[(i+1) & 0xff];
+ val = x;
+ idx = (x + idx) & 0xff;
+ key1[(i+1) & 0xff] = key1[idx];
+ key1[idx] = (x & 0xff);
+ val = (key1[(i+1)&0xff] + x) & 0xff;
+ val = key1[val];
+ outpg[i] = val ^ inpg[i];
+ }
+}
+
+static void *binary_extract(FILE *fp, uint32_t offset, uint32_t len, int descramble, int encode_mode)
+{
+ void *buff, *buff_ptr;
+ uint32_t ret;
+
+ if ((fp == NULL) || len == 0)
+ return NULL;
+
+ /* allocate buff */
+ if ((buff = malloc(len)) == NULL)
+ return NULL;
+
+ /* seek to the begining of the data */
+ fseek(fp, offset, SEEK_SET);
+
+ /* read into the buffer */
+ ret = fread(buff, 1, len, fp);
+
+ if (ret != len)
+ {
+ free(buff);
+ return NULL;
+ }
+
+ /* descramble */
+ if ( descramble )
+ {
+ buff_ptr = buff;
+ if (encode_mode == PAGE_ENC)
+ {
+ while (len >= 0x200)
+ {
+ encode_page((uint8_t *)buff_ptr,
+ (uint8_t *)buff_ptr,
+ 0x200);
+
+ buff_ptr += 0x200;
+ len -= 0x200;
+ }
+ }
+ encode_page((uint8_t *)buff_ptr, (uint8_t *)buff_ptr, len);
+ }
+
+ return buff;
+}
+
+static void usage(void)
+{
+ printf("Usage: rkboottool [options] Rock27Boot.bin\n");
+ printf("-h|--help This help message\n");
+ printf("-e|--extract Extract binary images from Rock27Boot.bin file\n");
+ printf("-d|--descramble Descramble extracted binary images\n");
+ printf("-i|--info Print info about Rock27Boot.bin file\n");
+ printf("\n");
+ printf("Usually you would like to use -d -e together to obtain raw binary\n");
+ printf("(out files rkboot_s1.bin, rkboot_s2.bin, rkboot_s3.bin, rkboot_s4.bin)\n");
+}
+
+int main (int argc, char **argv)
+{
+ struct rkboot_info_t rkboot_info;
+ FILE *fp_in, *fp_out;
+ int32_t i = 0, action = NONE;
+ int32_t ret;
+ void *buff;
+ char *in_filename = NULL;
+
+ if ( argc < 2 )
+ {
+ usage();
+ return -1;
+ }
+
+ /* print banner */
+ fprintf(stderr,"rkboottool " VERSION "\n");
+ fprintf(stderr,"(C) Marcin Bukat 2011\n");
+ fprintf(stderr,"This is free software; see the source for copying conditions. There is NO\n");
+ fprintf(stderr,"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
+
+ /* arguments handling */
+ while (i < argc)
+ {
+ if ((strcmp(argv[i],"-i")==0) || (strcmp(argv[i],"--info")==0))
+ {
+ action |= INFO;
+ }
+ else if ((strcmp(argv[i],"-e")==0) || (strcmp(argv[i],"--extract")==0))
+ {
+ action |= EXTRACT;
+ }
+ else if ((strcmp(argv[i],"-d")==0) || (strcmp(argv[i],"--descramble")==0))
+ {
+ action |= SCRAMBLE;
+ }
+ else if ((strcmp(argv[i],"-h")==0) || (strcmp(argv[i],"--help")==0))
+ {
+ usage();
+ return 0;
+ }
+ else if ( argv[i][0] != '-' )
+ {
+ /* file argument */
+ in_filename = argv[i];
+ }
+ i++;
+ }
+
+ if ( (fp_in = fopen(in_filename, "rb")) == NULL )
+ {
+ fprintf(stderr, "error: can't open %s file for reading\n", in_filename);
+ return -1;
+ }
+
+ ret = fread(&rkboot_info, 1, sizeof(rkboot_info), fp_in);
+
+ if (ret != sizeof(rkboot_info))
+ {
+ fclose(fp_in);
+ fprintf(stderr, "error: can't read %s file header\n", in_filename);
+ fprintf(stderr, "read %d, expected %d\n", ret, sizeof(rkboot_info));
+ return -2;
+ }
+
+ if (action & INFO)
+ {
+ printf("file: %s\n", in_filename);
+ printf("signature: %s\n", rkboot_info.sign);
+ printf("check bytes: ");
+ for (i = 0; i < 16; i++)
+ printf("0x%0x ", rkboot_info.check_values[i]);
+
+ printf("\n");
+ printf("timestamp %d.%d.%d %d:%d:%d\n", rkboot_info.time.day,
+ rkboot_info.time.month,
+ rkboot_info.time.year,
+ rkboot_info.time.hour,
+ rkboot_info.time.minute,
+ rkboot_info.time.second);
+ printf("UI master version: 0x%0x\n", rkboot_info.ui_master_version);
+ printf("UI slave version: 0x%0x\n", rkboot_info.ui_slave_version);
+ printf("s1 data offset: 0x%0x\n", rkboot_info.s1_offset);
+ printf("s1 data len: 0x%0x\n", rkboot_info.s1_len);
+ printf("s2 offset: 0x%0x\n", rkboot_info.s2_offset);
+ printf("s2 len: 0x%0x\n", rkboot_info.s2_len);
+ printf("s3 offset: 0x%0x\n", rkboot_info.s3_offset);
+ printf("s3 len: 0x%0x\n", rkboot_info.s3_len);
+ printf("s4 offset: 0x%0x\n", rkboot_info.s4_offset);
+ printf("s4 len: 0x%0x\n", rkboot_info.s4_len);
+ printf("UI version flag: 0x%0x\n", rkboot_info.version_flag);
+ }
+
+ if (action & EXTRACT)
+ {
+ /* first stage */
+ buff = binary_extract(fp_in, rkboot_info.s1_offset,
+ rkboot_info.s1_len,
+ action & SCRAMBLE,
+ CONTINOUS_ENC);
+
+ if ( buff == NULL )
+ {
+ fclose(fp_in);
+ fprintf(stderr, "error: can't extract image\n");
+ return -2;
+ }
+
+ /* output */
+ if ((fp_out = fopen("rkboot_s1.bin", "wb")) == NULL)
+ {
+ free(buff);
+ fclose(fp_in);
+ fprintf(stderr, "[error]: can't open rkboot_s1.bin for writing\n");
+ return -3;
+ }
+
+ fwrite(buff, 1, rkboot_info.s1_len, fp_out);
+
+ fprintf(stderr, "[info]: extracted rkboot_s1.bin file\n");
+ free(buff);
+ fclose(fp_out);
+
+ /* second stage */
+ buff = binary_extract(fp_in, rkboot_info.s2_offset,
+ rkboot_info.s2_len,
+ action & SCRAMBLE,
+ CONTINOUS_ENC);
+
+ if ( buff == NULL )
+ {
+ fclose(fp_in);
+ fprintf(stderr, "error: can't extract image\n");
+ return -2;
+ }
+
+ if ((fp_out = fopen("rkboot_s2.bin", "wb")) == NULL)
+ {
+ free(buff);
+ fclose(fp_in);
+ fprintf(stderr, "[error]: can't open rkboot_s2.bin for writing\n");
+ return -4;
+ }
+
+ fwrite(buff, 1, rkboot_info.s2_len, fp_out);
+
+ fprintf(stderr, "[info]: extracted rkboot_s2.bin file\n");
+ free(buff);
+ fclose(fp_out);
+
+ /* third stage */
+ buff = binary_extract(fp_in, rkboot_info.s3_offset,
+ rkboot_info.s3_len,
+ action & SCRAMBLE,
+ PAGE_ENC);
+ if ( buff == NULL )
+ {
+ fclose(fp_in);
+ fprintf(stderr, "[error]: can't extract image.\n");
+ return -2;
+ }
+
+ if ((fp_out = fopen("rkboot_s3.bin", "wb")) == NULL)
+ {
+ free(buff);
+ fclose(fp_in);
+ fprintf(stderr, "[error]: can't open rkboot_s3.bin for writing\n");
+ return -4;
+ }
+
+ fwrite(buff, 1, rkboot_info.s3_len, fp_out);
+
+ fprintf(stderr, "[info]: extracted rkboot_s3.bin file\n");
+ free(buff);
+ fclose(fp_out);
+
+ /* forth stage */
+ buff = binary_extract(fp_in, rkboot_info.s4_offset,
+ rkboot_info.s4_len,
+ action & SCRAMBLE,
+ CONTINOUS_ENC);
+ if ( buff == NULL )
+ {
+ fclose(fp_in);
+ fprintf(stderr, "[error]: can't extract image\n");
+ return -2;
+ }
+
+ if ((fp_out = fopen("rkboot_s4.bin", "wb")) == NULL)
+ {
+ free(buff);
+ fclose(fp_in);
+ fprintf(stderr, "[error]: can't open rkboot_s4.bin for writing\n");
+ return -4;
+ }
+
+ fwrite(buff, 1, rkboot_info.s4_len, fp_out);
+
+ fprintf(stderr, "[info]: extracted rkboot_s4.bin file\n");
+ free(buff);
+ fclose(fp_out);
+ }
+
+ fclose(fp_in);
+ return 0;
+}
+
diff --git a/utils/rk27utils/rkusbtool/Makefile b/utils/rk27utils/rkusbtool/Makefile
new file mode 100644
index 0000000000..785a09a1f1
--- /dev/null
+++ b/utils/rk27utils/rkusbtool/Makefile
@@ -0,0 +1,7 @@
+all: rkusbtool
+
+rkusbtool: rkusbtool.c
+ gcc -g -std=c99 -o $@ -W -Wall -lusb-1.0 -I/usr/include/libusb-1.0/ $^
+
+clean:
+ rm -fr rkusbtool
diff --git a/utils/rk27utils/rkusbtool/rkusbtool.c b/utils/rk27utils/rkusbtool/rkusbtool.c
new file mode 100644
index 0000000000..06fb7e860c
--- /dev/null
+++ b/utils/rk27utils/rkusbtool/rkusbtool.c
@@ -0,0 +1,388 @@
+/* on ubuntu compile with gcc -W rkusbtool.c -o rkusbtool -lusb-1.0 -I/usr/include/libusb-1.0/ */
+#include <libusb.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#define VERSION "v0.1"
+
+#define RETRY_MAX 5
+#define USB_TIMEOUT 512
+#define VENDORID 0x071b
+#define PRODUCTID 0x3203
+
+#define OUT_EP 0x01
+#define IN_EP 0x82
+
+#define CBW_SIGNATURE 0x43425355
+#define CSW_SIGNATURE 0x53425355
+#define SCSICMD_READ_12 0xa8
+
+/* rockchip specific commands */
+#define RK_CMD 0xe0
+#define RK_GET_VERSION 0xffffffff
+#define RK_SWITCH_ROCKUSB 0xfeffffff
+#define RK_CHECK_USB 0xfdffffff
+#define RK_OPEN_SYSDISK 0xfcffffff
+
+enum {
+ NONE = 0,
+ INFO = 1,
+ RKUSB = 2,
+ SYSDISK = 4,
+ CHECKUSB = 8
+};
+
+enum {
+ COMMAND_PASSED = 0,
+ COMMAND_FAILED = 1,
+ PHASE_ERROR = 2
+};
+
+struct CBWCB_t
+{
+ uint8_t cbCode;
+ uint8_t cbLun;
+ uint32_t LBA;
+ uint32_t cbLen;
+ uint8_t reseved;
+ uint8_t control;
+} __attribute__((__packed__));
+
+struct CBW_t
+{
+ uint32_t dCBWSignature;
+ uint32_t dCBWTag;
+ uint32_t dCBWDataTransferLength;
+ uint8_t bmCBWFlags;
+ uint8_t bCBWLUN;
+ uint8_t bCBWCBLength;
+ uint8_t CBWCB[16];
+} __attribute__((__packed__));
+
+struct CSW_t
+{
+ uint32_t dCSWSignature;
+ uint32_t dCSWTag;
+ uint32_t dCSWDataResidue;
+ uint8_t bCSWStatus;
+} __attribute__((__packed__));
+
+static int send_msc_cmd(libusb_device_handle *hdev, struct CBWCB_t *cbwcb, uint32_t data_len, uint32_t *reftag)
+{
+ struct CBW_t cbw;
+ int ret, repeat, transferred;
+ static uint32_t tag = 0xdaefbc01;
+
+ memset(&cbw, 0, sizeof(cbw));
+ cbw.dCBWSignature = CBW_SIGNATURE;
+ cbw.dCBWTag = tag++;
+ cbw.dCBWDataTransferLength = data_len;
+ cbw.bmCBWFlags = 0x80; /* device to host */
+ cbw.bCBWLUN = 0;
+ cbw.bCBWCBLength = sizeof(struct CBWCB_t);
+ memcpy(cbw.CBWCB, cbwcb, sizeof(struct CBWCB_t));
+
+ *reftag = cbw.dCBWTag;
+ do
+ {
+ /* transfer command to the device */
+ ret = libusb_bulk_transfer(hdev, OUT_EP, (unsigned char*)&cbw, 31, &transferred, USB_TIMEOUT);
+ if (ret == LIBUSB_ERROR_PIPE)
+ {
+ libusb_clear_halt(hdev, OUT_EP);
+ }
+ repeat++;
+ } while ((ret == LIBUSB_ERROR_PIPE) && (repeat < RETRY_MAX));
+
+ if (ret != LIBUSB_SUCCESS)
+ {
+ printf("error: command transfer error\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int get_msc_csw(libusb_device_handle *hdev, uint32_t reftag)
+{
+ struct CSW_t csw;
+ int ret, repeat, transferred;
+
+ /* get CSW response from device */
+ repeat = 0;
+ do
+ {
+ ret = libusb_bulk_transfer(hdev, IN_EP, (unsigned char *)&csw, 13, &transferred, USB_TIMEOUT);
+ if (ret == LIBUSB_ERROR_PIPE)
+ {
+ libusb_clear_halt(hdev, IN_EP);
+ }
+ repeat++;
+ } while ((ret == LIBUSB_ERROR_PIPE) && (repeat < RETRY_MAX));
+
+ if (ret != LIBUSB_SUCCESS)
+ {
+ printf("error reading CSW\n");
+ return -3;
+ }
+
+ if (transferred != 13)
+ {
+ printf("error wrong size of CSW packet\n");
+ return -4;
+ }
+
+ if (csw.dCSWSignature != CSW_SIGNATURE)
+ {
+ printf("error: wrong CSW signature.\n");
+ return -5;
+ }
+
+ if (csw.dCSWTag != reftag)
+ {
+ printf("error: CSW dCSWTag mismatch\n");
+ return -6;
+ }
+
+ if (csw.bCSWStatus)
+ {
+ /* In case of CSW indicating error dump the content of the packet */
+ printf ("dCSWSignature: 0x%0x\n", csw.dCSWSignature);
+ printf ("dCSWTag: 0x%0x\n", csw.dCSWTag);
+ printf ("dCSWDataResidue: 0x%0x\n", csw.dCSWDataResidue);
+ printf ("bCSWStatus: 0x%0x\n", csw.bCSWStatus);
+ }
+
+ return csw.bCSWStatus;
+}
+
+static int rk_cmd(libusb_device_handle *hdev, uint32_t command, uint8_t *buf, uint8_t len)
+{
+ struct CBWCB_t cbwcb;
+ int ret, transferred;
+ uint32_t reftag;
+
+ /* enter command */
+ memset(&cbwcb, 0, sizeof(cbwcb));
+ cbwcb.cbCode = SCSICMD_READ_12;
+ cbwcb.cbLun = RK_CMD;
+ cbwcb.LBA = command; /* RK_GET_VERSION, RK_OPEN_SYSDISK, RK_SWITCH_ROCKUSB */
+ cbwcb.cbLen = len; /* size of transfer in response to this command */
+
+ ret = send_msc_cmd(hdev, &cbwcb, len, &reftag);
+
+ /* get the response */
+ if (len > 0)
+ {
+ ret = libusb_bulk_transfer(hdev, IN_EP, buf, len, &transferred, USB_TIMEOUT);
+ if (ret != LIBUSB_SUCCESS || transferred != len)
+ {
+ printf("error: reading response data failed\n");
+ return -2;
+ }
+ }
+
+ return get_msc_csw(hdev, reftag);
+}
+
+static int get_sense(libusb_device_handle *hdev)
+{
+ struct CBWCB_t cbwcb;
+ unsigned char sense[0x12];
+ int size, ret;
+ uint32_t reftag;
+
+ memset(&cbwcb, 0, sizeof(cbwcb));
+ cbwcb.cbCode = 0x03;
+ cbwcb.cbLun = 0;
+ cbwcb.LBA = 0;
+ cbwcb.cbLen = 0x12;
+
+ ret = send_msc_cmd(hdev, &cbwcb, 0x12, &reftag);
+ libusb_bulk_transfer(hdev, IN_EP, (unsigned char*)&sense, 0x12, &size, USB_TIMEOUT);
+
+ return get_msc_csw(hdev, reftag);
+}
+
+static void usage(void)
+{
+ printf("Usage: rkusbtool [options]\n");
+ printf("-h|--help This help message\n");
+ printf("-i|--info Get version string from the device\n");
+ printf("-d|--dfu Put device into DFU mode\n");
+ printf("-s|--sysdisk Open system disk\n");
+ printf("-c|--checkusb Check if dev is in System or Loader USB mode\n");
+}
+
+int main (int argc, char **argv)
+{
+ libusb_device_handle *hdev;
+ int ret;
+ int i = 0, action = NONE;
+ uint32_t ver[3];
+
+ if (argc < 2)
+ {
+ usage();
+ return 1;
+ }
+
+ /* print banner */
+ fprintf(stderr,"rkusbtool " VERSION "\n");
+ fprintf(stderr,"(C) Marcin Bukat 2011\n");
+ fprintf(stderr,"This is free software; see the source for copying conditions. There is NO\n");
+ fprintf(stderr,"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
+
+ /* arguments handling */
+ while (i < argc)
+ {
+ if ((strcmp(argv[i],"-i")==0) || (strcmp(argv[i],"--info")==0))
+ {
+ action |= INFO;
+ }
+ else if ((strcmp(argv[i],"-d")==0) || (strcmp(argv[i],"--dfu")==0))
+ {
+ action |= RKUSB;
+ }
+ else if ((strcmp(argv[i],"-s")==0) || (strcmp(argv[i],"--sysdisk")==0))
+ {
+ action |= SYSDISK;
+ }
+ else if ((strcmp(argv[i],"-c")==0) || (strcmp(argv[i],"--checkusb")==0))
+ {
+ action |= CHECKUSB;
+ }
+ else if ((strcmp(argv[i],"-h")==0) || (strcmp(argv[i],"--help")==0))
+ {
+ usage();
+ return 0;
+ }
+ i++;
+ }
+
+ /* initialize libusb */
+ libusb_init(NULL);
+ /* usb_set_debug(2); */
+
+ hdev = libusb_open_device_with_vid_pid(NULL, VENDORID, PRODUCTID);
+ if (hdev == NULL)
+ {
+ printf("error: can't open device\n");
+ return -10;
+ }
+
+ ret = libusb_kernel_driver_active(hdev, 0);
+
+ if (ret < 0)
+ {
+ printf ("error checking kernel driver active\n");
+ libusb_close(hdev);
+ return -3;
+ }
+ else
+ {
+ if (ret)
+ libusb_detach_kernel_driver(hdev, 0);
+ }
+
+ ret = libusb_set_configuration(hdev, 1);
+ if (ret < 0)
+ {
+ printf("error: could not select configuration (1)\n");
+ libusb_close(hdev);
+ return -3;
+ }
+
+ ret = libusb_claim_interface(hdev, 0);
+ if (ret < 0)
+ {
+ printf("error: could not claim interface #0\n");
+ libusb_close(hdev);
+ return -11;
+ }
+
+ ret = libusb_set_interface_alt_setting(hdev, 0, 0);
+ if ( ret != LIBUSB_SUCCESS)
+ {
+ printf("error: could not set alt setting for interface #0\n");
+ libusb_close(hdev);
+ return -11;
+ }
+
+ /* BulkOnly reset */
+ //ret = libusb_control_transfer(hdev, 0x21, 0xff, 0, 0, NULL, 0, USB_TIMEOUT);
+
+ /* BulkOnly get max lun */
+ //ret = libusb_control_transfer(hdev, 0xa1, 0xfe, 0, 0, &maxlun, 1, USB_TIMEOUT);
+
+ /* Devices that do not support multiple LUNs may STALL this command. */
+ //if (ret == 0)
+ // maxlun = -1;
+
+ //printf("MAXLUN: %d\n", maxlun);
+
+ get_sense(hdev);
+
+ if (action & INFO)
+ {
+ ret = rk_cmd(hdev, RK_GET_VERSION, (uint8_t *)ver, 12);
+
+ if (ret)
+ {
+ printf("error sending RK_GET_VERSION command. Err 0x%0x\n", ret);
+ libusb_close(hdev);
+ return ret;
+ }
+
+ printf("Rockchip device info:\n");
+ printf("loader ver: %x.%x\n", (ver[0]>>16)&0xff, ver[0]&0xff);
+ printf("kernel ver: %x.%x\n", (ver[1]>>16)&0xff, ver[1]&0xff);
+ printf("sdk ver: %x.%x\n", (ver[2]>>16)&0xff, ver[2]&0xff);
+ }
+
+ if (action & CHECKUSB)
+ {
+ printf("Checking USB mode...\n");
+ ret = rk_cmd(hdev, RK_CHECK_USB, (uint8_t *)ver, 1);
+
+ //if (ret)
+ //{
+ // libusb_close(hdev);
+ // return ret;
+ //}
+
+ if (*(char *)ver)
+ printf("The device is in Loader USB mode\n");
+ else
+ printf("The device is in System USB mode\n");
+ }
+
+ if (action & SYSDISK)
+ {
+ printf("Opening system disk...\n");
+ ret = rk_cmd(hdev, RK_OPEN_SYSDISK, NULL, 0);
+
+ if (ret)
+ {
+ libusb_close(hdev);
+ return ret;
+ }
+ }
+
+ if (action & RKUSB)
+ {
+ printf("Switching into rk DFU mode...\n");
+ ret = rk_cmd(hdev, RK_SWITCH_ROCKUSB, NULL, 0);
+
+ if (ret)
+ {
+ libusb_close(hdev);
+ return ret;
+ }
+ }
+
+ libusb_close(hdev);
+ libusb_exit(NULL);
+ return 0;
+}