#include "UsbPhone.h" #include #include #include #ifndef WIN32 #include #endif #include #include "setup.h" #define NUL 0x00 #define STX 0x02 #define ETX 0x03 #define RS 0x1E #ifdef WIN32 #define _snprintf _snprintf_s #else #define _snprintf(a, b, c, ...) snprintf(a, b, __VA_ARGS__) #endif int UsbPhone::ezx_blob_recv_reply(char *b) { char buf[8192]; int ret; memset(buf, 0, sizeof(buf)); ret = usb_bulk_read(handle, type->in_ep, buf, sizeof(buf), 5000); if (b) memcpy(b, buf, 8192); if (buf[1] == 0x45 && buf[2] == 0x52 && buf[3] == 0x52) ret = -buf[5]; return ret; } int UsbPhone::ezx_blob_send_command(const char *command, const char *payload, int len, char *reply) { char buf[8192]; size_t cmdlen = strlen(command); size_t index = 0; int ret; memset(buf, 0, sizeof(buf)); buf[index++] = STX; memcpy(&buf[index], command, cmdlen); index += cmdlen; if (payload) { buf[index++] = RS; memcpy(&buf[index], payload, len); index += len; } buf[index++] = ETX; ret = usb_bulk_write(handle, type->out_ep, buf, (int)index, 50000); if (ret < 0) return ret; return ezx_blob_recv_reply(reply); } /* the most secure checksum I've ever seen ;) */ unsigned char UsbPhone::ezx_csum(const char *data, int len) { unsigned char ret = 0; int i; for (i = 0; i < len; i++) ret += data[i]; return ret; } int UsbPhone::ezx_blob_cmd_addr(unsigned int addr) { char buf[128]; unsigned char csum; int len; len = _snprintf(buf, sizeof(buf), sizeof(buf), "%08X", addr); csum = ezx_csum(buf, 8); len += _snprintf(buf+8, sizeof(buf)-len, sizeof(buf)-len, "%02X", csum); if (len != 10) return -1; return ezx_blob_send_command("ADDR", buf, len, NULL); } int UsbPhone::ezx_blob_cmd_jump(unsigned int addr) { char buf[128]; unsigned char csum; int len; len = _snprintf(buf, sizeof(buf), sizeof(buf), "%08X", addr); csum = ezx_csum(buf, 8); len += _snprintf(buf+8, sizeof(buf)-len, sizeof(buf)-len, "%02X", csum); if (len != 10) return -1; return ezx_blob_send_command("JUMP", buf, len, NULL); } int UsbPhone::ezx_blob_cmd_rbin(unsigned int addr, unsigned short size, unsigned char *response) { char buf[128]; char reply[8192]; unsigned char *data; unsigned char csum; int len, i; int err; len = _snprintf(buf, sizeof(buf), sizeof(buf), "%08X%04X", addr, size); csum = ezx_csum(buf, 12); len += _snprintf(buf+12, sizeof(buf)-len, sizeof(buf)-len, "%02X", csum); if (len != 14) return -1; err = ezx_blob_send_command("RBIN", buf, len, reply); if (err < 0) return err; csum = 0; data = (unsigned char *)reply + 6; for (i = 0; i < size; i++) { response[i] = data[i]; csum += data[i]; } if (csum != data[i]) return -1; return 0; } int UsbPhone::ezx_blob_cmd_bin(const char *data, unsigned short size) { char buf[8192+2+1]; size += (size % 8) ? (8 - (size % 8)) : 0; if (size > 8192) return -1; memset(buf, 0, sizeof(buf)); *(unsigned short *)buf = htons(size); memcpy(buf+2, data, size); buf[size+2] = ezx_csum(data, size); return ezx_blob_send_command("BIN", buf, size+3, NULL); } int UsbPhone::ezx_blob_cmd_flash(unsigned int source, unsigned int dest, unsigned int size) { char buf[128]; unsigned char csum; int len; len = _snprintf(buf, sizeof(buf), sizeof(buf), "%08X", source); len += _snprintf(buf+8, sizeof(buf)-len, sizeof(buf)-len, "%08X", dest); len += _snprintf(buf+16, sizeof(buf)-len, sizeof(buf)-len, "%08X", size); csum = ezx_csum(buf, 24); len += _snprintf(buf+24, sizeof(buf)-len, sizeof(buf)-len, "%02X", csum); if (len != 26) return -1; return ezx_blob_send_command("FLASH", buf, len, NULL); } #define CHUNK_SIZE 4096 int UsbPhone::ezx_blob_dload_program(unsigned int addr, char *data, int size) { unsigned int cur_addr; const char *cur_data; int err = -1; for (cur_addr = addr, cur_data = data; cur_addr < addr+size; cur_addr += CHUNK_SIZE, cur_data += CHUNK_SIZE) { int remain = (int)((data + size) - cur_data); if (remain > CHUNK_SIZE) remain = CHUNK_SIZE; if ((err = ezx_blob_cmd_rbin(cur_addr, remain, (unsigned char *)cur_data)) < 0) break; } if (err < 0) return err; return 0; } int UsbPhone::ezx_blob_load_program(unsigned short phone_id, unsigned int addr, const char *data, int size) { unsigned int cur_addr; const char *cur_data; int err = -1; if(!addr) /* workaround for missing values */ return -1; for (cur_addr = addr, cur_data = data; cur_addr < addr+size; cur_addr += CHUNK_SIZE, cur_data += CHUNK_SIZE) { int remain; if (phone_id == 0x6023) /* A1200 needs a fixed chunk size*/ remain = 4096; else remain = int((data + size) - cur_data); if (remain > CHUNK_SIZE) remain = CHUNK_SIZE; if ((err = ezx_blob_cmd_addr(cur_addr)) < 0) break; if ((err = ezx_blob_cmd_bin(cur_data, remain)) < 0) break; } if (err < 0) return err; return 0; } #define FLASH_BLOCK_SIZE 0x20000 /* 128k */ #define MAX_FLASH_SIZE 0x20000 /* 512k */ #define FLASH_TEMP_ADDR 0xa0400000 int UsbPhone::ezx_blob_flash_program(unsigned int addr, const char *data, int size) { unsigned int cur_addr; const char *cur_data; int pad = (size % FLASH_BLOCK_SIZE) ? (FLASH_BLOCK_SIZE - (size % FLASH_BLOCK_SIZE)) : 0; for (cur_addr = addr, cur_data = data; cur_addr < (addr + size); cur_addr += MAX_FLASH_SIZE, cur_data += MAX_FLASH_SIZE) { int remain = int((data + size) - cur_data); remain = (remain > MAX_FLASH_SIZE) ? MAX_FLASH_SIZE : remain; if (ezx_blob_load_program(0xbeef, FLASH_TEMP_ADDR, cur_data, remain) < 0) return -1; /* pad up to flash block size */ remain += pad; if (ezx_blob_cmd_flash(FLASH_TEMP_ADDR, cur_addr, remain) < 0) return -1; } return 0; } UsbPhone::UsbPhone(const struct phonetype *type, usb_dev_handle *handle) :protect_addr(0xa0000) { int ret=0; this->type = type; this->handle = handle; ret=usb_set_configuration(handle, 1); ret=usb_claim_interface(handle, 0); } UsbPhone::~UsbPhone(void) { usb_close(handle); } int UsbPhone::bootLinux(const char * kernelFileName, unsigned int machine_id, const char * cmdLine, const char *ramdiskFileName) { int kOffset = 0; if(machine_id && type->code_size){ kOffset += 4096; char *asm_code = new char[CHUNK_SIZE]; memset(asm_code, 0, CHUNK_SIZE); memcpy(asm_code, type->code, type->code_size); *(unsigned int *)(asm_code+type->code_size) = machine_id; ezx_blob_load_program(type->product_id, type->kernel_addr, asm_code, CHUNK_SIZE); delete asm_code; } QFile kernelFile(kernelFileName); QFile ramdiskFile(ramdiskFileName); kernelFile.open(QIODevice::ReadOnly); uchar *kernelCode =kernelFile.map(0, kernelFile.size()); ezx_blob_load_program(type->product_id, type->kernel_addr + kOffset, (const char *)kernelCode, (int)kernelFile.size()); kernelFile.unmap(kernelCode); uchar *ramdiskCode = NULL; struct tag *tag; struct tag *first_tag; int tagsize; /* we will always send at least 4 tags (core + (2 * mem) + none) */ tagsize = (sizeof(struct tag_header) * 4) + sizeof(struct tag_core) + (sizeof(struct tag_mem32) * 2); if(strlen(cmdLine)) tagsize += int(sizeof(struct tag_header) + ((strlen(cmdLine) + 5) > COMMAND_LINE_SIZE ? COMMAND_LINE_SIZE : strlen(cmdLine) + 5)); if(strlen(ramdiskFileName)) tagsize += sizeof(struct tag_header) + sizeof(struct tag_initrd); if (!(tag = (struct tag *)new char[tagsize])) { goto exit; } first_tag = tag; tag->hdr.tag = ATAG_CORE; tag->hdr.size = tag_size(tag_core); tag->u.core.flags = 0; tag->u.core.pagesize = 0; tag->u.core.rootdev = 0; tag = tag_next(tag); tag->hdr.tag = ATAG_MEM; tag->hdr.size = tag_size(tag_mem32); tag->u.mem.start = 0xa0000000; tag->u.mem.size = 32 * 1024 * 1024; tag = tag_next(tag); tag->hdr.tag = ATAG_MEM; tag->hdr.size = tag_size(tag_mem32); tag->u.mem.start = 0xac000000; tag->u.mem.size = 16 * 1024 * 1024; if (!strlen(cmdLine)) goto send_params; tag = tag_next(tag); tag->hdr.tag = ATAG_CMDLINE; tag->hdr.size = (int)(((sizeof(struct tag_header) + strlen(cmdLine) + 5) >> 2)); strcpy(tag->u.cmdline.cmdline, cmdLine); if (!strlen(ramdiskFileName)) goto send_params; ramdiskFile.open(QIODevice::ReadOnly); ramdiskCode = ramdiskFile.map(0, ramdiskFile.size()); ezx_blob_load_program(type->product_id, type->initrd_addr, (const char *)ramdiskCode, (int)ramdiskFile.size()); ramdiskFile.unmap(ramdiskCode); tag = tag_next(tag); tag->hdr.tag = ATAG_INITRD2; tag->hdr.size = tag_size(tag_initrd); tag->u.initrd.start = type->initrd_addr; tag->u.initrd.size = (unsigned int)ramdiskFile.size(); send_params: tag = tag_next(tag); tag->hdr.tag = ATAG_NONE; tag->hdr.size = 0; ezx_blob_load_program(type->product_id, type->params_addr, (char *) first_tag, tagsize); delete first_tag; ezx_blob_cmd_jump(type->kernel_addr); return 0; exit: return 0; }