forked from len0rd/rockbox
Rockchip rk27xx utils
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29936 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
976a1699da
commit
8f4202db28
28 changed files with 1845 additions and 0 deletions
37
utils/rk27utils/README
Normal file
37
utils/rk27utils/README
Normal file
|
|
@ -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.
|
||||||
7
utils/rk27utils/rk27load/Makefile
Normal file
7
utils/rk27utils/rk27load/Makefile
Normal file
|
|
@ -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
|
||||||
35
utils/rk27utils/rk27load/checksum.c
Normal file
35
utils/rk27utils/rk27load/checksum.c
Normal file
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
1
utils/rk27utils/rk27load/checksum.h
Normal file
1
utils/rk27utils/rk27load/checksum.h
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uint16_t checksum(void *buff, uint32_t size);
|
||||||
16
utils/rk27utils/rk27load/common.c
Normal file
16
utils/rk27utils/rk27load/common.c
Normal file
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
1
utils/rk27utils/rk27load/common.h
Normal file
1
utils/rk27utils/rk27load/common.h
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uint32_t filesize(FILE * f);
|
||||||
165
utils/rk27utils/rk27load/main.c
Normal file
165
utils/rk27utils/rk27load/main.c
Normal file
|
|
@ -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;
|
||||||
|
}
|
||||||
11
utils/rk27utils/rk27load/rk27load.h
Normal file
11
utils/rk27utils/rk27load/rk27load.h
Normal file
|
|
@ -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
|
||||||
|
|
||||||
46
utils/rk27utils/rk27load/scramble.c
Normal file
46
utils/rk27utils/rk27load/scramble.c
Normal file
|
|
@ -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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
1
utils/rk27utils/rk27load/scramble.h
Normal file
1
utils/rk27utils/rk27load/scramble.h
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
void scramble(uint8_t *in, uint8_t *out, const int size);
|
||||||
48
utils/rk27utils/rk27load/stage1/Makefile
Normal file
48
utils/rk27utils/rk27load/stage1/Makefile
Normal file
|
|
@ -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
|
||||||
42
utils/rk27utils/rk27load/stage1/main.S
Normal file
42
utils/rk27utils/rk27load/stage1/main.S
Normal file
|
|
@ -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 */
|
||||||
23
utils/rk27utils/rk27load/stage1/stage1.lds
Normal file
23
utils/rk27utils/rk27load/stage1/stage1.lds
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
113
utils/rk27utils/rk27load/stage1_upload.c
Normal file
113
utils/rk27utils/rk27load/stage1_upload.c
Normal file
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
3
utils/rk27utils/rk27load/stage1_upload.h
Normal file
3
utils/rk27utils/rk27load/stage1_upload.h
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
int upload_stage1_code(libusb_device_handle * hdev, char *fn_stage1,
|
||||||
|
bool do_scramble);
|
||||||
|
|
||||||
48
utils/rk27utils/rk27load/stage2/Makefile
Normal file
48
utils/rk27utils/rk27load/stage2/Makefile
Normal file
|
|
@ -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
|
||||||
55
utils/rk27utils/rk27load/stage2/crt0.S
Normal file
55
utils/rk27utils/rk27load/stage2/crt0.S
Normal file
|
|
@ -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
|
||||||
103
utils/rk27utils/rk27load/stage2/irq.S
Normal file
103
utils/rk27utils/rk27load/stage2/irq.S
Normal file
|
|
@ -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}
|
||||||
89
utils/rk27utils/rk27load/stage2/main.S
Normal file
89
utils/rk27utils/rk27load/stage2/main.S
Normal file
|
|
@ -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)
|
||||||
40
utils/rk27utils/rk27load/stage2/stage2.lds
Normal file
40
utils/rk27utils/rk27load/stage2/stage2.lds
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
102
utils/rk27utils/rk27load/stage2_upload.c
Normal file
102
utils/rk27utils/rk27load/stage2_upload.c
Normal file
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
3
utils/rk27utils/rk27load/stage2_upload.h
Normal file
3
utils/rk27utils/rk27load/stage2_upload.h
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
int upload_stage2_code(libusb_device_handle * hdev, char *fn_stage2,
|
||||||
|
bool do_scramble);
|
||||||
|
|
||||||
93
utils/rk27utils/rk27load/stage3_upload.c
Normal file
93
utils/rk27utils/rk27load/stage3_upload.c
Normal file
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
1
utils/rk27utils/rk27load/stage3_upload.h
Normal file
1
utils/rk27utils/rk27load/stage3_upload.h
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
int upload_stage3_code(libusb_device_handle *hdev, char *fn_stage3);
|
||||||
7
utils/rk27utils/rkboottool/Makefile
Normal file
7
utils/rk27utils/rkboottool/Makefile
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
all: rkboottool
|
||||||
|
|
||||||
|
rkboottool: rkboottool.c
|
||||||
|
gcc -g -std=c99 -o $@ -W -Wall $^
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -fr rkboottool
|
||||||
360
utils/rk27utils/rkboottool/rkboottool.c
Normal file
360
utils/rk27utils/rkboottool/rkboottool.c
Normal file
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
7
utils/rk27utils/rkusbtool/Makefile
Normal file
7
utils/rk27utils/rkusbtool/Makefile
Normal file
|
|
@ -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
|
||||||
388
utils/rk27utils/rkusbtool/rkusbtool.c
Normal file
388
utils/rk27utils/rkusbtool/rkusbtool.c
Normal file
|
|
@ -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;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue