2 * Copyright (C) 2012 Lothar Waßmann <LW@KARO-electronics.de>
3 * based on: code from RedBoot (C) Uwe Steinkohl <US@KARO-electronics.de>
5 * See file CREDITS for list of people who contributed to this
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
28 #include <asm/errno.h>
30 DECLARE_GLOBAL_DATA_PTR;
32 #define WINCE_VRAM_BASE 0x80000000
33 #define CE_FIX_ADDRESS(a) ((void *)((a) - WINCE_VRAM_BASE + CONFIG_SYS_SDRAM_BASE))
36 #define INT_MAX ((int)(~0 >> 1))
39 /* Bin image parse states */
40 #define CE_PS_RTI_ADDR 0
41 #define CE_PS_RTI_LEN 1
42 #define CE_PS_E_ADDR 2
44 #define CE_PS_E_CHKSUM 4
45 #define CE_PS_E_DATA 5
47 #define CE_MIN(a, b) (((a) < (b)) ? (a) : (b))
48 #define CE_MAX(a, b) (((a) > (b)) ? (a) : (b))
51 #define STRMAC(s) _STRMAC(s)
53 static enum bootme_state bootme_state;
54 static int bootme_src_port = 0xdeadface;
55 static int bootme_dst_port = 0xdeadbeef;
56 static uchar bootme_ether[ETH_ALEN];
57 static IPaddr_t bootme_ip;
58 static int bootme_timed_out;
59 //static size_t input_len, input_size;
60 //static void *input_packet;
61 static const char *output_packet; /* used by first send udp */
62 static int output_packet_len;
63 static unsigned long bootme_timeout;
64 static bootme_hand_f *bootme_packet_handler;
67 static void __attribute__((unused)) ce_dump_block(const void *ptr, int length)
73 for (i = 0; i < length; i++) {
75 printf("\n%p: ", ptr + i);
78 printf("%02x ", p[i]);
81 for (j = i - 15; j <= i; j++){
82 if((p[j] > 0x1f) && (p[j] < 0x7f)) {
93 static inline void ce_dump_block(void *ptr, int length)
98 static void bootme_timeout_handler(void)
100 printf("%s\n", __func__);
102 net_set_state(NETLOOP_SUCCESS);
106 static inline int env_changed(int *id)
108 int env_id = get_env_id();
111 debug("env_id: %d -> %d\n", *id, env_id);
120 static int is_broadcast(IPaddr_t ip)
122 static IPaddr_t netmask;
123 static IPaddr_t our_ip;
125 return (ip == ~0 || /* 255.255.255.255 */
126 ((netmask & our_ip) == (netmask & ip) && /* on the same net */
127 (netmask | ip) == ~0)); /* broadcast to our net */
130 static int check_net_config(void)
132 if (env_changed(&env_id)) {
136 bootme_dst_port = EDBG_DOWNLOAD_PORT;
137 if (bootme_ip == 0) {
138 bip = getenv("bootmeip");
140 bootme_ip = getenv_IPaddr("bootmeip");
143 p = strchr(bip, ':');
145 bootme_dst_port = simple_strtoul(p + 1, NULL, 10);
148 memset(&bootme_ip, 0xff, sizeof(bootme_ip));
152 p = getenv("bootme_dst_port");
154 bootme_dst_port = simple_strtoul(p, NULL, 10);
156 p = getenv("bootme_src_port");
158 bootme_src_port = simple_strtoul(p, NULL, 10);
160 bootme_src_port = bootme_dst_port;
162 if (is_broadcast(bootme_ip))
163 memset(bootme_ether, 0xff, sizeof(bootme_ether));
165 memset(bootme_ether, 0, sizeof(bootme_ether));
168 NetServerIP = bootme_ip;
173 static void bootme_wait_arp_handler(uchar *pkt, unsigned dest,
174 IPaddr_t sip, unsigned src,
177 net_set_state(NETLOOP_SUCCESS); /* got arp reply - quit net loop */
180 static inline char next_cursor(char c)
195 static void bootme_handler(uchar *pkt, unsigned dest_port, IPaddr_t src_ip,
196 unsigned src_port, unsigned len)
198 uchar *eth_pkt = pkt;
199 unsigned eth_len = len;
200 static char cursor = '|';
201 enum bootme_state last_state = BOOTME_INIT;
203 debug("received packet of len %d from %pI4:%d to port %d\n",
204 len, &src_ip, src_port, dest_port);
205 ce_dump_block(pkt, len);
207 if (!bootme_packet_handler) {
208 printf("No packet handler set for BOOTME protocol; dropping packet\n");
211 if (dest_port != bootme_src_port || !len)
212 return; /* not for us */
214 printf("%c\x08", cursor);
215 cursor = next_cursor(cursor);
217 if (is_broadcast(bootme_ip)) {
219 } else if (src_ip != bootme_ip) {
220 debug("src_ip %pI4 does not match destination IP %pI4\n",
221 &src_ip, &bootme_ip);
222 return; /* not from our server */
225 last_state = bootme_state;
226 bootme_dst_port = src_port;
227 debug("bootme_dst_port set to %d\n", bootme_dst_port);
228 if (bootme_state == BOOTME_INIT) {
229 bootme_src_port = EDBG_SVC_PORT;
230 debug("%s: bootme_src_port set to %d\n", __func__, bootme_src_port);
232 bootme_state = bootme_packet_handler(eth_pkt, eth_len);
233 debug("bootme_packet_handler() returned %d\n", bootme_state);
234 if (bootme_state != last_state)
235 debug("bootme_state: %d -> %d\n", last_state, bootme_state);
236 switch (bootme_state) {
240 case BOOTME_DOWNLOAD:
241 if (last_state != BOOTME_INIT)
242 NetBootFileXferSize += len - 4;
245 if (last_state == BOOTME_INIT) {
246 bootme_timeout = 3 * 1000;
248 NetSetTimeout(bootme_timeout, bootme_timeout_handler);
252 net_set_state(NETLOOP_SUCCESS);
253 bootme_packet_handler = NULL;
257 net_set_state(NETLOOP_FAIL);
258 bootme_packet_handler = NULL;
262 void BootmeStart(void)
264 if (bootme_state != BOOTME_DOWNLOAD)
267 if (output_packet_len == 0 ||
268 memcmp(bootme_ether, NetEtherNullAddr, ETH_ALEN) != 0) {
269 /* wait for incoming packet */
270 net_set_udp_handler(bootme_handler);
271 bootme_timed_out = 0;
272 NetSetTimeout(bootme_timeout, bootme_timeout_handler);
274 /* send ARP request */
277 net_set_arp_handler(bootme_wait_arp_handler);
278 assert(NetTxPacket != NULL);
279 pkt = (uchar *)NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE;
280 memcpy(pkt, output_packet, output_packet_len);
281 NetSendUDPPacket(bootme_ether, bootme_ip, bootme_dst_port,
282 bootme_src_port, output_packet_len);
286 int bootme_send_frame(const void *buf, size_t len)
289 struct eth_device *eth;
297 if (bootme_state == BOOTME_INIT)
300 debug("%s: buf: %p len: %u from %pI4:%d to %pI4:%d\n",
301 __func__, buf, len, &NetOurIP, bootme_src_port, &bootme_ip, bootme_dst_port);
303 if (memcmp(bootme_ether, NetEtherNullAddr, ETH_ALEN) == 0) {
304 if (eth->state == ETH_STATE_ACTIVE)
305 return 0; /* inside net loop */
308 output_packet_len = len;
309 /* wait for arp reply and send packet */
310 ret = NetLoop(BOOTME);
313 output_packet_len = 0;
316 if (bootme_timed_out)
321 if (eth->state != ETH_STATE_ACTIVE) {
322 if (eth_is_on_demand_init()) {
323 ret = eth_init(gd->bd);
326 eth_set_last_protocol(BOOTME);
328 eth_init_state_only(gd->bd);
333 assert(NetTxPacket != NULL);
334 pkt = (uchar *)NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE;
335 memcpy(pkt, buf, len);
337 ret = NetSendUDPPacket(bootme_ether, bootme_ip, bootme_dst_port,
338 bootme_src_port, len);
340 debug("Stopping network\n");
341 if (eth_is_on_demand_init())
344 eth_halt_state_only();
349 static void bootme_init(IPaddr_t server_ip)
351 bootme_state = BOOTME_INIT;
352 bootme_ip = server_ip;
353 /* force reconfiguration in check_net_config() */
357 int BootMeDownload(bootme_hand_f *handler)
361 bootme_packet_handler = handler;
363 ret = NetLoop(BOOTME);
366 if (bootme_timed_out && bootme_state != BOOTME_INIT)
372 int BootMeDebugStart(bootme_hand_f *handler)
376 bootme_packet_handler = handler;
378 bootme_init(bootme_ip);
379 bootme_state = BOOTME_DEBUG;
380 bootme_timeout = 3 * 1000;
381 NetSetTimeout(bootme_timeout, bootme_timeout_handler);
383 ret = NetLoop(BOOTME);
386 if (bootme_timed_out)
391 int BootMeRequest(IPaddr_t server_ip, const void *buf, size_t len, int timeout)
393 bootme_init(server_ip);
394 bootme_timeout = timeout * 1000;
395 bootme_timed_out = 0;
396 NetSetTimeout(bootme_timeout, bootme_timeout_handler);
397 return bootme_send_frame(buf, len);