X-Git-Url: https://git.kernelconcepts.de/?a=blobdiff_plain;f=common%2Fcmd_bootce.c;h=8e4ad20788b804db9af60afb7173a2cfbb3376d1;hb=59572eb941a444171421e8a7ebb308d254d665c4;hp=78bed8da40fb53054e27652910961b0ab9f64955;hpb=56b0f39408c3d78dacb02db88de15e669dff9669;p=karo-tx-uboot.git diff --git a/common/cmd_bootce.c b/common/cmd_bootce.c index 78bed8da40..8e4ad20788 100644 --- a/common/cmd_bootce.c +++ b/common/cmd_bootce.c @@ -25,7 +25,10 @@ #include #include #include +#include +#include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -33,7 +36,7 @@ DECLARE_GLOBAL_DATA_PTR; #define CE_FIX_ADDRESS(a) ((void *)((a) - WINCE_VRAM_BASE + CONFIG_SYS_SDRAM_BASE)) #ifndef INT_MAX -#define INT_MAX ((1U << (sizeof(int) * 8 - 1)) - 1) +#define INT_MAX ((int)(~0U >> 1)) #endif /* Bin image parse states */ @@ -47,20 +50,9 @@ DECLARE_GLOBAL_DATA_PTR; #define CE_MIN(a, b) (((a) < (b)) ? (a) : (b)) #define CE_MAX(a, b) (((a) > (b)) ? (a) : (b)) -#define _STRMAC(s) #s -#define STRMAC(s) _STRMAC(s) - static ce_bin __attribute__ ((aligned (32))) g_bin; static ce_net __attribute__ ((aligned (32))) g_net; - -static inline void print_IPaddr(IPaddr_t ip) -{ - printf("%d.%d.%d.%d", - ip & 0xff, - (ip >> 8) & 0xff, - (ip >> 16) & 0xff, - (ip >> 24) & 0xff); -} +static struct in_addr server_ip; static void ce_init_bin(ce_bin *bin, unsigned char *dataBuffer) { @@ -128,8 +120,7 @@ static inline void ce_dump_block(void *ptr, int length) } #endif -static void ce_setup_std_drv_globals(ce_std_driver_globals *std_drv_glb, - ce_bin *bin) +static void ce_setup_std_drv_globals(ce_std_driver_globals *std_drv_glb) { char *mtdparts = getenv("mtdparts"); size_t max_len = ALIGN((unsigned long)std_drv_glb, SZ_4K) - @@ -142,9 +133,9 @@ static void ce_setup_std_drv_globals(ce_std_driver_globals *std_drv_glb, snprintf(std_drv_glb->deviceId, sizeof(std_drv_glb->deviceId), "Triton%02X", eth_get_dev()->enetaddr[5]); - std_drv_glb->kitl.ipAddress = gd->bd->bi_ip_addr; - std_drv_glb->kitl.ipMask = getenv_IPaddr("netmask"); - std_drv_glb->kitl.ipRoute = getenv_IPaddr("gatewayip"); + net_copy_ip(&std_drv_glb->kitl.ipAddress, &net_ip); + std_drv_glb->kitl.ipMask = getenv_ip("netmask"); + std_drv_glb->kitl.ipRoute = getenv_ip("gatewayip"); if (mtdparts) { strncpy(std_drv_glb->mtdparts, mtdparts, max_len); @@ -154,12 +145,25 @@ static void ce_setup_std_drv_globals(ce_std_driver_globals *std_drv_glb, } } -static void ce_prepare_run_bin(ce_bin *bin) +static void ce_init_drv_globals(void) { - ce_driver_globals *drv_glb; struct ce_magic *ce_magic = (void *)CONFIG_SYS_SDRAM_BASE + 0x160; ce_std_driver_globals *std_drv_glb = &ce_magic->drv_glb; + debug("Copying CE MAGIC from %p to %p..%p\n", + &ce_magic_template, ce_magic, + (void *)ce_magic + sizeof(*ce_magic) - 1); + memcpy(ce_magic, &ce_magic_template, sizeof(*ce_magic)); + + ce_setup_std_drv_globals(std_drv_glb); + ce_magic->size = sizeof(*std_drv_glb) + + strlen(std_drv_glb->mtdparts) + 1; + ce_dump_block(ce_magic, offsetof(struct ce_magic, drv_glb) + + ce_magic->size); +} + +static void ce_prepare_run_bin(ce_bin *bin) +{ /* Clear os RAM area (if needed) */ if (bin->edbgConfig.flags & EDBG_FL_CLEANBOOT) { debug("cleaning memory from %p to %p\n", @@ -170,55 +174,7 @@ static void ce_prepare_run_bin(ce_bin *bin) printf("ok\n"); } - /* Prepare driver globals (if needed) */ - if (bin->eDrvGlb) { - debug("Copying CE MAGIC from %p to %p..%p\n", - &ce_magic_template, ce_magic, - (void *)ce_magic + sizeof(*ce_magic) - 1); - memcpy(ce_magic, &ce_magic_template, sizeof(*ce_magic)); - - ce_setup_std_drv_globals(std_drv_glb, bin); - ce_magic->size = sizeof(*std_drv_glb) + - strlen(std_drv_glb->mtdparts) + 1; - ce_dump_block(ce_magic, offsetof(struct ce_magic, drv_glb) + - ce_magic->size); - - drv_glb = bin->eDrvGlb; - memset(drv_glb, 0, sizeof(*drv_glb)); - - drv_glb->signature = DRV_GLB_SIGNATURE; - - /* Local ethernet MAC address */ - memcpy(drv_glb->macAddr, std_drv_glb->kitl.mac, - sizeof(drv_glb->macAddr)); - debug("got MAC address %02x:%02x:%02x:%02x:%02x:%02x from environment\n", - drv_glb->macAddr[0], drv_glb->macAddr[1], - drv_glb->macAddr[2], drv_glb->macAddr[3], - drv_glb->macAddr[4], drv_glb->macAddr[5]); - - /* Local IP address */ - drv_glb->ipAddr = getenv_IPaddr("ipaddr"); - - /* Subnet mask */ - drv_glb->ipMask = getenv_IPaddr("netmask"); - - /* Gateway config */ - drv_glb->ipGate = getenv_IPaddr("gatewayip"); -#ifdef DEBUG - debug("got IP address "); - print_IPaddr(drv_glb->ipAddr); - debug(" from environment\n"); - debug("got IP mask "); - print_IPaddr(drv_glb->ipMask); - debug(" from environment\n"); - debug("got gateway address "); - print_IPaddr(drv_glb->ipGate); - debug(" from environment\n"); -#endif - /* EDBG services config */ - memcpy(&drv_glb->edbgConfig, &bin->edbgConfig, - sizeof(bin->edbgConfig)); - } + ce_init_drv_globals(); /* * Make sure, all the above makes it into SDRAM because @@ -263,15 +219,6 @@ static int ce_lookup_ep_bin(ce_bin *bin) e32->e32_entryrva; bin->eRamStart = CE_FIX_ADDRESS(header->ramStart); bin->eRamLen = header->ramEnd - header->ramStart; - // Save driver_globals address - // Must follow RAM section in CE config.bib file - // - // eg. - // - // RAM 80900000 03200000 RAM - // DRV_GLB 83B00000 00001000 RESERVED - // - bin->eDrvGlb = CE_FIX_ADDRESS(header->ramEnd); return 1; } } @@ -341,6 +288,8 @@ static int ce_parse_bin(ce_bin *bin) break; case CE_PS_E_DATA: + debug("ePhysAddr=%p physlen=%08x parselen=%08x\n", + bin->ePhysAddr, bin->ePhysLen, bin->parseLen); if (bin->ePhysAddr) { copyLen = CE_MIN(bin->ePhysLen - bin->parseLen, len); bin->parseLen += copyLen; @@ -416,24 +365,29 @@ static int ce_bin_load(void *image, int imglen) static void ce_run_bin(void (*entry)(void)) { printf("Launching Windows CE ...\n"); +#ifdef TEST_LAUNCH +return; +#endif entry(); } -static int do_bootce(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +static int do_bootce(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { void *addr; size_t image_size; - char *s; if (argc > 1) { + if (strcmp(argv[1], "-i") == 0) { + ce_init_drv_globals(); + return CMD_RET_SUCCESS; + } addr = (void *)simple_strtoul(argv[1], NULL, 16); image_size = INT_MAX; /* actually we do not know the image size */ } else if (getenv("fileaddr") != NULL) { addr = (void *)getenv_ulong("fileaddr", 16, 0); image_size = getenv_ulong("filesize", 16, INT_MAX); } else { - printf ("Usage:\n%s\n", cmdtp->usage); - return 1; + return CMD_RET_USAGE; } printf ("## Booting Windows CE Image from address %p ...\n", addr); @@ -444,204 +398,263 @@ static int do_bootce(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) /* Ops! Corrupted .BIN image! */ /* Handle error here ... */ printf("corrupted .BIN image !!!\n"); - return 1; + return CMD_RET_FAILURE; } - if ((s = getenv("autostart")) != NULL) { - if (*s != 'y') { - /* - * just use bootce to load the image to SDRAM; - * Do not start it automatically. - */ - setenv_addr("fileaddr", - g_bin.eEntryPoint); - return 0; - } + if (getenv_yesno("autostart") != 1) { + /* + * just use bootce to load the image to SDRAM; + * Do not start it automatically. + */ + setenv_addr("fileaddr", g_bin.eEntryPoint); + return CMD_RET_SUCCESS; } ce_run_bin(g_bin.eEntryPoint); /* start the image */ } else { printf("Image does not seem to be a valid Windows CE image!\n"); - return 1; + return CMD_RET_FAILURE; } - return 1; /* never reached - just to keep compiler happy */ + return CMD_RET_FAILURE; /* never reached - just to keep compiler happy */ } - U_BOOT_CMD( - bootce, 2, 0, do_bootce, - "bootce\t- Boot a Windows CE image from memory \n", - "[args..]\n" - "\taddr\t\t-boot image from address addr\n" + bootce, 2, 0, do_bootce, + "Boot a Windows CE image from RAM", + "[addr]\n" + "\taddr\t\tboot image from address addr (default ${fileaddr})\n" + "or\n" + "\t-i\t\tinitialize the WinCE globals data structure (before loading a .nb0 image)" ); -static void wince_handler(uchar *pkt, unsigned dport, IPaddr_t sip, - unsigned sport, unsigned len) +#ifdef CONFIG_CMD_NAND +static int ce_nand_load(ce_bin *bin, loff_t *offset, void *buf, size_t max_len) { - void *eth_pkt = pkt - IP_HDR_SIZE - ETHER_HDR_SIZE; - unsigned eth_len = len + IP_HDR_SIZE + ETHER_HDR_SIZE; - - NetState = NETLOOP_SUCCESS; /* got input - quit net loop */ - - if (memcmp(eth_pkt, eth_get_dev()->enetaddr, ETH_ALEN) != 0) { - g_net.got_packet_4me = 0; - return; + int ret; + size_t len = max_len; + nand_info_t *nand = &nand_info[0]; + + while (nand_block_isbad(nand, *offset & ~(max_len - 1))) { + printf("Skipping bad block 0x%08llx\n", + *offset & ~(max_len - 1)); + *offset += max_len; + if (*offset + max_len > nand->size) + return -EINVAL; } - memcpy(&g_net.data[g_net.align_offset], - eth_pkt, eth_len); - g_net.dataLen = len; - g_net.got_packet_4me = 1; - - g_net.srvAddrRecv.sin_port = *((unsigned short *)(&g_net.data[ - ETHER_HDR_SIZE + IP_HDR_SIZE_NO_UDP + g_net.align_offset])); - NetCopyIP(&g_net.srvAddrRecv.sin_addr, &g_net.data[ETHER_HDR_SIZE + - g_net.align_offset + 12]); - memcpy(NetServerEther, &g_net.data[g_net.align_offset + 6], ETH_ALEN); -#if 0 - printf("received packet: buffer %p Laenge %d \n", pkt, len); - printf("from "); - print_IPaddr(g_net.srvAddrRecv.sin_addr); - printf(", port: %d\n", ntohs(g_net.srvAddrRecv.sin_port)); - - ce_dump_block(pkt, len); - - printf("Headers:\n"); - ce_dump_block(eth_pkt, ETHER_HDR_SIZE + IP_HDR_SIZE); - printf("my port should be: %d\n", - ntohs(*((unsigned short *)(&g_net.data[ETHER_HDR_SIZE + - IP_HDR_SIZE_NO_UDP + - g_net.align_offset + 2])))); -#endif + ret = nand_read(nand, *offset, &len, buf); + if (ret < 0) + return ret; + + bin->dataLen = len; + return len; } -/* returns packet length if successfull */ -static int ce_recv_packet(uchar *buf, int len, struct sockaddr_in *from, - struct sockaddr_in *local, struct timeval *timeout) +static int do_nbootce(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { - int rxlength; - ulong time_started; - - g_net.got_packet_4me = 0; - time_started = get_timer(0); - NetSetHandler(wince_handler); - - while (1) { - rxlength = eth_rx(); - if (g_net.got_packet_4me) - return g_net.dataLen; - /* check for timeout */ - if (get_timer(time_started) > timeout->tv_sec * CONFIG_SYS_HZ) { - return -ETIMEDOUT; + int ret; + struct mtd_device *dev; + struct part_info *part_info; + u8 part_num; + loff_t offset; + char *end; + void *buffer; + size_t bufsize = nand_info[0].erasesize, len; + + if (argc < 2 || argc > 3) + return CMD_RET_USAGE; + + ret = mtdparts_init(); + if (ret) + return CMD_RET_FAILURE; + + offset = simple_strtoul(argv[1], &end, 16); + if (*end != '\0') { + ret = find_dev_and_part(argv[1], &dev, &part_num, + &part_info); + if (ret != 0) { + printf("Partition '%s' not found\n", argv[1]); + return CMD_RET_FAILURE; } + offset = part_info->offset; + printf ("## Booting Windows CE Image from NAND partition %s at offset %08llx\n", + argv[1], offset); + } else { + printf ("## Booting Windows CE Image from NAND offset %08llx\n", + offset); } -} - -static int ce_recv_frame(ce_net *net, int timeout) -{ - struct timeval timeo; - timeo.tv_sec = timeout; - timeo.tv_usec = 0; + buffer = malloc(bufsize); + if (buffer == NULL) { + printf("Failed to allocate %u byte buffer\n", bufsize); + return CMD_RET_FAILURE; + } - net->dataLen = ce_recv_packet(&net->data[net->align_offset], - sizeof(net->data) - net->align_offset, - &net->srvAddrRecv, &net->locAddr, &timeo); + ce_init_bin(&g_bin, buffer); - if (net->dataLen < 0 || net->dataLen > sizeof(net->data)) { - /* Error! No data available */ - net->dataLen = 0; + ret = ce_nand_load(&g_bin, &offset, buffer, bufsize); + if (ret < 0) { + printf("Failed to read NAND: %d\n", ret); + goto err; } + len = ret; + /* check if there is a valid windows CE image header */ + if (ce_is_bin_image(buffer, len)) { + do { + ret = ce_parse_bin(&g_bin); + switch (ret) { + case CE_PR_MORE: + { + if (ctrlc()) { + printf("NBOOTCE - canceled by user\n"); + goto err; + } + offset += len; + len = ce_nand_load(&g_bin, &offset, buffer, + bufsize); + if (len < 0) { + printf("Nand read error: %d\n", len); + ret = len; + goto err; + } + } + break; - return net->dataLen; -} - -static int ce_send_frame(ce_net *net) -{ - uchar *pkt = (uchar *)NetTxPacket + ETHER_HDR_SIZE + IP_HDR_SIZE; + case CE_PR_EOF: + ce_prepare_run_bin(&g_bin); + break; - memcpy(pkt, &net->data[net->align_offset + ETHER_HDR_SIZE + IP_HDR_SIZE], - net->dataLen); - return NetSendUDPPacket(NetServerEther, net->srvAddrSend.sin_addr, - ntohs(net->srvAddrSend.sin_port), - ntohs(net->locAddr.sin_port), net->dataLen); + case CE_PR_ERROR: + break; + } + } while (ret == CE_PR_MORE); + free(buffer); + if (ret != CE_PR_EOF) + return CMD_RET_FAILURE; + + if (getenv_yesno("autostart") != 1) { + /* + * just use bootce to load the image to SDRAM; + * Do not start it automatically. + */ + setenv_addr("fileaddr", g_bin.eEntryPoint); + return CMD_RET_SUCCESS; + } + ce_run_bin(g_bin.eEntryPoint); /* start the image */ + } else { + printf("Image does not seem to be a valid Windows CE image!\n"); + } +err: + free(buffer); + return CMD_RET_FAILURE; } +U_BOOT_CMD( + nbootce, 2, 0, do_nbootce, + "Boot a Windows CE image from NAND", + "off|partitition\n" + "\toff\t\t- flash offset (hex)\n" + "\tpartition\t- partition name" +); +#endif static int ce_send_write_ack(ce_net *net) { - unsigned short *wdata; - unsigned long aligned_address; - - aligned_address = (unsigned long)&net->data[ETHER_HDR_SIZE + IP_HDR_SIZE + net->align_offset]; + int ret; + unsigned short wdata[2]; + int retries = 0; - wdata = (unsigned short *)aligned_address; wdata[0] = htons(EDBG_CMD_WRITE_ACK); wdata[1] = htons(net->blockNum); - - net->dataLen = 4; - - return ce_send_frame(net); + net->dataLen = sizeof(wdata); + memcpy(net->data, wdata, net->dataLen); + + do { + ret = bootme_send_frame(net->data, net->dataLen); + if (ret) { + printf("Failed to send write ack %d; retries=%d\n", + ret, retries); + } + } while (ret != 0 && retries-- > 0); + return ret; } -static int ce_process_download(ce_net *net, ce_bin *bin) +static enum bootme_state ce_process_download(ce_net *net, ce_bin *bin) { - int ret = CE_PR_MORE; + int ret = net->state; - if (net->dataLen >= 2) { + if (net->dataLen >= 4) { unsigned short command; + unsigned short blknum; - command = ntohs(*(unsigned short *)&net->data[CE_DOFFSET]); + memcpy(&command, net->data, sizeof(command)); + command = ntohs(command); debug("command found: 0x%04X\n", command); + if (net->state == BOOTME_DOWNLOAD) { + unsigned short nxt = net->blockNum + 1; + + memcpy(&blknum, &net->data[2], sizeof(blknum)); + blknum = ntohs(blknum); + if (blknum == nxt) { + net->blockNum = blknum; + } else { + int rc = ce_send_write_ack(net); + + if (net->verbose) + printf("Dropping out of sequence packet with ID %d (expected %d)\n", + blknum, nxt); + if (rc != 0) + return rc; + + return ret; + } + } + switch (command) { case EDBG_CMD_WRITE_REQ: - if (!net->link) { + if (net->state == BOOTME_INIT) { // Check file name for WRITE request // CE EShell uses "boot.bin" file name -#if 0 - printf(">>>>>>>> First Frame, IP: %s, port: %d\n", - inet_ntoa((in_addr_t *)&net->srvAddrRecv), - ntohs(net->srvAddrRecv.sin_port)); -#endif - if (strncmp((char *)&net->data[CE_DOFFSET + 2], + if (strncmp((char *)&net->data[2], "boot.bin", 8) == 0) { // Some diag output if (net->verbose) { - printf("Locked Down download link, IP: "); - print_IPaddr(net->srvAddrRecv.sin_addr); - printf(", port: %d\n", ntohs(net->srvAddrRecv.sin_port)); - - printf("Sending BOOTME request [%d] to ", - net->seqNum); - print_IPaddr(net->srvAddrSend.sin_addr); - printf("\n"); + printf("Locked Down download link, IP: %pI4\n", + &net_server_ip); + printf("Sending BOOTME request [%d] to %pI4\n", + net->seqNum, &net_server_ip); } // Lock down EShell download link - net->locAddr.sin_port = htons(EDBG_DOWNLOAD_PORT + 1); - net->srvAddrSend.sin_port = net->srvAddrRecv.sin_port; - net->srvAddrSend.sin_addr = net->srvAddrRecv.sin_addr; - net->link = 1; + ret = BOOTME_DOWNLOAD; } else { // Unknown link - net->srvAddrRecv.sin_port = 0; + printf("Unknown link\n"); } - if (net->link) { - ce_send_write_ack(net); + if (ret == BOOTME_DOWNLOAD) { + int rc = ce_send_write_ack(net); + if (rc != 0) + return rc; } } break; case EDBG_CMD_WRITE: - /* Fix data len */ + /* Fixup data len */ + bin->data = &net->data[4]; bin->dataLen = net->dataLen - 4; - ret = ce_parse_bin(bin); if (ret != CE_PR_ERROR) { - net->blockNum++; - ce_send_write_ack(net); + int rc = ce_send_write_ack(net); + if (rc) + return rc; + if (ret == CE_PR_EOF) + ret = BOOTME_DONE; + } else { + ret = BOOTME_ERROR; } break; case EDBG_CMD_READ_REQ: + printf("Ignoring EDBG_CMD_READ_REQ\n"); /* Read requests are not supported * Do nothing ... */ @@ -651,66 +664,55 @@ static int ce_process_download(ce_net *net, ce_bin *bin) printf("Error: unknown error on the host side\n"); bin->binLen = 0; - ret = CE_PR_ERROR; + ret = BOOTME_ERROR; break; default: printf("unknown command 0x%04X\n", command); - return -EINVAL; + net->state = BOOTME_ERROR; } } return ret; } -static void ce_init_edbg_link(ce_net *net) -{ - /* Initialize EDBG link for commands */ - - net->locAddr.sin_port = htons(EDBG_DOWNLOAD_PORT); - net->srvAddrSend.sin_port = htons(EDBG_DOWNLOAD_PORT); - net->srvAddrRecv.sin_port = 0; - net->link = 0; -} - -static void ce_process_edbg(ce_net *net, ce_bin *bin) +static enum bootme_state ce_process_edbg(ce_net *net, ce_bin *bin) { - eth_dbg_hdr *header; + enum bootme_state ret = net->state; + eth_dbg_hdr header; - if (net->dataLen < sizeof(eth_dbg_hdr)) { + if (net->dataLen < sizeof(header)) { /* Bad packet */ - - net->srvAddrRecv.sin_port = 0; - return; + printf("Invalid packet size %u\n", net->dataLen); + net->dataLen = 0; + return ret; } - - header = (eth_dbg_hdr *)&net->data[net->align_offset + ETHER_HDR_SIZE + IP_HDR_SIZE]; - - if (header->id != EDBG_ID) { + memcpy(&header, net->data, sizeof(header)); + if (header.id != EDBG_ID) { /* Bad packet */ - - net->srvAddrRecv.sin_port = 0; - return; + printf("Bad EDBG ID %08x\n", header.id); + net->dataLen = 0; + return ret; } - if (header->service != EDBG_SVC_ADMIN) { + if (header.service != EDBG_SVC_ADMIN) { /* Unknown service */ - return; + printf("Bad EDBG service %02x\n", header.service); + net->dataLen = 0; + return ret; } - if (!net->link) { + if (net->state == BOOTME_INIT) { /* Some diag output */ if (net->verbose) { - printf("Locked Down EDBG service link, IP: "); - print_IPaddr(net->srvAddrRecv.sin_addr); - printf(", port: %d\n", ntohs(net->srvAddrRecv.sin_port)); + printf("Locked Down EDBG service link, IP: %pI4\n", + &net_server_ip); } /* Lock down EDBG link */ - net->srvAddrSend.sin_port = net->srvAddrRecv.sin_port; - net->link = 1; + net->state = BOOTME_DEBUG; } - switch (header->cmd) { + switch (header.cmd) { case EDBG_CMD_JUMPIMG: net->gotJumpingRequest = 1; @@ -718,36 +720,28 @@ static void ce_process_edbg(ce_net *net, ce_bin *bin) printf("Received JUMPING command\n"); } /* Just pass through and copy CONFIG structure */ + ret = BOOTME_DONE; case EDBG_CMD_OS_CONFIG: /* Copy config structure */ - memcpy(&bin->edbgConfig, header->data, + memcpy(&bin->edbgConfig, &net->data[sizeof(header)], sizeof(edbg_os_config_data)); if (net->verbose) { printf("Received CONFIG command\n"); if (bin->edbgConfig.flags & EDBG_FL_DBGMSG) { - printf("--> Enabling DBGMSG service, IP: %d.%d.%d.%d, port: %d\n", - (bin->edbgConfig.dbgMsgIPAddr >> 0) & 0xFF, - (bin->edbgConfig.dbgMsgIPAddr >> 8) & 0xFF, - (bin->edbgConfig.dbgMsgIPAddr >> 16) & 0xFF, - (bin->edbgConfig.dbgMsgIPAddr >> 24) & 0xFF, + printf("--> Enabling DBGMSG service, IP: %pI4, port: %d\n", + &bin->edbgConfig.dbgMsgIPAddr, ntohs(bin->edbgConfig.dbgMsgPort)); } if (bin->edbgConfig.flags & EDBG_FL_PPSH) { - printf("--> Enabling PPSH service, IP: %d.%d.%d.%d, port: %d\n", - (bin->edbgConfig.ppshIPAddr >> 0) & 0xFF, - (bin->edbgConfig.ppshIPAddr >> 8) & 0xFF, - (bin->edbgConfig.ppshIPAddr >> 16) & 0xFF, - (bin->edbgConfig.ppshIPAddr >> 24) & 0xFF, + printf("--> Enabling PPSH service, IP: %pI4, port: %d\n", + &bin->edbgConfig.ppshIPAddr, ntohs(bin->edbgConfig.ppshPort)); } if (bin->edbgConfig.flags & EDBG_FL_KDBG) { - printf("--> Enabling KDBG service, IP: %d.%d.%d.%d, port: %d\n", - (bin->edbgConfig.kdbgIPAddr >> 0) & 0xFF, - (bin->edbgConfig.kdbgIPAddr >> 8) & 0xFF, - (bin->edbgConfig.kdbgIPAddr >> 16) & 0xFF, - (bin->edbgConfig.kdbgIPAddr >> 24) & 0xFF, + printf("--> Enabling KDBG service, IP: %pI4, port: %d\n", + &bin->edbgConfig.kdbgIPAddr, ntohs(bin->edbgConfig.kdbgPort)); } @@ -759,28 +753,67 @@ static void ce_process_edbg(ce_net *net, ce_bin *bin) default: if (net->verbose) { - printf("Received unknown command: %08X\n", header->cmd); + printf("Received unknown command: %08X\n", header.cmd); } - return; + return BOOTME_ERROR; } /* Respond with ack */ - header->flags = EDBG_FL_FROM_DEV | EDBG_FL_ACK; + header.flags = EDBG_FL_FROM_DEV | EDBG_FL_ACK; + memcpy(net->data, &header, sizeof(header)); net->dataLen = EDBG_DATA_OFFSET; - ce_send_frame(net); + + int retries = 10; + int rc; + do { + rc = bootme_send_frame(net->data, net->dataLen); + if (rc != 0) { + printf("Failed to send ACK: %d\n", rc); + } + } while (rc && retries-- > 0); + return rc ?: ret; +} + +static enum bootme_state ce_edbg_handler(const void *buf, size_t len) +{ + if (len == 0) + return BOOTME_DONE; + + g_net.data = (void *)buf; + g_net.dataLen = len; + + return ce_process_edbg(&g_net, &g_bin); +} + +static void ce_init_edbg_link(ce_net *net) +{ + /* Initialize EDBG link for commands */ + net->state = BOOTME_INIT; +} + +static enum bootme_state ce_download_handler(const void *buf, size_t len) +{ + g_net.data = (void *)buf; + g_net.dataLen = len; + + g_net.state = ce_process_download(&g_net, &g_bin); + return g_net.state; } static int ce_send_bootme(ce_net *net) { eth_dbg_hdr *header; edbg_bootme_data *data; + unsigned char txbuf[PKTSIZE_ALIGN]; #ifdef DEBUG int i; unsigned char *pkt; #endif /* Fill out BOOTME packet */ + net->data = txbuf; + memset(net->data, 0, PKTSIZE); - header = (eth_dbg_hdr *)&net->data[CE_DOFFSET]; + header = (eth_dbg_hdr *)net->data; data = (edbg_bootme_data *)header->data; header->id = EDBG_ID; @@ -803,8 +836,8 @@ static int ce_send_bootme(ce_net *net) memset(data->macAddr, 0, sizeof(data->macAddr)); } - /* IP address from environment */ - data->ipAddr = getenv_IPaddr("ipaddr"); + /* IP address from active config */ + net_copy_ip(&data->ipAddr, &net_ip); // Device name string (NULL terminated). Should include // platform and number based on Ether address (e.g. Odo42, CEPCLS2346, etc) @@ -817,136 +850,123 @@ static int ce_send_bootme(ce_net *net) data->platformId, data->macAddr[5]); #ifdef DEBUG - printf("header->id: %08X\r\n", header->id); - printf("header->service: %08X\r\n", header->service); - printf("header->flags: %08X\r\n", header->flags); - printf("header->seqNum: %08X\r\n", header->seqNum); - printf("header->cmd: %08X\r\n\r\n", header->cmd); - - printf("data->versionMajor: %08X\r\n", data->versionMajor); - printf("data->versionMinor: %08X\r\n", data->versionMinor); - printf("data->cpuId: %08X\r\n", data->cpuId); - printf("data->bootmeVer: %08X\r\n", data->bootmeVer); - printf("data->bootFlags: %08X\r\n", data->bootFlags); - printf("data->svcPort: %08X\r\n\r\n", ntohs(data->svcPort)); - - printf("data->macAddr: %02X-%02X-%02X-%02X-%02X-%02X\r\n", - data->macAddr[0], data->macAddr[1], - data->macAddr[2], data->macAddr[3], - data->macAddr[4], data->macAddr[5]); - - printf("data->ipAddr: %d.%d.%d.%d\r\n", - (data->ipAddr >> 0) & 0xFF, - (data->ipAddr >> 8) & 0xFF, - (data->ipAddr >> 16) & 0xFF, - (data->ipAddr >> 24) & 0xFF); - - printf("data->platformId: %s\r\n", data->platformId); - - printf("data->deviceName: %s\r\n", data->deviceName); + printf("header->id: %08X\n", header->id); + printf("header->service: %08X\n", header->service); + printf("header->flags: %08X\n", header->flags); + printf("header->seqNum: %08X\n", header->seqNum); + printf("header->cmd: %08X\n\n", header->cmd); + + printf("data->versionMajor: %08X\n", data->versionMajor); + printf("data->versionMinor: %08X\n", data->versionMinor); + printf("data->cpuId: %08X\n", data->cpuId); + printf("data->bootmeVer: %08X\n", data->bootmeVer); + printf("data->bootFlags: %08X\n", data->bootFlags); + printf("data->svcPort: %08X\n\n", ntohs(data->svcPort)); + + printf("data->macAddr: %pM\n", data->macAddr); + printf("data->ipAddr: %pI4\n", &data->ipAddr); + printf("data->platformId: %s\n", data->platformId); + printf("data->deviceName: %s\n", data->deviceName); #endif // Some diag output ... if (net->verbose) { - printf("Sending BOOTME request [%d] to ", net->seqNum); - print_IPaddr(net->srvAddrSend.sin_addr); - printf("\n"); + printf("Sending BOOTME request [%d] to %pI4\n", net->seqNum, + &server_ip); } net->dataLen = BOOTME_PKT_SIZE; +// net->status = CE_PR_MORE; + net->state = BOOTME_INIT; #ifdef DEBUG debug("Start of buffer: %p\n", net->data); - debug("Start of ethernet buffer: %p\n", &net->data[net->align_offset]); + debug("Start of ethernet buffer: %p\n", net->data); debug("Start of CE header: %p\n", header); debug("Start of CE data: %p\n", data); - pkt = &net->data[net->align_offset]; + pkt = net->data; debug("packet to send (ceconnect): \n"); - for (i = 0; i < net->dataLen + ETHER_HDR_SIZE + IP_HDR_SIZE; i++) { + for (i = 0; i < net->dataLen; i++) { debug("0x%02X ", pkt[i]); if (!((i + 1) % 16)) debug("\n"); } debug("\n"); #endif - memcpy(NetServerEther, NetBcastAddr, 6); - return ce_send_frame(net); + return BootMeRequest(server_ip, net->data, net->dataLen, 1); } -static int ce_init_download_link(ce_net *net, ce_bin *bin, - struct sockaddr_in *host_addr, int verbose) +static inline int ce_init_download_link(ce_net *net, ce_bin *bin, int verbose) { - int ret; - unsigned long aligned_address; - if (!eth_get_dev()) { printf("No network interface available\n"); return -ENODEV; } - printf("Usinge device '%s'\n", eth_get_name()); + printf("Using device '%s'\n", eth_get_name()); /* Initialize EDBG link for download */ memset(net, 0, sizeof(*net)); - /* our buffer contains space for ethernet- ip- and udp- headers */ - /* calculate an offset so that our ce field is aligned to 4 bytes */ - aligned_address = (unsigned long)net->data; - /* we need 42 bytes room for headers (14 Ethernet , 20 IPv4, 8 UDP) */ - aligned_address += ETHER_HDR_SIZE + IP_HDR_SIZE; - /* want CE header aligned to 4 Byte boundary */ - net->align_offset = (4 - (aligned_address % 4)) % 4; - - net->locAddr.sin_family = AF_INET; - net->locAddr.sin_addr = getenv_IPaddr("ipaddr"); - net->locAddr.sin_port = htons(EDBG_DOWNLOAD_PORT); + net->verbose = verbose; - net->srvAddrSend.sin_family = AF_INET; - net->srvAddrSend.sin_port = htons(EDBG_DOWNLOAD_PORT); + /* buffer will be dynamically assigned in ce_download_handler() */ + ce_init_bin(bin, NULL); + return 0; +} - net->srvAddrRecv.sin_family = AF_INET; - net->srvAddrRecv.sin_port = 0; +static inline int ce_download_file(ce_net *net, ulong timeout) +{ + ulong start = get_timer_masked(); - if (host_addr->sin_addr) { - /* Use specified host address ... */ - net->srvAddrSend.sin_addr = host_addr->sin_addr; - net->srvAddrRecv.sin_addr = host_addr->sin_addr; - } else { - /* ... or default server address */ - net->srvAddrSend.sin_addr = getenv_IPaddr("serverip"); - net->srvAddrRecv.sin_addr = getenv_IPaddr("serverip"); - } + while (net->state == BOOTME_INIT) { + int ret; - net->verbose = verbose; + if (timeout && get_timer(start) > timeout) { + printf("CELOAD - Canceled, timeout\n"); + return 1; + } - ce_init_bin(bin, &net->data[CE_DOFFSET + 4]); + if (ctrlc()) { + printf("CELOAD - canceled by user\n"); + return 1; + } - eth_halt(); + if (ce_send_bootme(&g_net)) { + printf("CELOAD - error while sending BOOTME request\n"); + return 1; + } + if (net->verbose) { + if (timeout) { + printf("Waiting for connection, timeout %lu sec\n", + DIV_ROUND_UP(timeout - get_timer(start), + CONFIG_SYS_HZ)); + } else { + printf("Waiting for connection, enter ^C to abort\n"); + } + } -#ifdef CONFIG_NET_MULTI - eth_set_current(); -#endif - ret = eth_init(gd->bd); - if (ret < 0) { - printf("ceconnect: failed to init ethernet: %d\n", ret); - eth_halt(); - return ret; + ret = BootMeDownload(ce_download_handler); + if (ret == BOOTME_ERROR) { + printf("CELOAD - aborted\n"); + return 1; + } } -#ifdef ET_DEBUG - puts("ceconnect: init ethernet done!\n"); -#endif - memcpy(NetOurEther, eth_get_dev()->enetaddr, ETH_ALEN); - NetCopyIP(&NetOurIP, &gd->bd->bi_ip_addr); - NetOurGatewayIP = getenv_IPaddr("gatewayip"); - NetOurSubnetMask = getenv_IPaddr("netmask"); - NetServerIP = getenv_IPaddr("serverip"); return 0; } -static int do_ceconnect(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +static void ce_disconnect(void) { + net_set_udp_handler(NULL); + eth_halt(); +} + +static int do_ceconnect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + int verbose = 0; + ulong timeout = 0; + int ret = 1; int i; - int verbose = 0, use_timeout = 0; - int timeout = 0, recv_timeout, ret; - struct sockaddr_in host_ip_addr; + + server_ip.s_addr = 0; for (i = 1; i < argc; i++){ if (*argv[i] != '-') @@ -957,62 +977,34 @@ static int do_ceconnect(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[ i++; if (argc > i) { timeout = simple_strtoul(argv[i], - NULL, 10); - use_timeout = 1; + NULL, 0); + if (timeout >= UINT_MAX / CONFIG_SYS_HZ) { + printf("Timeout value %lu out of range (max.: %u)\n", + timeout, UINT_MAX / CONFIG_SYS_HZ - 1); + return CMD_RET_USAGE; + } + timeout *= CONFIG_SYS_HZ; } else { printf("Option requires an argument - t\n"); - return 1; + return CMD_RET_USAGE; + } + } else if (argv[i][1] == 'h') { + i++; + if (argc > i) { + server_ip = string_to_ip(argv[i]); + printf("Using server %pI4\n", &server_ip); + } else { + printf("Option requires an argument - h\n"); + return CMD_RET_USAGE; } } } - memset(&host_ip_addr, 0xff, sizeof(host_ip_addr)); - - if (ce_init_download_link(&g_net, &g_bin, &host_ip_addr, verbose) != 0) - return 1; + if (ce_init_download_link(&g_net, &g_bin, verbose) != 0) + goto err; - while (1) { - if (g_net.link) { - recv_timeout = 3; - } else { - recv_timeout = 1; - - if (use_timeout && timeout <= 0) { - printf("CELOAD - Canceled, timeout\n"); - eth_halt(); - return 1; - } - if (ctrlc()) { - printf("CELOAD - canceled by user\n"); - eth_halt(); - return 1; - } - - debug("sending broadcast frame bootme\n"); - - if (ce_send_bootme(&g_net)) { - printf("CELOAD - error while sending BOOTME request\n"); - eth_halt(); - return 1; - } - debug("net state is: %d\n", NetState); - if (verbose) { - if (use_timeout) { - printf("Waiting for connection, timeout %d sec\n", timeout); - } else { - printf("Waiting for connection, enter ^C to abort\n"); - } - } - } - - if (ce_recv_frame(&g_net, recv_timeout)) { - ret = ce_process_download(&g_net, &g_bin); - if (ret != CE_PR_MORE) - break; - } else if (use_timeout) { - timeout -= recv_timeout; - } - } + if (ce_download_file(&g_net, timeout)) + goto err; if (g_bin.binLen) { // Try to receive edbg commands from host @@ -1020,8 +1012,9 @@ static int do_ceconnect(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[ if (verbose) printf("Waiting for EDBG commands ...\n"); - while (ce_recv_frame(&g_net, 3)) - ce_process_edbg(&g_net, &g_bin); + ret = BootMeDebugStart(ce_edbg_handler); + if (ret != BOOTME_DONE) + goto err; // Prepare WinCE image for execution ce_prepare_run_bin(&g_bin); @@ -1030,14 +1023,16 @@ static int do_ceconnect(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[ if (g_net.gotJumpingRequest) ce_run_bin(g_bin.eEntryPoint); } - eth_halt(); - return 0; + ret = 0; +err: + ce_disconnect(); + return ret == 0 ? CMD_RET_SUCCESS : CMD_RET_FAILURE; } - U_BOOT_CMD( - ceconnect, 4, 1, do_ceconnect, - "ceconnect - Set up a connection to the CE host PC over TCP/IP and download the run-time image\n", - "ceconnect [-v] [-t ]\n" - " -v verbose operation\n" - " -t - max wait time (#sec) for the connection\n" + ceconnect, 6, 1, do_ceconnect, + "Set up a connection to the CE host PC over TCP/IP and download the run-time image", + "[-v] [-t ] [-h host]\n" + " -v - verbose operation\n" + " -t - max wait time (#sec) for the connection\n" + " -h - send BOOTME requests to (default: broadcast address 255.255.255.255)" );