From 8d65ec43823423088fe95676f08bf39d151b63f9 Mon Sep 17 00:00:00 2001 From: Matthias Breithaupt Date: Thu, 12 Sep 2024 07:50:52 +0200 Subject: [PATCH 1/5] bios: add helper print_ip Signed-off-by: Matthias Breithaupt --- litex/soc/software/bios/helpers.c | 6 ++++++ litex/soc/software/bios/helpers.h | 1 + 2 files changed, 7 insertions(+) diff --git a/litex/soc/software/bios/helpers.c b/litex/soc/software/bios/helpers.c index 6b384ec0e6..fbff7ae202 100644 --- a/litex/soc/software/bios/helpers.c +++ b/litex/soc/software/bios/helpers.c @@ -15,6 +15,12 @@ extern unsigned int _ftext, _edata_rom; +void print_ip(uint32_t ip) +{ + printf("%d.%d.%d.%d", (uint8_t)(ip >> 24), (uint8_t)(ip >> 16), + (uint8_t)(ip >> 8), (uint8_t)ip); +} + #define NUMBER_OF_BYTES_ON_A_LINE 16 void dump_bytes(unsigned int *ptr, int count, unsigned long addr) { diff --git a/litex/soc/software/bios/helpers.h b/litex/soc/software/bios/helpers.h index 23853afce1..2e9541b095 100644 --- a/litex/soc/software/bios/helpers.h +++ b/litex/soc/software/bios/helpers.h @@ -1,6 +1,7 @@ #ifndef __HELPERS_H__ #define __HELPERS_H__ +void print_ip(uint32_t ip); void dump_bytes(unsigned int *ptr, int count, unsigned long addr); void crcbios(void); int get_param(char *buf, char **cmd, char **params); From ba59cd682d9aeb53301b238874f55253a00ca811 Mon Sep 17 00:00:00 2001 From: Matthias Breithaupt Date: Thu, 12 Sep 2024 08:30:51 +0200 Subject: [PATCH 2/5] bios: make libliteeth/udp more portable By moving from platform dependent types like `unsigned int` to cross-platform types like `uint32_t`, the behavior will remain as expected even on different platforms/compilers. I got some warnings when compiling for the simulator that hinted at a potential problem with the previous code. Signed-off-by: Matthias Breithaupt --- litex/soc/software/libliteeth/udp.c | 125 ++++++++++++++-------------- litex/soc/software/libliteeth/udp.h | 12 +-- 2 files changed, 68 insertions(+), 69 deletions(-) diff --git a/litex/soc/software/libliteeth/udp.c b/litex/soc/software/libliteeth/udp.c index 881b4f542e..ce57326341 100644 --- a/litex/soc/software/libliteeth/udp.c +++ b/litex/soc/software/libliteeth/udp.c @@ -32,14 +32,14 @@ struct ethernet_header { #ifndef HW_PREAMBLE_CRC - unsigned char preamble[8]; + uint8_t preamble[8]; #endif - unsigned char destmac[6]; - unsigned char srcmac[6]; - unsigned short ethertype; + uint8_t destmac[6]; + uint8_t srcmac[6]; + uint16_t ethertype; } __attribute__((packed)); -static void fill_eth_header(struct ethernet_header *h, const unsigned char *destmac, const unsigned char *srcmac, unsigned short ethertype) +static void fill_eth_header(struct ethernet_header *h, const uint8_t *destmac, const uint8_t *srcmac, uint16_t ethertype) { int i; @@ -67,16 +67,16 @@ static void fill_eth_header(struct ethernet_header *h, const unsigned char *dest #define ARP_OPCODE_REPLY 0x0002 struct arp_frame { - unsigned short hwtype; - unsigned short proto; - unsigned char hwsize; - unsigned char protosize; - unsigned short opcode; - unsigned char sender_mac[6]; - unsigned int sender_ip; - unsigned char target_mac[6]; - unsigned int target_ip; - unsigned char padding[18]; + uint16_t hwtype; + uint16_t proto; + uint8_t hwsize; + uint8_t protosize; + uint16_t opcode; + uint8_t sender_mac[6]; + uint32_t sender_ip; + uint8_t target_mac[6]; + uint32_t target_ip; + uint8_t padding[18]; } __attribute__((packed)); #define IP_IPV4 0x45 @@ -85,23 +85,23 @@ struct arp_frame { #define IP_PROTO_UDP 0x11 struct ip_header { - unsigned char version; - unsigned char diff_services; - unsigned short total_length; - unsigned short identification; - unsigned short fragment_offset; - unsigned char ttl; - unsigned char proto; - unsigned short checksum; - unsigned int src_ip; - unsigned int dst_ip; + uint8_t version; + uint8_t diff_services; + uint16_t total_length; + uint16_t identification; + uint16_t fragment_offset; + uint8_t ttl; + uint8_t proto; + uint16_t checksum; + uint32_t src_ip; + uint32_t dst_ip; } __attribute__((packed)); struct udp_header { - unsigned short src_port; - unsigned short dst_port; - unsigned short length; - unsigned short checksum; + uint16_t src_port; + uint16_t dst_port; + uint16_t length; + uint16_t checksum; } __attribute__((packed)); struct udp_frame { @@ -120,15 +120,15 @@ struct ethernet_frame { typedef union { struct ethernet_frame frame; - unsigned char raw[ETHMAC_SLOT_SIZE]; + uint8_t raw[ETHMAC_SLOT_SIZE]; } ethernet_buffer; -static unsigned int rxslot; -static unsigned int rxlen; +static uint32_t rxslot; +static uint32_t rxlen; static ethernet_buffer *rxbuffer; -static unsigned int txslot; -static unsigned int txlen; +static uint32_t txslot; +static uint32_t txlen; static ethernet_buffer *txbuffer; static void send_packet(void) @@ -138,7 +138,7 @@ static void send_packet(void) /* fill txbuffer */ #ifndef HW_PREAMBLE_CRC - unsigned int crc; + uint32_t crc; crc = crc32(&txbuffer->raw[8], txlen-8); txbuffer->raw[txlen ] = (crc & 0xff); txbuffer->raw[txlen+1] = (crc & 0xff00) >> 8; @@ -165,15 +165,15 @@ static void send_packet(void) txbuffer = (ethernet_buffer *)(ETHMAC_BASE + ETHMAC_SLOT_SIZE * (ETHMAC_RX_SLOTS + txslot)); } -static unsigned char my_mac[6]; -static unsigned int my_ip; +static uint8_t my_mac[6]; +static uint32_t my_ip; -void udp_set_ip(unsigned int ip) +void udp_set_ip(uint32_t ip) { my_ip = ip; } -void udp_set_mac(const unsigned char *macaddr) +void udp_set_mac(const uint8_t *macaddr) { int i; for(i=0;i<6;i++) @@ -181,8 +181,8 @@ void udp_set_mac(const unsigned char *macaddr) } /* ARP cache - one entry only */ -static unsigned char cached_mac[6]; -static unsigned int cached_ip; +static uint8_t cached_mac[6]; +static uint32_t cached_ip; static void process_arp(void) { @@ -229,9 +229,9 @@ static void process_arp(void) } } -static const unsigned char broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const uint8_t broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -int udp_arp_resolve(unsigned int ip) +int udp_arp_resolve(uint32_t ip) { struct arp_frame *arp; int i; @@ -279,16 +279,16 @@ int udp_arp_resolve(unsigned int ip) return 0; } -static unsigned short ip_checksum(unsigned int r, void *buffer, unsigned int length, int complete) +static uint16_t ip_checksum(uint32_t r, void *buffer, uint32_t length, int complete) { - unsigned char *ptr; - unsigned int i; + uint8_t *ptr; + uint32_t i; - ptr = (unsigned char *)buffer; + ptr = (uint8_t *)buffer; length >>= 1; for(i=0;i> 16) @@ -308,17 +308,17 @@ void *udp_get_tx_buffer(void) } struct pseudo_header { - unsigned int src_ip; - unsigned int dst_ip; - unsigned char zero; - unsigned char proto; - unsigned short length; + uint32_t src_ip; + uint32_t dst_ip; + uint8_t zero; + uint8_t proto; + uint16_t length; } __attribute__((packed)); -int udp_send(unsigned short src_port, unsigned short dst_port, unsigned int length) +int udp_send(uint16_t src_port, uint16_t dst_port, uint32_t length) { struct pseudo_header h; - unsigned int r; + uint32_t r; if((cached_mac[0] == 0) && (cached_mac[1] == 0) && (cached_mac[2] == 0) && (cached_mac[3] == 0) && (cached_mac[4] == 0) && (cached_mac[5] == 0)) @@ -412,12 +412,12 @@ static void process_frame(void) #endif #ifndef HW_PREAMBLE_CRC - unsigned int received_crc; - unsigned int computed_crc; - received_crc = ((unsigned int)rxbuffer->raw[rxlen-1] << 24) - |((unsigned int)rxbuffer->raw[rxlen-2] << 16) - |((unsigned int)rxbuffer->raw[rxlen-3] << 8) - |((unsigned int)rxbuffer->raw[rxlen-4]); + uint32_t received_crc; + uint32_t computed_crc; + received_crc = ((uint32_t)rxbuffer->raw[rxlen-1] << 24) + |((uint32_t)rxbuffer->raw[rxlen-2] << 16) + |((uint32_t)rxbuffer->raw[rxlen-3] << 8) + |((uint32_t)rxbuffer->raw[rxlen-4]); computed_crc = crc32(&rxbuffer->raw[8], rxlen-12); if(received_crc != computed_crc) return; @@ -428,12 +428,11 @@ static void process_frame(void) else if(ntohs(rxbuffer->frame.eth_header.ethertype) == ETHERTYPE_IP) process_ip(); } -void udp_start(const unsigned char *macaddr, unsigned int ip) +void udp_start(const uint8_t *macaddr, uint32_t ip) { int i; ethmac_sram_reader_ev_pending_write(ETHMAC_EV_SRAM_READER); ethmac_sram_writer_ev_pending_write(ETHMAC_EV_SRAM_WRITER); - udp_set_ip(ip); udp_set_mac(macaddr); diff --git a/litex/soc/software/libliteeth/udp.h b/litex/soc/software/libliteeth/udp.h index 854065179d..a0a8789e18 100644 --- a/litex/soc/software/libliteeth/udp.h +++ b/litex/soc/software/libliteeth/udp.h @@ -12,14 +12,14 @@ extern "C" { #define UDP_BUFSIZE (5*1532) -typedef void (*udp_callback)(unsigned int src_ip, unsigned short src_port, unsigned short dst_port, void *data, unsigned int length); +typedef void (*udp_callback)(uint32_t src_ip, uint16_t src_port, uint16_t dst_port, void *data, uint32_t length); -void udp_set_ip(unsigned int ip); -void udp_set_mac(const unsigned char *macaddr); -void udp_start(const unsigned char *macaddr, unsigned int ip); -int udp_arp_resolve(unsigned int ip); +void udp_set_ip(uint32_t ip); +void udp_set_mac(const uint8_t *macaddr); +void udp_start(const uint8_t *macaddr, uint32_t ip); +int udp_arp_resolve(uint32_t ip); void *udp_get_tx_buffer(void); -int udp_send(unsigned short src_port, unsigned short dst_port, unsigned int length); +int udp_send(uint16_t src_port, uint16_t dst_port, uint32_t length); void udp_set_callback(udp_callback callback); void udp_service(void); From b794a246c0f9999cf7e5dd95d628f6b1e696b562 Mon Sep 17 00:00:00 2001 From: Matthias Breithaupt Date: Thu, 12 Sep 2024 08:43:11 +0200 Subject: [PATCH 3/5] bios: add broadcast support to libliteeth/udp This adds support for UDP broadcasts and a helper function to get the currently set IP. These changes are required for BOOTP support. Signed-off-by: Matthias Breithaupt --- litex/soc/software/libliteeth/udp.c | 40 +++++++++++++++++++++++++---- litex/soc/software/libliteeth/udp.h | 3 +++ 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/litex/soc/software/libliteeth/udp.c b/litex/soc/software/libliteeth/udp.c index ce57326341..a149f700be 100644 --- a/litex/soc/software/libliteeth/udp.c +++ b/litex/soc/software/libliteeth/udp.c @@ -173,6 +173,11 @@ void udp_set_ip(uint32_t ip) my_ip = ip; } +uint32_t udp_get_ip(void) +{ + return my_ip; +} + void udp_set_mac(const uint8_t *macaddr) { int i; @@ -184,6 +189,14 @@ void udp_set_mac(const uint8_t *macaddr) static uint8_t cached_mac[6]; static uint32_t cached_ip; +void udp_set_broadcast(void) +{ + int i; + for(i=0;i<6;i++) + cached_mac[i] = 0xFF; + cached_ip = IPTOINT(255, 255, 255, 255); +} + static void process_arp(void) { const struct arp_frame *rx_arp = &rxbuffer->frame.contents.arp; @@ -366,6 +379,7 @@ int udp_send(uint16_t src_port, uint16_t dst_port, uint32_t length) } static udp_callback rx_callback; +static udp_callback bx_callback; static void process_ip(void) { @@ -379,12 +393,22 @@ static void process_ip(void) // check disabled for QEMU compatibility //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(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)); + if(ntohl(udp_ip->ip.dst_ip) != my_ip) { + if(ntohl(udp_ip->ip.dst_ip) == IPTOINT(255, 255, 255, 255) && bx_callback) { + bx_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)); + } + } else { + + if(rx_callback) { + 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)); + } else if(bx_callback) { + bx_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 udp_set_callback(udp_callback callback) @@ -392,6 +416,11 @@ void udp_set_callback(udp_callback callback) rx_callback = callback; } +void udp_set_broadcast_callback(udp_callback callback) +{ + bx_callback = callback; +} + static void process_frame(void) { flush_cpu_dcache(); @@ -447,6 +476,7 @@ void udp_start(const uint8_t *macaddr, uint32_t ip) rxslot = 0; rxbuffer = (ethernet_buffer *)(ETHMAC_BASE + ETHMAC_SLOT_SIZE * rxslot); rx_callback = (udp_callback)0; + bx_callback = (udp_callback)0; } void udp_service(void) diff --git a/litex/soc/software/libliteeth/udp.h b/litex/soc/software/libliteeth/udp.h index a0a8789e18..f36946b274 100644 --- a/litex/soc/software/libliteeth/udp.h +++ b/litex/soc/software/libliteeth/udp.h @@ -15,12 +15,15 @@ extern "C" { typedef void (*udp_callback)(uint32_t src_ip, uint16_t src_port, uint16_t dst_port, void *data, uint32_t length); void udp_set_ip(uint32_t ip); +uint32_t udp_get_ip(void); void udp_set_mac(const uint8_t *macaddr); +void udp_set_broadcast(void); void udp_start(const uint8_t *macaddr, uint32_t ip); int udp_arp_resolve(uint32_t ip); void *udp_get_tx_buffer(void); int udp_send(uint16_t src_port, uint16_t dst_port, uint32_t length); void udp_set_callback(udp_callback callback); +void udp_set_broadcast_callback(udp_callback callback); void udp_service(void); void eth_init(void); From d9ac1e9d1b16e22f4a0bd55fa496dc9fa8f9232d Mon Sep 17 00:00:00 2001 From: Matthias Breithaupt Date: Thu, 12 Sep 2024 08:45:23 +0200 Subject: [PATCH 4/5] bios: add BOOTP support to libliteeth This adds BOOTP support as per RFC 951 and RFC 1532. Since most recent BOOTP servers seem to require the magic cookie defined in RFC 1533, this is also included. N.b.: the secs field is set to the uptime, even though RFC 1532 specifies this as the time since the first BOOTREQUEST. Since the BIOS usually won't be running for that long and the field is often ignored by servers, this felt like a reasonable compromise. Signed-off-by: Matthias Breithaupt --- litex/soc/software/libliteeth/Makefile | 2 +- litex/soc/software/libliteeth/bootp.c | 193 +++++++++++++++++++++++++ litex/soc/software/libliteeth/bootp.h | 21 +++ 3 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 litex/soc/software/libliteeth/bootp.c create mode 100644 litex/soc/software/libliteeth/bootp.h diff --git a/litex/soc/software/libliteeth/Makefile b/litex/soc/software/libliteeth/Makefile index c3cf0b98f5..c26b3fb059 100644 --- a/litex/soc/software/libliteeth/Makefile +++ b/litex/soc/software/libliteeth/Makefile @@ -1,7 +1,7 @@ include ../include/generated/variables.mak include $(SOC_DIRECTORY)/software/common.mak -OBJECTS=udp.o tftp.o mdio.o +OBJECTS=udp.o bootp.o tftp.o mdio.o all: libliteeth.a diff --git a/litex/soc/software/libliteeth/bootp.c b/litex/soc/software/libliteeth/bootp.c new file mode 100644 index 0000000000..01f4567384 --- /dev/null +++ b/litex/soc/software/libliteeth/bootp.c @@ -0,0 +1,193 @@ +// This file is Copyright (c) 2024 Matthias Breithaupt + +// License: BSD + +#include +#include +#include + +#include + +#include +#include +#include + +#define PORT_SERVER 67 +#define PORT_CLIENT 68 + +#define OP_BOOTREQUEST 1 +#define OP_BOOTREPLY 2 + +#define HTYPE_ETHERNET 1 + +#define HLEN_ETHERNET 6 + +#define FLAG_BROADCAST 0x8000 + +#define MAGIC_COOKIE 0x63825363 + +typedef struct { + uint8_t op; + uint8_t htype; + uint8_t hlen; + uint8_t hops; + uint32_t xid; + uint16_t secs; + uint16_t flags; + uint32_t ciaddr; + uint32_t yiaddr; + uint32_t siaddr; + uint32_t giaddr; + uint8_t chaddr[6]; + uint8_t pad[10]; + uint8_t sname[64]; + uint8_t file[128]; + uint32_t cookie; + uint8_t vend[60]; +} __attribute__((packed)) bootp_message; + +static unsigned int seed = 0; + +static void seed_from_mac(const unsigned char* macaddr) +{ + seed = macaddr[2] << 24 | macaddr[3] << 16 | macaddr[4] << 8 | macaddr[5]; +} + +static uint32_t rand32(void) +{ +#ifdef CSR_TIMER0_UPTIME_CYCLES_ADDR + timer0_uptime_latch_write(1); + seed = timer0_uptime_cycles_read(); +#endif + uint32_t ret = lfsr(32, seed); + seed = ret; + return ret; +} + +static int format_request(uint8_t *buf, uint32_t xid, const unsigned char* macaddr) +{ + uint16_t flags = FLAG_BROADCAST; + uint16_t uptime = 0; +#ifdef CSR_TIMER0_UPTIME_CYCLES_ADDR + timer0_uptime_latch_write(1); + uptime = timer0_uptime_cycles_read()/CONFIG_CLOCK_FREQUENCY +#endif + + bootp_message *msg = (bootp_message*) buf; + msg->op = OP_BOOTREQUEST; + msg->htype = HTYPE_ETHERNET; + msg->hlen = HLEN_ETHERNET; + msg->hops = 0; + msg->xid = htonl(xid); + msg->secs = htons(uptime); + msg->flags = htons(flags); + msg->ciaddr = 0; + msg->yiaddr = 0; + msg->siaddr = 0; + msg->giaddr = 0; + memcpy(msg->chaddr, macaddr, 6); + memset(msg->pad, 0, sizeof(msg->pad)); + memset(msg->sname, 0, sizeof(msg->sname)); + memset(msg->file, 0, sizeof(msg->file)); + msg->cookie = htonl(MAGIC_COOKIE); + memset(msg->vend, 0, sizeof(msg->vend)); + return 300; +} + +static uint32_t xid; +static uint8_t response_received; + +static unsigned char mymac[6]; +static uint32_t client_ip; +static uint32_t server_ip; +static char filename[128]; + +static uint8_t got_ip; + +static void rx_callback(uint32_t src_ip, uint16_t src_port, + uint16_t dst_port, void *buf, unsigned int length) +{ + bootp_message *msg; + if(length < 300) return; + msg = (bootp_message*) buf; + if(dst_port != PORT_CLIENT) return; + if(msg->op != OP_BOOTREPLY) return; + if(msg->htype != HTYPE_ETHERNET) return; + if(msg->hlen != HLEN_ETHERNET) return; + if(msg->hops != 0) return; + if(ntohl(msg->xid) != xid) return; + if(memcmp(msg->chaddr, mymac, 6) != 0) return; + client_ip = ntohl(msg->yiaddr); + server_ip = ntohl(msg->siaddr); + memcpy(filename, msg->file, sizeof(filename)); + filename[sizeof(filename) - 1] = 0; + response_received = 1; +} + +int bootp_get(const unsigned char *macaddr, uint32_t *_client_ip, + uint32_t *_server_ip, char *_filename, size_t _len_filename, + uint8_t force) +{ + int len, tries, i; + int ret = -1; + uint8_t *packet_data; + uint8_t len_filename = 128; + + if (_len_filename < 128) { + len_filename = _len_filename; + } + if (got_ip && !force) { + ret = 0; + goto copy; + } + response_received = 0; + memcpy(mymac, macaddr, 6); + + client_ip = udp_get_ip(); + udp_set_ip(IPTOINT(0, 0, 0, 0)); + +#ifndef CSR_TIMER0_UPTIME_CYCLES_ADDR + if(seed == 0) { + seed_from_mac(macaddr); + } +#endif + + udp_set_broadcast_callback((udp_callback) rx_callback); + + tries = 3; + + while(1) { + xid = rand32(); + + packet_data = udp_get_tx_buffer(); + len = format_request(packet_data, xid, macaddr); + + udp_set_broadcast(); + udp_send(PORT_CLIENT, PORT_SERVER, len); + for(i=0;i<100000;i++) { + udp_service(); + if(response_received) break; + } + if(response_received) break; + tries--; + if(tries == 0) { + ret = -1; + goto end; + } + } + + ret = 0; + got_ip = 1; +copy: + *_server_ip = server_ip; + len = strlen(filename); + memcpy(_filename, filename, len_filename); + _filename[len_filename - 1] = 0; + +end: + *_client_ip = client_ip; + udp_set_broadcast_callback(NULL); + udp_set_ip(client_ip); + + return ret; +} diff --git a/litex/soc/software/libliteeth/bootp.h b/litex/soc/software/libliteeth/bootp.h new file mode 100644 index 0000000000..26d4fa2c97 --- /dev/null +++ b/litex/soc/software/libliteeth/bootp.h @@ -0,0 +1,21 @@ +#ifndef __BOOTP_H +#define __BOOTP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +int bootp_get(const unsigned char *macaddr, uint32_t *client_ip, + uint32_t *server_ip, char *filename, size_t len_filename, + uint8_t force); + +int bootp_has_ip(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __BOOTP_H */ + From 94a7cbf6725161ffde18d262d274be6eb2cd22ac Mon Sep 17 00:00:00 2001 From: Matthias Breithaupt Date: Thu, 12 Sep 2024 09:10:18 +0200 Subject: [PATCH 5/5] bios: add bootp to netboot This changes netboot to first try getting IPs and filename via BOOTP. If `netboot` is run multiple times, the assigned values are cached. To update this cache, a new command `bootp` has been added that will always make a new request to the BOOTP server. After updating the cache, `netboot` can be run again. Signed-off-by: Matthias Breithaupt --- litex/soc/software/bios/boot.c | 69 +++++++++++++++++++++---- litex/soc/software/bios/boot.h | 1 + litex/soc/software/bios/cmds/cmd_boot.c | 1 + 3 files changed, 62 insertions(+), 9 deletions(-) diff --git a/litex/soc/software/bios/boot.c b/litex/soc/software/bios/boot.c index 5faa649354..8166249c26 100755 --- a/litex/soc/software/bios/boot.c +++ b/litex/soc/software/bios/boot.c @@ -21,6 +21,8 @@ #include "sfl.h" #include "boot.h" +#include + #include #include @@ -29,6 +31,7 @@ #include #include +#include #include #include @@ -538,34 +541,82 @@ static void netboot_from_bin(const char * filename, unsigned int ip, unsigned sh } #endif +void bootp(void) +{ + uint32_t client_ip; + uint32_t server_ip; + char bootp_filename[64]; + int ret; + + printf("Requesting ip...\n"); + udp_start(macadr, IPTOINT(local_ip[0], local_ip[1], local_ip[2], local_ip[3])); + ret = bootp_get(macadr, &client_ip, &server_ip, (char *) &bootp_filename, sizeof(bootp_filename), 1); + if (ret == 0) { + printf("Local IP: "); + print_ip(client_ip); + printf("\n"); + printf("Remote IP: "); + print_ip(server_ip); + printf("\n"); + } + printf("BOOTP done.\n"); +} + void netboot(int nb_params, char **params) { - unsigned int ip; char * filename = NULL; + char bootp_name[64]; + uint8_t bootp_len; + uint8_t bootp_ret; + uint32_t client_ip; + uint32_t server_ip; if (nb_params > 0 ) filename = params[0]; printf("Booting from network...\n"); - printf("Local IP: %d.%d.%d.%d\n", local_ip[0], local_ip[1], local_ip[2], local_ip[3]); - printf("Remote IP: %d.%d.%d.%d\n", remote_ip[0], remote_ip[1], remote_ip[2], remote_ip[3]); + server_ip = IPTOINT(remote_ip[0], remote_ip[1], remote_ip[2], remote_ip[3]); + if(udp_get_ip() == 0) + udp_start(macadr, IPTOINT(local_ip[0], local_ip[1], local_ip[2], local_ip[3])); - ip = IPTOINT(remote_ip[0], remote_ip[1], remote_ip[2], remote_ip[3]); - udp_start(macadr, IPTOINT(local_ip[0], local_ip[1], local_ip[2], local_ip[3])); + bootp_ret = bootp_get(macadr, &client_ip, &server_ip, (char *) &bootp_name, sizeof(bootp_name), 0); + bootp_len = strlen(bootp_name); - if (filename) { + if(bootp_ret == 0) + printf("Received configuration via BOOTP.\n"); + printf("Local IP: "); + print_ip(client_ip); + printf("\n"); + printf("Remote IP: "); + print_ip(server_ip); + printf("\n"); + + if(bootp_ret == 0 && bootp_len > 0 && bootp_len < sizeof(bootp_name)) { +#ifdef MAIN_RAM_BASE + if(bootp_name[bootp_len - 4] == '.' && bootp_name[bootp_len - 3] == 'b' && + bootp_name[bootp_len - 2] == 'i' && bootp_name[bootp_len - 1] == 'n'){ + printf("Booting from %s...\n", bootp_name); + netboot_from_bin(bootp_name, server_ip, TFTP_SERVER_PORT); + } else { +#else + if(1){ +#endif + printf("Booting from %s (JSON)...\n", bootp_name); + netboot_from_json(bootp_name, server_ip, TFTP_SERVER_PORT); + } + } else if (filename) { printf("Booting from %s (JSON)...\n", filename); - netboot_from_json(filename, ip, TFTP_SERVER_PORT); + netboot_from_json(filename, server_ip, TFTP_SERVER_PORT); } else { /* Boot from boot.json */ printf("Booting from boot.json...\n"); - netboot_from_json("boot.json", ip, TFTP_SERVER_PORT); + netboot_from_json("boot.json", server_ip, TFTP_SERVER_PORT); #ifdef MAIN_RAM_BASE /* Boot from boot.bin */ printf("Booting from boot.bin...\n"); - netboot_from_bin("boot.bin", ip, TFTP_SERVER_PORT); + netboot_from_bin("boot.bin", server_ip, TFTP_SERVER_PORT); #endif } diff --git a/litex/soc/software/bios/boot.h b/litex/soc/software/bios/boot.h index 338312d090..59746764b0 100644 --- a/litex/soc/software/bios/boot.h +++ b/litex/soc/software/bios/boot.h @@ -8,6 +8,7 @@ void set_mac_addr(const char * mac_address); void __attribute__((noreturn)) boot(unsigned long r1, unsigned long r2, unsigned long r3, unsigned long addr); int serialboot(void); void netboot(int nb_params, char **params); +void bootp(void); void flashboot(void); void romboot(void); void sdcardboot(void); diff --git a/litex/soc/software/bios/cmds/cmd_boot.c b/litex/soc/software/bios/cmds/cmd_boot.c index 0a9b0df63e..f7d49ed50d 100644 --- a/litex/soc/software/bios/cmds/cmd_boot.c +++ b/litex/soc/software/bios/cmds/cmd_boot.c @@ -114,6 +114,7 @@ define_command(serialboot, serialboot, "Boot from Serial (SFL)", BOOT_CMDS); */ #ifdef CSR_ETHMAC_BASE define_command(netboot, netboot, "Boot via Ethernet (TFTP)", BOOT_CMDS); +define_command(bootp, bootp, "Request IP (BOOTP)", BOOT_CMDS); #endif /**