Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BIOS: Add BOOTP support #2070

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 60 additions & 9 deletions litex/soc/software/bios/boot.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include "sfl.h"
#include "boot.h"

#include <bios/helpers.h>

#include <libbase/uart.h>

#include <libbase/console.h>
Expand All @@ -29,6 +31,7 @@
#include <libbase/progress.h>

#include <libliteeth/udp.h>
#include <libliteeth/bootp.h>
#include <libliteeth/tftp.h>

#include <liblitesdcard/spisdcard.h>
Expand Down Expand Up @@ -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
}

Expand Down
1 change: 1 addition & 0 deletions litex/soc/software/bios/boot.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions litex/soc/software/bios/cmds/cmd_boot.c
Original file line number Diff line number Diff line change
Expand Up @@ -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

/**
Expand Down
6 changes: 6 additions & 0 deletions litex/soc/software/bios/helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
1 change: 1 addition & 0 deletions litex/soc/software/bios/helpers.h
Original file line number Diff line number Diff line change
@@ -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);
Expand Down
2 changes: 1 addition & 1 deletion litex/soc/software/libliteeth/Makefile
Original file line number Diff line number Diff line change
@@ -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

Expand Down
193 changes: 193 additions & 0 deletions litex/soc/software/libliteeth/bootp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
// This file is Copyright (c) 2024 Matthias Breithaupt <[email protected]>

// License: BSD

#include <stdio.h>
#include <stdint.h>
#include <string.h>

#include <libbase/lfsr.h>

#include <libliteeth/inet.h>
#include <libliteeth/udp.h>
#include <libliteeth/bootp.h>

#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;
}
21 changes: 21 additions & 0 deletions litex/soc/software/libliteeth/bootp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#ifndef __BOOTP_H
#define __BOOTP_H

#ifdef __cplusplus
extern "C" {
#endif

#include <stdint.h>

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 */

Loading