Root/xbboot/host-app/host_main.c

1//
2// Authors: Wolfgang Spraul <wolfgang@sharism.cc>
3// Authors: Xiangfu Liu <xiangfu@sharism.cc>
4//
5// This program is free software; you can redistribute it and/or
6// modify it under the terms of the GNU General Public License
7// as published by the Free Software Foundation; either version
8// 3 of the License, or (at your option) any later version.
9//
10
11#include <stdio.h>
12#include <stdint.h>
13#include <string.h>
14#include <usb.h>
15#include <time.h>
16#include "xbboot_version.h"
17
18#define HIWORD(dw) (((dw) >> 16) & 0xFFFF)
19#define LOWORD(dw) ((dw) & 0xFFFF)
20
21#define INGENIC_VENDOR_ID 0x601A
22#define INGENIC_XBURST_JZ4740 0x4740
23#define INGENIC_XBURST_JZ4760 0x4760
24
25// REQ_ values are negative so they can be mixed together with the VR_ types in a signed integer.
26#define REQ_BULK_READ -1
27#define REQ_BULK_WRITE -2
28
29#define VR_GET_CPU_INFO 0x00
30#define VR_SET_DATA_ADDRESS 0x01
31#define VR_SET_DATA_LENGTH 0x02
32#define VR_FLUSH_CACHES 0x03
33#define VR_PROGRAM_START1 0x04
34#define VR_PROGRAM_START2 0x05
35#define VR_NOR_OPS 0x06
36#define VR_NAND_OPS 0x07
37#define VR_SDRAM_OPS 0x08
38#define VR_CONFIGRATION 0x09
39#define VR_GET_NUM 0x0a
40
41#define USB_TIMEOUT 3000
42#define VR_GET_CPU_INFO_LEN 8
43#define INGENIC_IN_ENDPOINT 0x81
44#define INGENIC_OUT_ENDPOINT 0x01
45
46#define STAGE1_FILE_PATH (DATADIR "stage1.bin")
47#define STAGE1_ADDRESS ("0x80002000")
48
49uint8_t xburst_interface = 0;
50uint8_t option_upload = 0;
51uint16_t xburst_cpu = INGENIC_XBURST_JZ4760;
52
53struct usb_dev_handle* open_xburst_device();
54void close_xburst_device(struct usb_dev_handle* xburst_h);
55int send_request(struct usb_dev_handle* xburst_h, char* request, char* str_param);
56void show_help();
57
58int main(int argc, char** argv)
59{
60    struct usb_dev_handle* xburst_h;
61
62    if (argc < 2
63        || !strcmp(argv[1], "-h")
64        || !strcmp(argv[1], "--help")) {
65        show_help();
66        return EXIT_SUCCESS;
67    }
68    if (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version")) {
69        printf("xbboot version %s\n", XBBOOT_VERSION);
70        return EXIT_SUCCESS;
71    }
72
73    if ((getuid()) || (getgid())) {
74        fprintf(stderr, "Error - you must be root to run '%s'\n", argv[0]);
75        return EXIT_FAILURE;
76    }
77
78    if (!strcmp(argv[1], "-u") || !strcmp(argv[1], "--upload")) {
79        if (argc != 4) {
80            show_help();
81            goto xquit;
82        }
83
84        option_upload = 1;
85        struct timespec timx,tim1;
86
87        tim1.tv_sec = 1;
88        tim1.tv_nsec = 0;
89        while(1) {
90            nanosleep(&tim1,&timx);
91
92            xburst_h = open_xburst_device();
93            if (xburst_h) {
94                printf("\nInfo - found XBurst boot device.\n");
95                if (send_request(xburst_h, "set_addr", STAGE1_ADDRESS)) {
96                    close_xburst_device(xburst_h);
97                    continue;
98                }
99                if (send_request(xburst_h, "bulk_write", STAGE1_FILE_PATH)) {
100                    close_xburst_device(xburst_h);
101                    continue;
102                }
103                if (send_request(xburst_h, "start1", STAGE1_ADDRESS)) {
104                    close_xburst_device(xburst_h);
105                    continue;
106                }
107                if (send_request(xburst_h, "get_info", "NULL")) {
108                    close_xburst_device(xburst_h);
109                    continue;
110                }
111                if (send_request(xburst_h, "set_addr", argv[2])) {
112                    close_xburst_device(xburst_h);
113                    continue;
114                }
115                if (send_request(xburst_h, "bulk_write", argv[3])) {
116                    close_xburst_device(xburst_h);
117                    continue;
118                }
119                if (send_request(xburst_h, "flush_cache","NULL")) {
120                    close_xburst_device(xburst_h);
121                    continue;
122                }
123                if (send_request(xburst_h, "start2", argv[2])) {
124                    close_xburst_device(xburst_h);
125                    continue;
126                }
127
128                goto xquit;
129            }
130        }
131    }
132
133    xburst_h = open_xburst_device();
134    if (xburst_h)
135        if (send_request(xburst_h, argv[1], (argc == 2 ? NULL : argv[2]))) {
136            close_xburst_device(xburst_h);
137            return EXIT_FAILURE;
138        }
139xquit:
140    close_xburst_device(xburst_h);
141    return EXIT_SUCCESS;
142}
143
144
145void close_xburst_device(struct usb_dev_handle* xburst_h)
146{
147        if (xburst_h && xburst_interface)
148        usb_release_interface(xburst_h, xburst_interface);
149
150        if (xburst_h)
151        usb_close(xburst_h);
152}
153
154struct usb_dev_handle* open_xburst_device()
155{
156    struct usb_device* xburst_dev = 0;
157    struct usb_dev_handle* xburst_h = 0;
158
159    usb_init();
160    /* usb_set_debug(255); */
161    usb_find_busses();
162    usb_find_devices();
163
164    // look for Ingenic XBurst USB boot device & interface
165    {
166        {
167            struct usb_bus* usb_bus;
168            struct usb_device* usb_dev;
169
170            for (usb_bus = usb_get_busses(); usb_bus != 0; usb_bus = usb_bus->next) {
171                for (usb_dev = usb_bus->devices; usb_dev != 0; usb_dev = usb_dev->next) {
172                    if (usb_dev->descriptor.idVendor == INGENIC_VENDOR_ID) {
173                        if (usb_dev->descriptor.idProduct == INGENIC_XBURST_JZ4740 ||
174                            usb_dev->descriptor.idProduct == INGENIC_XBURST_JZ4760) {
175                            if (xburst_dev) {
176                                fprintf(stderr, "Error - more than one XBurst boot device found.\n");
177                                goto xout;
178                            }
179                            xburst_dev = usb_dev;
180                            xburst_cpu = usb_dev->descriptor.idProduct;
181                            // keep searching to make sure there is only 1 XBurst device
182                        }
183                    }
184                }
185            }
186            if (!xburst_dev) {
187                fprintf(stderr, "Info - no XBurst boot device found.\n");
188                goto xout;
189            }
190        }
191        {
192            struct usb_config_descriptor* usb_config_desc;
193            struct usb_interface_descriptor* usb_if_desc;
194            struct usb_interface* usb_if;
195            int cfg_index, if_index, alt_index;
196
197            for (cfg_index = 0; cfg_index < xburst_dev->descriptor.bNumConfigurations; cfg_index++) {
198                usb_config_desc = &xburst_dev->config[cfg_index];
199                if (!usb_config_desc) {
200                    fprintf(stderr, "Error - usb_config_desc NULL\n");
201                    goto xout;
202                }
203                for (if_index = 0; if_index < usb_config_desc->bNumInterfaces; if_index++) {
204                    usb_if = &usb_config_desc->interface[if_index];
205                    if (!usb_if) {
206                        fprintf(stderr, "Error - usb_if NULL\n");
207                        goto xout;
208                    }
209                    for (alt_index = 0; alt_index < usb_if->num_altsetting; alt_index++) {
210                        usb_if_desc = &usb_if->altsetting[alt_index];
211                        if (!usb_if_desc) {
212                            fprintf(stderr, "Error - usb_if_desc NULL\n");
213                            goto xout;
214                        }
215                        if (usb_if_desc->bInterfaceClass == 0xFF
216                            && usb_if_desc->bInterfaceSubClass == 0) {
217                            xburst_interface = usb_if_desc->bInterfaceNumber;
218                            goto interface_found;
219                        }
220                    }
221                }
222            }
223        interface_found: ;
224        }
225    }
226    xburst_h = usb_open(xburst_dev);
227    if (!xburst_h) {
228        fprintf(stderr, "Error - can't open XBurst device: %s\n", usb_strerror());
229        goto xout;
230    }
231    if (usb_claim_interface(xburst_h, xburst_interface) < 0) {
232        fprintf(stderr, "Error - can't claim XBurst interface: %s\n", usb_strerror());
233        goto xout_xburst_h;
234    }
235
236    return xburst_h;
237
238xout_xburst_h:
239    usb_close(xburst_h);
240xout:
241    return NULL;
242}
243
244int send_request(struct usb_dev_handle* xburst_h, char* request, char* str_param)
245{
246    int request_type;
247    int usb_status;
248    uint32_t u32_param;
249
250    if (!strcmp(request, "bulk_read"))
251        request_type = REQ_BULK_READ;
252    else if (!strcmp(request, "bulk_write"))
253        request_type = REQ_BULK_WRITE;
254    else if (!strcmp(request, "VR_GET_CPU_INFO") || !strcmp(request, "get_info"))
255        request_type = VR_GET_CPU_INFO;
256    else if (!strcmp(request, "VR_SET_DATA_ADDRESS") || !strcmp(request, "set_addr"))
257        request_type = VR_SET_DATA_ADDRESS;
258    else if (!strcmp(request, "VR_SET_DATA_LENGTH") || !strcmp(request, "set_len"))
259        request_type = VR_SET_DATA_LENGTH;
260    else if (!strcmp(request, "VR_FLUSH_CACHES") || !strcmp(request, "flush_cache"))
261        request_type = VR_FLUSH_CACHES;
262    else if (!strcmp(request, "VR_PROGRAM_START1") || !strcmp(request, "start1"))
263        request_type = VR_PROGRAM_START1;
264    else if (!strcmp(request, "VR_PROGRAM_START2") || !strcmp(request, "start2"))
265        request_type = VR_PROGRAM_START2;
266    else {
267        fprintf(stderr, "Error - unknown vendor request %s - run with --help to see all requests\n", request);
268        return 1;
269    }
270
271    switch (request_type) {
272        case VR_GET_CPU_INFO: {
273            char cpu_info_buf[VR_GET_CPU_INFO_LEN+1] = {0};
274            usb_status = usb_control_msg(xburst_h,
275                /* requesttype */ USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
276                /* request */ VR_GET_CPU_INFO,
277                /* value */ 0,
278                /* index */ 0,
279                /* bytes */ cpu_info_buf,
280                /* size */ VR_GET_CPU_INFO_LEN,
281                /* timeout */ USB_TIMEOUT);
282
283            if (usb_status != VR_GET_CPU_INFO_LEN) {
284                fprintf(stderr, "Error - %s() returned %i\n", request, usb_status);
285                goto xout_xburst_interface;
286            }
287            printf("VR_GET_CPU_INFO %s\n", cpu_info_buf);
288            break;
289        }
290        case VR_SET_DATA_ADDRESS:
291        case VR_SET_DATA_LENGTH:
292        case VR_PROGRAM_START1:
293        case VR_PROGRAM_START2: {
294            if (str_param == NULL) {
295                fprintf(stderr, "Error - number of parameters %s\n", request);
296                goto xout_xburst_interface;
297            }
298
299            u32_param = strtoul(str_param, 0, 0);
300            usb_status = usb_control_msg(xburst_h,
301                /* requesttype */ USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
302                /* request */ request_type,
303                /* value */ HIWORD(u32_param),
304                /* index */ LOWORD(u32_param),
305                /* bytes */ 0,
306                /* size */ 0,
307                /* timeout */ USB_TIMEOUT);
308            if (usb_status) {
309                fprintf(stderr, "Error - %s() returned %i\n", request, usb_status);
310                goto xout_xburst_interface;
311            }
312            printf("%s %lxh\n", request, (unsigned long) u32_param);
313            break;
314        }
315        case VR_FLUSH_CACHES: {
316            usb_status = usb_control_msg(xburst_h,
317                /* requesttype */ USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
318                /* request */ VR_FLUSH_CACHES,
319                /* value */ 0,
320                /* index */ 0,
321                /* bytes */ 0,
322                /* size */ 0,
323                /* timeout */ USB_TIMEOUT);
324            if (usb_status) {
325                fprintf(stderr, "Error - %s() returned %i\n", request, usb_status);
326                goto xout_xburst_interface;
327            }
328            printf("VR_FLUSH_CACHES\n");
329            break;
330        }
331        case REQ_BULK_READ: {
332            int read_len;
333            char* read_buf;
334
335            if (str_param == NULL) {
336                fprintf(stderr, "Error - number of parameters %s\n", request);
337                goto xout_xburst_interface;
338            }
339
340            if (str_param[0] == '0' && str_param[1] == 'x')
341                read_len = strtol(&str_param[2], 0, 16);
342            else
343                read_len = strtol(str_param, 0, 10);
344
345            read_buf = (char*) malloc(read_len);
346            if (!read_buf) {
347                fprintf(stderr, "Error - cannot allocate %i bytes read buffer.\n", read_len);
348                goto xout_xburst_interface;
349            }
350            usb_status = usb_bulk_read(xburst_h,
351                /* endpoint */ INGENIC_IN_ENDPOINT,
352                /* bytes */ read_buf,
353                /* size */ read_len,
354                /* timeout */ USB_TIMEOUT);
355            if (usb_status > 0)
356                fwrite(read_buf, 1 /* size */, usb_status, stdout);
357            free(read_buf);
358            if (usb_status < read_len) {
359                fprintf(stderr, "Error reading %d bytes (result %i).\n", read_len, usb_status);
360                goto xout_xburst_interface;
361            }
362            break;
363        }
364        case REQ_BULK_WRITE: {
365            char* file_data;
366            int file_len;
367            FILE* file_h;
368            size_t num_read;
369
370            if (str_param == NULL) {
371                fprintf(stderr, "Error - number of parameters %s\n", request);
372                goto xout_xburst_interface;
373            }
374            file_h = fopen(str_param, "rb");
375            if (!file_h) {
376                fprintf(stderr, "Error opening %s.\n", str_param);
377                goto xout_xburst_interface;
378            }
379            if (fseek(file_h, 0, SEEK_END)) {
380                fprintf(stderr, "Error seeking to end of %s.\n", str_param);
381                fclose(file_h);
382                goto xout_xburst_interface;
383            }
384            file_len = ftell(file_h);
385            if (fseek(file_h, 0, SEEK_SET)) {
386                fprintf(stderr, "Error seeking to beginning of %s.\n", str_param);
387                fclose(file_h);
388                goto xout_xburst_interface;
389            }
390            file_data = (char*) malloc(file_len);
391            if (!file_data) {
392                fprintf(stderr, "Error allocating %d bytes data.\n", file_len);
393                fclose(file_h);
394                goto xout_xburst_interface;
395            }
396            num_read = fread(file_data, 1, file_len, file_h);
397            fclose(file_h);
398            if (num_read != (size_t) file_len) {
399                fprintf(stderr, "Error reading %d bytes (got %d).\n", file_len, num_read);
400                free(file_data);
401                goto xout_xburst_interface;
402            }
403            {
404                if(option_upload) {
405                    memcpy(file_data + 8, &xburst_cpu, sizeof(unsigned int));
406                    option_upload = 0;
407                }
408            }
409            usb_status = usb_bulk_write(xburst_h,
410                /* endpoint */ INGENIC_OUT_ENDPOINT,
411                /* bytes */ file_data,
412                /* size */ file_len,
413                /* timeout */ USB_TIMEOUT);
414            free(file_data);
415            if (usb_status < file_len) {
416                fprintf(stderr, "Error writing %d bytes (result %i).\n", file_len, usb_status);
417                goto xout_xburst_interface;
418            }
419            printf("bulk_write successfully wrote %i bytes.\n", usb_status);
420            break;
421        }
422    }
423
424    usleep(100);
425    return 0;
426
427xout_xburst_interface:
428    return 1;
429}
430
431void show_help()
432{
433    printf("\n"
434           "xbboot version %s - Ingenic XBurst USB Boot Vendor Requests\n"
435           "(c) 2009 Wolfgang Spraul\n"
436           "Report bugs to <wolfgang@sharism.cc>, <xiangfu@sharism.cc>.\n"
437           "\n"
438           "xbboot [vendor_request] ... (must run as root)\n"
439           " -h --help print this help message\n"
440           " -v --version print the version number\n"
441           " [-u | --upload] <address> <path> upload file at <path> to <address> then jump to <address>\n"
442           "\n"
443           " bulk_read <len> read len bulk bytes from USB, write to stdout\n"
444           " bulk_write <path> write file at <path> to USB\n"
445           " [get_info | VR_GET_CPU_INFO] read 8-byte CPU info and write to stdout\n"
446           " [set_addr | VR_SET_DATA_ADDRESS] <addr> send memory address\n"
447           " [set_len | VR_SET_DATA_LENGTH] <len> send data length\n"
448           " [flush_cache | VR_FLUSH_CACHES] flush I-Cache and D-Cache\n"
449           " [start1 | VR_PROGRAM_START1] <addr> transfer data from D-Cache to I-Cache and branch to I-Cache\n"
450           " [start2 | VR_PROGRAM_START2] <addr> branch to <addr> directly\n"
451           "\n"
452           "- all numbers can be prefixed 0x for hex otherwise decimal\n"
453           "\n", XBBOOT_VERSION);
454}
455

Archive Download this file



interactive