diff --git a/litex/boards/targets/arty.py b/litex/boards/targets/arty.py index 5e0b5aecd..501a8d7ec 100755 --- a/litex/boards/targets/arty.py +++ b/litex/boards/targets/arty.py @@ -136,7 +136,7 @@ class MiniSoC(BaseSoC): self.submodules.ethphy = LiteEthPHYMII(self.platform.request("eth_clocks"), self.platform.request("eth")) - self.submodules.ethmac = LiteEthMAC(phy=self.ethphy, dw=32, interface="wishbone") + self.submodules.ethmac = LiteEthMAC(phy=self.ethphy, dw=32, interface="wishbone", endianness="little") self.add_wb_slave(mem_decoder(self.mem_map["ethmac"]), self.ethmac.bus) self.add_memory_region("ethmac", self.mem_map["ethmac"] | self.shadow_base, 0x2000) diff --git a/litex/soc/software/include/base/inet.h b/litex/soc/software/include/base/inet.h new file mode 100644 index 000000000..373074719 --- /dev/null +++ b/litex/soc/software/include/base/inet.h @@ -0,0 +1,52 @@ +/* Copyright © 2005-2014 Rich Felker, et al. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __INET_H +#define __INET_H + +#include + +static __inline uint16_t __bswap_16(uint16_t __x) +{ + return (__x<<8) | (__x>>8); +} + +static __inline uint32_t __bswap_32(uint32_t __x) +{ + return (__x>>24) | ((__x>>8)&0xff00) | ((__x<<8)&0xff0000) | (__x<<24); +} + +static __inline uint64_t __bswap_64(uint64_t __x) +{ + return (__bswap_32(__x)+(0ULL<<32)) | __bswap_32(__x>>32); +} + +#define bswap_16(x) __bswap_16(x) +#define bswap_32(x) __bswap_32(x) +#define bswap_64(x) __bswap_64(x) + +uint16_t htons(uint16_t n); +uint32_t htonl(uint32_t n); +uint16_t ntohs(uint16_t n); +uint32_t ntohl(uint32_t n); + +#endif /* __INET_H */ diff --git a/litex/soc/software/libbase/libc.c b/litex/soc/software/libbase/libc.c index e45a79dac..f28c4207e 100644 --- a/litex/soc/software/libbase/libc.c +++ b/litex/soc/software/libbase/libc.c @@ -22,6 +22,7 @@ #include #include #include +#include /** * strchr - Find the first occurrence of a character in a string @@ -732,3 +733,27 @@ void abort(void) printf("Aborted."); while(1); } + +uint32_t htonl(uint32_t n) +{ + union { int i; char c; } u = { 1 }; + return u.c ? bswap_32(n) : n; +} + +uint16_t htons(uint16_t n) +{ + union { int i; char c; } u = { 1 }; + return u.c ? bswap_16(n) : n; +} + +uint32_t ntohl(uint32_t n) +{ + union { int i; char c; } u = { 1 }; + return u.c ? bswap_32(n) : n; +} + +uint16_t ntohs(uint16_t n) +{ + union { int i; char c; } u = { 1 }; + return u.c ? bswap_16(n) : n; +} diff --git a/litex/soc/software/libnet/microudp.c b/litex/soc/software/libnet/microudp.c index 6372a37ca..b54107101 100644 --- a/litex/soc/software/libnet/microudp.c +++ b/litex/soc/software/libnet/microudp.c @@ -2,6 +2,7 @@ #ifdef CSR_ETHMAC_BASE #include +#include #include #include #include @@ -41,7 +42,7 @@ static void fill_eth_header(struct ethernet_header *h, const unsigned char *dest h->destmac[i] = destmac[i]; for(i=0;i<6;i++) h->srcmac[i] = srcmac[i]; - h->ethertype = ethertype; + h->ethertype = htons(ethertype); } #define ARP_HWTYPE_ETHERNET 0x0001 @@ -133,8 +134,9 @@ static void send_packet(void) txbuffer->raw[txlen+1] = (crc & 0xff00) >> 8; txbuffer->raw[txlen+2] = (crc & 0xff0000) >> 16; txbuffer->raw[txlen+3] = (crc & 0xff000000) >> 24; - txlen += 4; + //txlen += 4; #endif + txlen += 4; // FIXME #ifdef DEBUG_MICROUDP_TX int j; @@ -167,21 +169,22 @@ static void process_arp(void) const struct arp_frame *rx_arp = &rxbuffer->frame.contents.arp; struct arp_frame *tx_arp = &txbuffer->frame.contents.arp; - if(rxlen < ARP_PACKET_LENGTH) return; - if(rx_arp->hwtype != ARP_HWTYPE_ETHERNET) return; - if(rx_arp->proto != ARP_PROTO_IP) return; + //if(rxlen < ARP_PACKET_LENGTH) return; // FIXME + if(ntohs(rx_arp->hwtype) != ARP_HWTYPE_ETHERNET) return; + if(ntohs(rx_arp->proto) != ARP_PROTO_IP) return; if(rx_arp->hwsize != 6) return; if(rx_arp->protosize != 4) return; - if(rx_arp->opcode == ARP_OPCODE_REPLY) { - if(rx_arp->sender_ip == cached_ip) { + + if(ntohs(rx_arp->opcode) == ARP_OPCODE_REPLY) { + if(ntohl(rx_arp->sender_ip) == cached_ip) { int i; for(i=0;i<6;i++) cached_mac[i] = rx_arp->sender_mac[i]; } return; } - if(rx_arp->opcode == ARP_OPCODE_REQUEST) { - if(rx_arp->target_ip == my_ip) { + if(ntohs(rx_arp->opcode) == ARP_OPCODE_REQUEST) { + if(ntohl(rx_arp->target_ip) == my_ip) { int i; fill_eth_header(&txbuffer->frame.eth_header, @@ -189,15 +192,15 @@ static void process_arp(void) my_mac, ETHERTYPE_ARP); txlen = ARP_PACKET_LENGTH; - tx_arp->hwtype = ARP_HWTYPE_ETHERNET; - tx_arp->proto = ARP_PROTO_IP; + tx_arp->hwtype = htons(ARP_HWTYPE_ETHERNET); + tx_arp->proto = htons(ARP_PROTO_IP); tx_arp->hwsize = 6; tx_arp->protosize = 4; - tx_arp->opcode = ARP_OPCODE_REPLY; - tx_arp->sender_ip = my_ip; + tx_arp->opcode = htons(ARP_OPCODE_REPLY); + tx_arp->sender_ip = htonl(my_ip); for(i=0;i<6;i++) tx_arp->sender_mac[i] = my_mac[i]; - tx_arp->target_ip = rx_arp->sender_ip; + tx_arp->target_ip = htonl(ntohl(rx_arp->sender_ip)); for(i=0;i<6;i++) tx_arp->target_mac[i] = rx_arp->sender_mac[i]; send_packet(); @@ -210,7 +213,7 @@ static const unsigned char broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; int microudp_arp_resolve(unsigned int ip) { - struct arp_frame *arp = &txbuffer->frame.contents.arp; + struct arp_frame *arp; int i; int tries; int timeout; @@ -230,17 +233,19 @@ int microudp_arp_resolve(unsigned int ip) my_mac, ETHERTYPE_ARP); txlen = ARP_PACKET_LENGTH; - arp->hwtype = ARP_HWTYPE_ETHERNET; - arp->proto = ARP_PROTO_IP; + arp = &txbuffer->frame.contents.arp; + arp->hwtype = htons(ARP_HWTYPE_ETHERNET); + arp->proto = htons(ARP_PROTO_IP); arp->hwsize = 6; arp->protosize = 4; - arp->opcode = ARP_OPCODE_REQUEST; - arp->sender_ip = my_ip; + arp->opcode = htons(ARP_OPCODE_REQUEST); + arp->sender_ip = htonl(my_ip); for(i=0;i<6;i++) arp->sender_mac[i] = my_mac[i]; - arp->target_ip = ip; + arp->target_ip = htonl(ip); for(i=0;i<6;i++) arp->target_mac[i] = 0; + send_packet(); /* Do we get a reply ? */ @@ -309,20 +314,20 @@ int microudp_send(unsigned short src_port, unsigned short dst_port, unsigned int txbuffer->frame.contents.udp.ip.version = IP_IPV4; txbuffer->frame.contents.udp.ip.diff_services = 0; - txbuffer->frame.contents.udp.ip.total_length = length + sizeof(struct udp_frame); - txbuffer->frame.contents.udp.ip.identification = 0; - txbuffer->frame.contents.udp.ip.fragment_offset = IP_DONT_FRAGMENT; + txbuffer->frame.contents.udp.ip.total_length = htons(length + sizeof(struct udp_frame)); + txbuffer->frame.contents.udp.ip.identification = htons(0); + txbuffer->frame.contents.udp.ip.fragment_offset = htons(IP_DONT_FRAGMENT); txbuffer->frame.contents.udp.ip.ttl = IP_TTL; h.proto = txbuffer->frame.contents.udp.ip.proto = IP_PROTO_UDP; txbuffer->frame.contents.udp.ip.checksum = 0; - h.src_ip = txbuffer->frame.contents.udp.ip.src_ip = my_ip; - h.dst_ip = txbuffer->frame.contents.udp.ip.dst_ip = cached_ip; - txbuffer->frame.contents.udp.ip.checksum = ip_checksum(0, &txbuffer->frame.contents.udp.ip, - sizeof(struct ip_header), 1); + h.src_ip = txbuffer->frame.contents.udp.ip.src_ip = htonl(my_ip); + h.dst_ip = txbuffer->frame.contents.udp.ip.dst_ip = htonl(cached_ip); + txbuffer->frame.contents.udp.ip.checksum = htons(ip_checksum(0, &txbuffer->frame.contents.udp.ip, + sizeof(struct ip_header), 1)); - txbuffer->frame.contents.udp.udp.src_port = src_port; - txbuffer->frame.contents.udp.udp.dst_port = dst_port; - h.length = txbuffer->frame.contents.udp.udp.length = length + sizeof(struct udp_header); + txbuffer->frame.contents.udp.udp.src_port = htons(src_port); + txbuffer->frame.contents.udp.udp.dst_port = htons(dst_port); + h.length = txbuffer->frame.contents.udp.udp.length = htons(length + sizeof(struct udp_header)); txbuffer->frame.contents.udp.udp.checksum = 0; h.zero = 0; @@ -333,7 +338,7 @@ int microudp_send(unsigned short src_port, unsigned short dst_port, unsigned int } r = ip_checksum(r, &txbuffer->frame.contents.udp.udp, sizeof(struct udp_header)+length, 1); - txbuffer->frame.contents.udp.udp.checksum = r; + txbuffer->frame.contents.udp.udp.checksum = htons(r); send_packet(); @@ -345,19 +350,21 @@ static udp_callback rx_callback; static void process_ip(void) { if(rxlen < (sizeof(struct ethernet_header)+sizeof(struct udp_frame))) return; + struct udp_frame *udp_ip = &rxbuffer->frame.contents.udp; /* We don't verify UDP and IP checksums and rely on the Ethernet checksum solely */ - if(rxbuffer->frame.contents.udp.ip.version != IP_IPV4) return; + if(udp_ip->ip.version != IP_IPV4) return; // check disabled for QEMU compatibility //if(rxbuffer->frame.contents.udp.ip.diff_services != 0) return; - if(rxbuffer->frame.contents.udp.ip.total_length < sizeof(struct udp_frame)) return; + if(ntohs(udp_ip->ip.total_length) < sizeof(struct udp_frame)) return; // check disabled for QEMU compatibility - //if(rxbuffer->frame.contents.udp.ip.fragment_offset != IP_DONT_FRAGMENT) return; - if(rxbuffer->frame.contents.udp.ip.proto != IP_PROTO_UDP) return; - if(rxbuffer->frame.contents.udp.ip.dst_ip != my_ip) return; - if(rxbuffer->frame.contents.udp.udp.length < sizeof(struct udp_header)) return; + //if(ntohs(rxbuffer->frame.contents.udp.ip.fragment_offset) != IP_DONT_FRAGMENT) return; + if(udp_ip->ip.proto != IP_PROTO_UDP) return; + if(ntohl(udp_ip->ip.dst_ip) != my_ip) return; + if(ntohs(udp_ip->udp.length) < sizeof(struct udp_header)) return; if(rx_callback) - rx_callback(rxbuffer->frame.contents.udp.ip.src_ip, rxbuffer->frame.contents.udp.udp.src_port, rxbuffer->frame.contents.udp.udp.dst_port, rxbuffer->frame.contents.udp.payload, rxbuffer->frame.contents.udp.udp.length-sizeof(struct udp_header)); + rx_callback(ntohl(udp_ip->ip.src_ip), ntohs(udp_ip->udp.src_port), ntohs(udp_ip->udp.dst_port), + udp_ip->payload, ntohs(udp_ip->udp.length)-sizeof(struct udp_header)); } void microudp_set_callback(udp_callback callback) @@ -397,8 +404,8 @@ static void process_frame(void) rxlen -= 4; /* strip CRC here to be consistent with TX */ #endif - if(rxbuffer->frame.eth_header.ethertype == ETHERTYPE_ARP) process_arp(); - else if(rxbuffer->frame.eth_header.ethertype == ETHERTYPE_IP) process_ip(); + if(ntohs(rxbuffer->frame.eth_header.ethertype) == ETHERTYPE_ARP) process_arp(); + else if(ntohs(rxbuffer->frame.eth_header.ethertype) == ETHERTYPE_IP) process_ip(); } void microudp_start(const unsigned char *macaddr, unsigned int ip)