URL
https://opencores.org/ocsvn/amber/amber/trunk
Subversion Repositories amber
Compare Revisions
- This comparison shows the changes necessary to convert path
/amber/trunk
- from Rev 79 to Rev 80
- ↔ Reverse comparison
Rev 79 → Rev 80
/sw/boot-loader-serial/fpga-version.h
1,?rev1len? → ?rev2line?,?rev2len?
#define AMBER_FPGA_VERSION "20130506123001" |
#define AMBER_FPGA_VERSION "20130506130110" |
/sw/boot-loader-serial/README.txt
1,2 → 1,2
The boot loader must fit in the boot memory, which is 8KBytes. |
The boot loader must fit in the boot memory, which is 16KBytes. |
Keep an eye on the .mem file to make sure it doesn't get larger than that. |
/sw/boot-loader-ethmac/boot-loader-ethmac.h
File deleted
/sw/boot-loader-ethmac/telnet.h
46,4 → 46,6
void parse_telnet_payload (char *, socket_t*); |
void telnet_options (socket_t*); |
void telnet_tx (socket_t*, line_buf_t*); |
void process_telnet (socket_t*); |
int parse_command (socket_t*, char*); |
|
/sw/boot-loader-ethmac/ethmac.c
51,30 → 51,19
#include "ethmac.h" |
|
|
void close_link (void) |
/* open a link */ |
void init_ethmac() |
{ |
/* Disable EthMac interrupts in Ethmac core */ |
*(unsigned int *) ( ADR_ETHMAC_INT_MASK ) = 0x0; |
/* initialize the packet rx buffer */ |
init_packet(); |
|
/* Disable Ethmac interrupt in interrupt controller */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x100; |
/* open ethernet port and wait for connection requests |
keep trying forever */ |
while (!open_link()); |
} |
|
/* Disable Rx & Tx - MODER Register |
[15] = Add pads to short frames |
[13] = CRCEN |
[10] = Enable full duplex |
[7] = loopback |
[5] = 1 for promiscuous, 0 rx only frames that match mac address |
[1] = txen |
[0] = rxen */ |
*(unsigned int *) ( ADR_ETHMAC_MODER ) = 0xa420; |
|
/* Put the PHY into reset */ |
phy_rst(0); /* reset is active low */ |
|
} |
|
|
/* return 1 if link comes up */ |
int open_link (void) |
{ |
92,7 → 81,8
d32 = self_g.mac[0]<<8|self_g.mac[1]; |
*(unsigned int *) ( ADR_ETHMAC_MAC_ADDR1 ) = d32; |
|
if (!config_phy()) return 0; |
if (!init_phy()) |
return 0; |
|
/* Write the Receive Packet Buffer Descriptor */ |
/* Buffer Pointer */ |
141,6 → 131,31
} |
|
|
|
void close_link (void) |
{ |
/* Disable EthMac interrupts in Ethmac core */ |
*(unsigned int *) ( ADR_ETHMAC_INT_MASK ) = 0x0; |
|
/* Disable Ethmac interrupt in interrupt controller */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x100; |
|
/* Disable Rx & Tx - MODER Register |
[15] = Add pads to short frames |
[13] = CRCEN |
[10] = Enable full duplex |
[7] = loopback |
[5] = 1 for promiscuous, 0 rx only frames that match mac address |
[1] = txen |
[0] = rxen */ |
*(unsigned int *) ( ADR_ETHMAC_MODER ) = 0xa420; |
|
/* Put the PHY into reset */ |
phy_rst(0); /* reset is active low */ |
|
} |
|
|
void tx_packet(int len) |
{ |
unsigned int status = 0; |
170,7 → 185,7
|
|
/* returns 1 if link comes up */ |
int config_phy (void) |
int init_phy (void) |
{ |
int addr; |
int bmcr; |
179,7 → 194,7
int link_up = 1; |
time_t* link_timer; |
|
link_timer = init_timer(); |
link_timer = new_timer(); |
|
/* Bring PHY out of reset */ |
phy_rst(1); /* reset is active low */ |
303,7 → 318,6
rx_buf_status = *(volatile unsigned int *) ( ADR_ETHMAC_BDBASE + 0x200 + buffer*8 ); |
|
if ((rx_buf_status & 0x8000) == 0) { |
|
parse_rx_packet((char*)(ETHMAC_RX_BUFFER+buffer*0x1000), rx_packet_g); |
|
/* set empty flag again */ |
/sw/boot-loader-ethmac/elfsplitter.h
43,11 → 43,11
|
/* |
ELF File Structure |
A single segment usually consist of several sections. E.g., a loadable |
read-only segment could contain sections for executable code, read-only |
data, and symbols for the dynamic linker. Relocatable files have section |
header tables. Executable files have program header tables. Shared object |
files have both. Sections are intended for further processing by a linker, |
A single segment usually consist of several sections. E.g., a loadable |
read-only segment could contain sections for executable code, read-only |
data, and symbols for the dynamic linker. Relocatable files have section |
header tables. Executable files have program header tables. Shared object |
files have both. Sections are intended for further processing by a linker, |
while the segments are intended to be mapped into memory. |
*/ |
|
90,10 → 90,10
} Elf32_Shdr; |
|
|
/* Buffer to hold interrupt vector memory values |
Can't copy these into mem0 locations until ready to pass control |
t new program |
*/ |
/* Buffer to hold interrupt vector memory values |
Can't copy these into mem0 locations until ready to pass control |
t new program |
*/ |
typedef struct { |
char data; |
int valid; |
109,4 → 109,4
mem_buf_t* elf_mem0_g; |
|
/* function prototypes */ |
int elfsplitter (char*, socket_t*); |
int elfsplitter (char*); |
/sw/boot-loader-ethmac/led.c
0,0 → 1,116
/*---------------------------------------------------------------- |
// // |
// boot-loader-ethmac.c // |
// // |
// This file is part of the Amber project // |
// http://www.opencores.org/project,amber // |
// // |
// Description // |
// The main functions for the boot loader application. This // |
// application is embedded in the FPGA's SRAM and is used // |
// to load larger applications into the DDR3 memory on // |
// the development board. // |
// // |
// Author(s): // |
// - Conor Santifort, csantifort.amber@gmail.com // |
// // |
////////////////////////////////////////////////////////////////// |
// // |
// Copyright (C) 2011 Authors and OPENCORES.ORG // |
// // |
// This source file may be used and distributed without // |
// restriction provided that this copyright statement is not // |
// removed from the file and that any derivative work contains // |
// the original copyright notice and the associated disclaimer. // |
// // |
// This source file is free software; you can redistribute it // |
// and/or modify it under the terms of the GNU Lesser General // |
// Public License as published by the Free Software Foundation; // |
// either version 2.1 of the License, or (at your option) any // |
// later version. // |
// // |
// This source is distributed in the hope that it will be // |
// useful, but WITHOUT ANY WARRANTY; without even the implied // |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // |
// PURPOSE. See the GNU Lesser General Public License for more // |
// details. // |
// // |
// You should have received a copy of the GNU Lesser General // |
// Public License along with this source; if not, download it // |
// from http://www.opencores.org/lgpl.shtml // |
// // |
----------------------------------------------------------------*/ |
|
#include "amber_registers.h" |
#include "timer.h" |
#include "led.h" |
|
|
/* global variables */ |
time_t* led_flash_timer_g; |
|
|
void init_led() |
{ |
/* Turn off all LEDs */ |
led_clear(); |
|
/* create some timers */ |
led_flash_timer_g = new_timer(); |
set_timer(led_flash_timer_g, 500); |
} |
|
|
void process_led() |
{ |
/* Flash a heartbeat LED */ |
if (timer_expired(led_flash_timer_g)) { |
led_flip(0); |
set_timer(led_flash_timer_g, 500); |
} |
} |
|
|
/* turn off all leds */ |
void led_clear() |
{ |
*(unsigned int *) ADR_AMBER_TEST_LED = 0; |
} |
|
|
/* led is either 0,1,2 or 3 */ |
void led_flip(int led) |
{ |
int current_value; |
current_value = *(unsigned int *) ADR_AMBER_TEST_LED; |
*(unsigned int *) ADR_AMBER_TEST_LED = current_value ^ (1<<led); |
} |
|
|
|
/* led is either 0,1,2 or 3 */ |
void led_on(int led) |
{ |
int current_value; |
current_value = *(unsigned int *) ADR_AMBER_TEST_LED; |
*(unsigned int *) ADR_AMBER_TEST_LED = current_value | (1<<led); |
} |
|
|
|
/* led is either 0,1,2 or 3 */ |
void led_off(int led) |
{ |
int current_value; |
current_value = *(unsigned int *) ADR_AMBER_TEST_LED; |
*(unsigned int *) ADR_AMBER_TEST_LED = current_value & ~(1<<led); |
} |
|
|
/* led is either 0,1,2 or 3 */ |
void led_123(int value) |
{ |
int current_value; |
current_value = *(unsigned int *) ADR_AMBER_TEST_LED; |
*(unsigned int *) ADR_AMBER_TEST_LED = (current_value & 1) | value<<1; |
} |
/sw/boot-loader-ethmac/boot-loader-ethmac.c
41,307 → 41,70
// // |
----------------------------------------------------------------*/ |
|
#include "amber_registers.h" |
#include "address_map.h" |
#include "line-buffer.h" |
#include "timer.h" |
#include "utilities.h" |
#include "packet.h" |
#include "ethmac.h" |
#include "packet.h" |
#include "tcp.h" |
#include "udp.h" |
#include "telnet.h" |
#include "serial.h" |
|
#include "elfsplitter.h" |
#include "boot-loader-ethmac.h" |
|
|
|
int main ( void ) { |
char* line; |
time_t* led_flash_timer; |
time_t* reboot_timer; |
socket_t* socket = socket0_g; |
int reboot_stage = 0; |
socket_t* socket; |
|
|
/* Enable the serial debug port */ |
init_serial(); |
print_serial("Amber debug port\n\r"); |
|
|
/* Turn off all LEDs */ |
led_clear(); |
|
|
/* initialize the memory allocation system */ |
init_malloc(); |
|
/* Enable the hardware timer to generate interrrupts 100 timer per second, |
current time will start incrementing from this point onwards */ |
init_timer(); |
|
/* Initialize current time and some timers */ |
init_current_time(); |
led_flash_timer = init_timer(); |
set_timer(led_flash_timer, 500); |
reboot_timer = init_timer(); |
/* Create a timer to flash a led periodically */ |
init_led(); |
|
/* initialize the tftp stuff */ |
init_tftp(); |
|
/* receive packet buffer */ |
rx_packet_g = malloc(sizeof(packet_t)); |
|
/* create a tcp socket for listening */ |
first_socket_g = new_socket(NULL); |
socket = first_socket_g; |
|
/* initialize two tcp sockets */ |
socket0_g = init_socket(0); |
socket1_g = init_socket(1); |
/* initialize the PHY and MAC and listen for connections |
This is the last init because packets will be received from this point |
onwards. */ |
init_ethmac(); |
|
|
/* open ethernet port and wait for connection requests |
keep trying forever */ |
while (!open_link()); |
|
|
/* infinite loop. Everything is timer, interrupt and queue driven from here on down */ |
/* Process loop. Everything is timer, interrupt and queue driven from here on down */ |
while (1) { |
|
/* Flash a heartbeat LED */ |
if (timer_expired(led_flash_timer)) { |
led_flip(0); |
set_timer(led_flash_timer, 500); |
} |
/* flash an led */ |
process_led(); |
|
/* Check for received tftp files and reboot */ |
process_tftp(); |
|
/* Check for newly downloaded tftp file. Add to all tx buffers */ |
/* Has a file been uploaded via tftp ? */ |
if (udp_file_g != NULL) { |
/* Notify telnet clients that file has been received */ |
if (udp_file_g->ready) { |
udp_file_g->ready = 0; |
|
print_serial("Received file %s, %d bytes", |
udp_file_g->filename, udp_file_g->total_bytes); |
if (udp_file_g->linux_boot) |
print_serial(", linux image detected\r\n"); |
else |
print_serial("\r\n"); |
|
if (process_file(socket0_g) == 0) { |
/* Disconnect in 1 second */ |
set_timer(reboot_timer, 1000); |
} |
else |
print_serial("Not an elf file\r\n"); |
} |
} |
|
|
/* reboot timer expired */ |
if (timer_expired(reboot_timer)) { |
/* First stage of reboot sequence is to nicely disconnect */ |
if (reboot_stage == 0) { |
set_timer(reboot_timer, 1000); |
reboot_stage = 1; |
socket0_g->tcp_disconnect = 1; |
socket1_g->tcp_disconnect = 1; |
} |
else { |
/* Second stage of reboot sequence is to turn off ethmac and then jump to restart vector */ |
close_link(); |
reboot(); |
} |
} |
|
|
/* Poll both sockets in turn for activity */ |
if (socket == socket0_g) |
socket = socket1_g; |
/* handle tcp connections and process buffers */ |
/* Poll all sockets in turn for activity */ |
if (socket->next == NULL) |
socket = first_socket_g; |
else |
socket = socket0_g; |
socket = socket->next; |
|
|
/* Check if any tcp packets need to be re-transmitted */ |
tcp_retransmit(socket); |
|
|
/* Handle exit command */ |
if (socket->tcp_disconnect && socket->tcp_connection_state == TCP_OPEN) { |
tcp_disconnect(socket); |
} |
|
|
/* Reset connection */ |
if (socket->tcp_reset) { |
socket->tcp_connection_state = TCP_CLOSED; |
socket->telnet_connection_state = TELNET_CLOSED; |
socket->telnet_options_sent = 0; |
tcp_reply(socket, NULL, 0); |
socket->tcp_reset = 0; |
} |
|
|
/* Send telnet options */ |
if (socket->tcp_connection_state == TCP_OPEN && !socket->telnet_options_sent){ |
telnet_options(socket); |
socket->telnet_options_sent = 1; |
} |
|
/* telnet connection open |
Communicate with client */ |
else if (socket->telnet_connection_state == TELNET_OPEN) { |
/* Send telnet greeting */ |
if (!socket->telnet_sent_opening_message){ |
put_line (socket->telnet_txbuf, "Amber Processor Boot Loader\r\n> "); |
socket->telnet_sent_opening_message = 1; |
} |
|
/* Parse telnet rx buffer */ |
if (get_line(socket->telnet_rxbuf, &line)) |
parse_command (socket, line); |
|
/* Transmit text from telnet tx buffer */ |
telnet_tx(socket, socket->telnet_txbuf); |
} |
process_tcp(socket); |
} |
} |
|
|
|
/* Parse a command line passed from main and execute the command */ |
/* returns the length of the reply string */ |
int parse_command (socket_t* socket, char* line) |
{ |
unsigned int start_addr; |
unsigned int address; |
unsigned int range; |
int len, error = 0; |
|
/* All commands are just a single character. |
Just ignore anything else */ |
switch (line[0]) { |
/* Disconnect */ |
case 'e': |
case 'x': |
case 'q': |
socket->tcp_disconnect = 1; |
return 0; |
|
case 'r': /* Read mem */ |
{ |
if (len = get_hex (&line[2], &start_addr)) { |
if (len = get_hex (&line[3+len], &range)) { |
for (address=start_addr; address<start_addr+range; address+=4) { |
put_line (socket->telnet_txbuf, "0x%08x 0x%08x\r\n", |
address, *(unsigned int *)address); |
} |
} |
else { |
put_line (socket->telnet_txbuf, "0x%08x 0x%08x\r\n", |
start_addr, *(unsigned int *)start_addr); |
} |
} |
else |
error=1; |
break; |
} |
|
|
case 'h': {/* Help */ |
put_line (socket->telnet_txbuf, "You need help alright\r\n"); |
break; |
} |
|
|
case 's': {/* Status */ |
put_line (socket->telnet_txbuf, "Socket ID %d\r\n", socket->id); |
put_line (socket->telnet_txbuf, "Packets received %d\r\n", socket->packets_received); |
put_line (socket->telnet_txbuf, "Packets transmitted %d\r\n", socket->packets_sent); |
put_line (socket->telnet_txbuf, "Packets resent %d\r\n", socket->packets_resent); |
put_line (socket->telnet_txbuf, "TCP checksum errors %d\r\n", tcp_checksum_errors_g); |
|
put_line (socket->telnet_txbuf, "Counterparty IP %d.%d.%d.%d\r\n", |
socket->rx_packet->src_ip[0], |
socket->rx_packet->src_ip[1], |
socket->rx_packet->src_ip[2], |
socket->rx_packet->src_ip[3]); |
|
put_line (socket->telnet_txbuf, "Counterparty Port %d\r\n", |
socket->rx_packet->tcp_src_port); |
|
put_line (socket->telnet_txbuf, "Malloc pointer 0x%08x\r\n", |
*(unsigned int *)(ADR_MALLOC_POINTER)); |
put_line (socket->telnet_txbuf, "Malloc count %d\r\n", |
*(unsigned int *)(ADR_MALLOC_COUNT)); |
put_line (socket->telnet_txbuf, "Uptime %d seconds\r\n", current_time_g->seconds); |
break; |
} |
|
|
default: { |
error=1; break; |
} |
} |
|
|
if (error) |
put_line (socket->telnet_txbuf, "You're not making any sense\r\n", |
line[0], line[1], line[2]); |
|
put_line (socket->telnet_txbuf, "> "); |
return 0; |
} |
|
|
/* copy tftp file into a single contiguous buffer so |
if can be processed by elf splitter */ |
int process_file(socket_t* socket) |
{ |
block_t* block; |
char* buf512; |
char* tftp_file; |
char* line; |
int line_len; |
int ret; |
|
tftp_file = malloc(udp_file_g->total_bytes); |
|
block = udp_file_g; |
buf512= tftp_file; |
|
while (block->next) { |
memcpy(buf512, block->buf512, block->bytes); |
buf512=&buf512[512]; |
block=block->next; |
} |
memcpy(buf512, block->buf512, block->bytes); |
buf512=&buf512[512]; |
|
return elfsplitter(tftp_file, socket); |
} |
|
|
/* Disable interrupts |
Load new values into the interrupt vector memory space |
Jump to address 0 |
*/ |
void reboot() |
{ |
int i; |
|
/* Disable all interrupts */ |
/* Disable ethmac_int interrupt */ |
/* Disable timer 0 interrupt in interrupt controller */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x120; |
|
for(i=0;i<MEM_BUF_ENTRIES;i++) |
if (elf_mem0_g->entry[i].valid) |
*(char *)(i) = elf_mem0_g->entry[i].data; |
|
if (udp_file_g->linux_boot) { |
print_serial("linux reboot\n\r"); |
_jump_to_program(LINUX_JUMP_ADR); |
} |
else { |
print_serial("normal reboot\n\r"); |
_restart(); |
} |
} |
|
/sw/boot-loader-ethmac/ethmac.h
38,11 → 38,14
// // |
----------------------------------------------------------------*/ |
|
/* Global variables */ |
extern packet_t* rx_packet_g; |
|
/* Function prototypes */ |
void init_ethmac (void); |
int open_link (void); |
void close_link (void); |
int config_phy (void); |
int init_phy (void); |
|
void mdio_ready (); |
int mdio_read (int addr, int reg); |
/sw/boot-loader-ethmac/packet.c
7,7 → 7,7
// // |
// Description // |
// The main functions for the boot loader application. This // |
// application is embedded in the FPGA's SRAM and is used // |
// application is embedded in the FPGA's SRAM and is used // |
// to load larger applications into the DDR3 memory on // |
// the development board. // |
// // |
56,66 → 56,17
{192, 168, 0, 17} /* IPv4 address */ |
}; |
|
|
packet_t* rx_packet_g; |
socket_t* socket0_g; |
socket_t* socket1_g; |
|
|
|
socket_t* init_socket(int socket_id) |
void init_packet() |
{ |
socket_t* socket; |
|
socket = (socket_t*) malloc(sizeof(socket_t)); |
socket->rx_packet =(packet_t*) malloc(sizeof(packet_t)); |
init_packet_buffers(socket); |
|
socket->telnet_txbuf = init_line_buffer(0x80000); |
socket->telnet_rxbuf = init_line_buffer(0x1000); |
|
socket->id = socket_id; |
|
socket->packets_sent = 0; |
socket->packets_received = 0; |
socket->packets_resent = 0; |
|
socket->telnet_sent_opening_message = 0; |
socket->telnet_echo_mode = 0; |
socket->telnet_connection_state = TELNET_CLOSED; |
socket->telnet_options_sent = 0; |
|
socket->tcp_current_buf = 0; |
socket->tcp_reset = 0; |
socket->tcp_connection_state = TCP_CLOSED; |
socket->tcp_disconnect = 0; |
socket->tcp_seq = 0x100; /* should be random initial seq number for tcp */ |
socket->tcp_last_seq = socket->tcp_seq; |
socket->tcp_last_ack = 0; |
|
return socket; |
/* receive packet buffer */ |
rx_packet_g = malloc(sizeof(packet_t)); |
} |
|
|
void init_packet_buffers (socket_t* socket) |
{ |
int i; |
|
/* Create space for an array of pointers */ |
socket->tcp_buf = malloc (TCP_TX_BUFFERS * sizeof (void *)); |
|
/* Create space for a set of buffers, each pointed to by an element of the array */ |
for (i=0;i<TCP_TX_BUFFERS;i=i+1) { |
socket->tcp_buf[i] = (packet_buffer_t*) malloc (sizeof (packet_buffer_t)); |
socket->tcp_buf[i]->payload_valid = 0; |
socket->tcp_buf[i]->starting_seq = 0; |
socket->tcp_buf[i]->ending_seq = 0; |
socket->tcp_buf[i]->len_bytes = 0; |
socket->tcp_buf[i]->ack_received = 0; |
} |
} |
|
|
void ethernet_header(char *buf, mac_ip_t* target, unsigned short type) |
{ |
/* ethernet header */ |
126,7 → 77,7
buf[ 3] = target->mac[3]; |
buf[ 4] = target->mac[4]; |
buf[ 5] = target->mac[5]; |
|
|
/* SA */ |
buf[ 6] = self_g.mac[0]; |
buf[ 7] = self_g.mac[1]; |
134,7 → 85,7
buf[ 9] = self_g.mac[3]; |
buf[10] = self_g.mac[4]; |
buf[11] = self_g.mac[5]; |
|
|
/* type */ |
buf[12] = type>>8; |
buf[13] = type&0xff; |
147,46 → 98,46
static unsigned short ip_id = 0; |
|
/* Version, Header length */ |
buf[0] = 0x45; |
|
buf[0] = 0x45; |
|
/* dscp */ |
buf[1] = 0; |
|
|
/* ip len */ |
buf[2] = ip_len>>8; |
buf[2] = ip_len>>8; |
buf[3] = ip_len&0xff; |
|
|
/* ID */ |
buf[4] = (ip_id>>8)&0xff; |
buf[5] = ip_id&0xff; |
buf[5] = ip_id&0xff; |
//ip_id++; |
|
|
/* Fragment */ |
buf[6] = 0; |
buf[7] = 0; |
|
|
/* ttl */ |
buf[8] = 64; |
|
|
/* Protocol */ |
buf[9] = ip_proto; |
|
|
/* header checksum */ |
buf[10] = 0; |
buf[11] = 0; |
|
|
/* Source IP */ |
buf[12] = self_g.ip[0]; |
buf[13] = self_g.ip[1]; |
buf[14] = self_g.ip[2]; |
buf[15] = self_g.ip[3]; |
|
|
/* Destination IP */ |
buf[16] = target->ip[0]; |
buf[17] = target->ip[1]; |
buf[18] = target->ip[2]; |
buf[19] = target->ip[3]; |
|
|
/* header checksum */ |
header_checksum = header_checksum16(buf, 20, 0); |
buf[10] = (header_checksum>>8)&0xff; |
198,7 → 149,7
{ |
|
ethernet_header(buf, arp_sender, 0x0806); |
|
|
/* Hardware Type */ |
buf[14] = 0x00; |
buf[15] = 0x01; |
209,11 → 160,11
buf[18] = 0x06; |
/* PLEN */ |
buf[19] = 0x04; |
|
|
/* Operation = Reply */ |
buf[20] = 0x00; |
buf[21] = 0x02; |
|
|
/* Sender MAC */ |
buf[22] = self_g.mac[0]; |
buf[23] = self_g.mac[1]; |
221,13 → 172,13
buf[25] = self_g.mac[3]; |
buf[26] = self_g.mac[4]; |
buf[27] = self_g.mac[5]; |
|
|
/* Sender IP */ |
buf[28] = self_g.ip[0]; |
buf[29] = self_g.ip[1]; |
buf[30] = self_g.ip[2]; |
buf[31] = self_g.ip[3]; |
|
|
/* Target MAC */ |
buf[32] = arp_sender->mac[0]; |
buf[33] = arp_sender->mac[1]; |
235,7 → 186,7
buf[35] = arp_sender->mac[3]; |
buf[36] = arp_sender->mac[4]; |
buf[37] = arp_sender->mac[5]; |
|
|
/* Target IP */ |
buf[38] = arp_sender->ip[0]; |
buf[39] = arp_sender->ip[1]; |
252,7 → 203,7
unsigned short header_checksum; |
mac_ip_t target; |
char * buf = (char*)ETHMAC_TX_BUFFER; |
|
|
target.mac[0] = rx_packet->src_mac[0]; |
target.mac[1] = rx_packet->src_mac[1]; |
target.mac[2] = rx_packet->src_mac[2]; |
259,7 → 210,7
target.mac[3] = rx_packet->src_mac[3]; |
target.mac[4] = rx_packet->src_mac[4]; |
target.mac[5] = rx_packet->src_mac[5]; |
|
|
target.ip[0] = rx_packet->src_ip[0]; |
target.ip[1] = rx_packet->src_ip[1]; |
target.ip[2] = rx_packet->src_ip[2]; |
267,22 → 218,22
|
ethernet_header(buf, &target, 0x0800); /*bytes 0 to 13*/ |
ip_header(&buf[14], &target, rx_packet->ip_len, 1); /* bytes 14 to 33, ip_proto = 1, ICMP*/ |
|
|
/* ICMP */ |
/* Type = reply */ |
buf[34] = 0; |
|
|
/* Code = 0 */ |
buf[35] = 0; |
|
|
/* checksum */ |
buf[36] = 0; |
buf[37] = 0; |
|
|
/* ID */ |
buf[38] = ping_id>>8; |
buf[39] = ping_id&0xff; |
|
|
/* SEQ */ |
buf[40] = ping_seq>>8; |
buf[41] = ping_seq&0xff; |
301,7 → 252,7
void parse_rx_packet(char * buf, packet_t* rx_packet) |
{ |
int i; |
|
|
rx_packet->dst_mac[0] = buf[0]; |
rx_packet->dst_mac[1] = buf[1]; |
rx_packet->dst_mac[1] = buf[2]; |
314,10 → 265,10
rx_packet->src_mac[2] = buf[8]; |
rx_packet->src_mac[3] = buf[9]; |
rx_packet->src_mac[4] = buf[10]; |
rx_packet->src_mac[5] = buf[11]; |
rx_packet->src_mac[5] = buf[11]; |
rx_packet->eth_type = (buf[12]<<8) + buf[13]; |
|
|
|
|
/* ARP */ |
if (rx_packet->eth_type == 0x0806) { |
parse_arp_packet(&buf[14]); |
338,7 → 289,7
*/ |
int arp_op; |
mac_ip_t arp_sender, arp_target; |
|
|
arp_op = buf[6]<<8 | buf[7]; |
|
arp_sender.mac[0] = buf[8]; |
347,12 → 298,12
arp_sender.mac[3] = buf[11]; |
arp_sender.mac[4] = buf[12]; |
arp_sender.mac[5] = buf[13]; |
|
|
arp_sender.ip [0] = buf[14]; |
arp_sender.ip [1] = buf[15]; |
arp_sender.ip [2] = buf[16]; |
arp_sender.ip [3] = buf[17]; |
|
|
arp_target.mac[0] = buf[18]; |
arp_target.mac[1] = buf[19]; |
arp_target.mac[2] = buf[20]; |
359,19 → 310,19
arp_target.mac[3] = buf[21]; |
arp_target.mac[4] = buf[22]; |
arp_target.mac[5] = buf[23]; |
|
|
arp_target.ip [0] = buf[24]; |
arp_target.ip [1] = buf[25]; |
arp_target.ip [2] = buf[26]; |
arp_target.ip [3] = buf[27]; |
|
|
/* Send a reply ? */ |
if (arp_op==1 && |
arp_target.ip[0]==self_g.ip[0] && |
arp_target.ip[1]==self_g.ip[1] && |
arp_target.ip[2]==self_g.ip[2] && |
if (arp_op==1 && |
arp_target.ip[0]==self_g.ip[0] && |
arp_target.ip[1]==self_g.ip[1] && |
arp_target.ip[2]==self_g.ip[2] && |
arp_target.ip[3]==self_g.ip[3]) { |
|
|
// ARP reply |
arp_reply((char*)ETHMAC_TX_BUFFER, &arp_sender); |
} |
382,13 → 333,13
void parse_ip_packet(char * buf, packet_t* rx_packet) |
{ |
unsigned int ip_version; |
|
|
ip_version = buf[0]>>4; |
if (ip_version != 4) { |
//printf("%s: IP version %d not supported\n", __func__, ip_version); |
return; |
} |
|
|
/* Get destination IP address */ |
rx_packet->dst_ip[0] = buf[16]; |
rx_packet->dst_ip[1] = buf[17]; |
396,13 → 347,13
rx_packet->dst_ip[3] = buf[19]; |
|
/* If its not my address then ignore the packet */ |
if (rx_packet->dst_ip[0] != self_g.ip[0] || |
rx_packet->dst_ip[1] != self_g.ip[1] || |
rx_packet->dst_ip[2] != self_g.ip[2] || |
if (rx_packet->dst_ip[0] != self_g.ip[0] || |
rx_packet->dst_ip[1] != self_g.ip[1] || |
rx_packet->dst_ip[2] != self_g.ip[2] || |
rx_packet->dst_ip[3] != self_g.ip[3] ) { |
return; |
} |
|
|
rx_packet->ip_len = buf[ 2]<<8|buf[ 3]; |
rx_packet->ip_header_len = buf[0] & 0xf; |
rx_packet->ip_proto = buf[9]; |
411,17 → 362,17
rx_packet->src_ip[2] = buf[14]; |
rx_packet->src_ip[3] = buf[15]; |
|
|
/* Ping packets */ |
|
/* Ping packets */ |
if (rx_packet->ip_proto == 1){ |
parse_ping_packet(&buf[(rx_packet->ip_header_len)*4], rx_packet); |
} |
|
|
/* TCP packets */ |
else if (rx_packet->ip_proto == 6){ |
parse_tcp_packet(&buf[(rx_packet->ip_header_len)*4], rx_packet); |
} |
|
|
/* UDP packets */ |
else if (rx_packet->ip_proto == 17){ |
parse_udp_packet(&buf[(rx_packet->ip_header_len)*4], rx_packet); |
436,7 → 387,7
|
ping_id = buf[4]<<8|buf[5]; |
ping_seq = buf[6]<<8|buf[7]; |
|
|
ping_reply(rx_packet, ping_id, ping_seq, buf); |
} |
|
458,7 → 409,7
while (sum>>16) { |
sum = (sum & 0xFFFF)+(sum >> 16); |
} |
|
|
// build 1's complement: |
return( (unsigned short ) sum ^ 0xFFFF); |
} |
/sw/boot-loader-ethmac/led.h
0,0 → 1,50
/*---------------------------------------------------------------- |
// // |
// boot-loader.h // |
// // |
// This file is part of the Amber project // |
// http://www.opencores.org/project,amber // |
// // |
// Description // |
// Defines for the boot-loader application. // |
// // |
// Author(s): // |
// - Conor Santifort, csantifort.amber@gmail.com // |
// // |
////////////////////////////////////////////////////////////////// |
// // |
// Copyright (C) 2010-2013 Authors and OPENCORES.ORG // |
// // |
// This source file may be used and distributed without // |
// restriction provided that this copyright statement is not // |
// removed from the file and that any derivative work contains // |
// the original copyright notice and the associated disclaimer. // |
// // |
// This source file is free software; you can redistribute it // |
// and/or modify it under the terms of the GNU Lesser General // |
// Public License as published by the Free Software Foundation; // |
// either version 2.1 of the License, or (at your option) any // |
// later version. // |
// // |
// This source is distributed in the hope that it will be // |
// useful, but WITHOUT ANY WARRANTY; without even the implied // |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // |
// PURPOSE. See the GNU Lesser General Public License for more // |
// details. // |
// // |
// You should have received a copy of the GNU Lesser General // |
// Public License along with this source; if not, download it // |
// from http://www.opencores.org/lgpl.shtml // |
// // |
----------------------------------------------------------------*/ |
|
/* Global variables */ |
extern time_t* led_flash_timer_g; |
|
/* Function Prototypes */ |
void led_clear (void); |
void led_flip (int); |
void led_on (int); |
void led_off (int); |
void led_123 (int); |
|
/sw/boot-loader-ethmac/utilities.c
7,7 → 7,7
// // |
// Description // |
// The main functions for the boot loader application. This // |
// application is embedded in the FPGA's SRAM and is used // |
// application is embedded in the FPGA's SRAM and is used // |
// to load larger applications into the DDR3 memory on // |
// the development board. // |
// // |
57,7 → 57,7
{ |
int pos = 0; |
int equal=1; |
|
|
while (*str1!=0 && *str2!=0 && pos<256 && equal) { |
equal = *str1==*str2; |
str1++; |
74,7 → 74,7
int cpos = 0, done = 0; |
*num = 0; |
|
while (!done) { |
while (!done) { |
if ( buf[cpos] >= '0' && buf[cpos] <= '9' ) { |
*num = *num<<4; |
*num = *num + buf[cpos] - '0'; |
89,16 → 89,16
} |
else |
done = 1; |
|
|
// Don't increment cops if the first character is not part of an ascii-hex string |
// oo that a 0 is returned to indicate failure. |
if (!done) |
if (!done) |
cpos++; |
|
|
if (cpos >= 8) |
done = 1; |
} |
|
|
/* Return length of acsii-hex string */ |
return cpos; |
} |
116,47 → 116,3
*(unsigned int *) ADR_AMBER_TEST_PHY_RST = value; |
} |
|
|
/* turn off all leds */ |
void led_clear() |
{ |
*(unsigned int *) ADR_AMBER_TEST_LED = 0; |
} |
|
|
/* led is either 0,1,2 or 3 */ |
void led_flip(int led) |
{ |
int current_value; |
current_value = *(unsigned int *) ADR_AMBER_TEST_LED; |
*(unsigned int *) ADR_AMBER_TEST_LED = current_value ^ (1<<led); |
} |
|
|
|
/* led is either 0,1,2 or 3 */ |
void led_on(int led) |
{ |
int current_value; |
current_value = *(unsigned int *) ADR_AMBER_TEST_LED; |
*(unsigned int *) ADR_AMBER_TEST_LED = current_value | (1<<led); |
} |
|
|
|
/* led is either 0,1,2 or 3 */ |
void led_off(int led) |
{ |
int current_value; |
current_value = *(unsigned int *) ADR_AMBER_TEST_LED; |
*(unsigned int *) ADR_AMBER_TEST_LED = current_value & ~(1<<led); |
} |
|
|
/* led is either 0,1,2 or 3 */ |
void led_123(int value) |
{ |
int current_value; |
current_value = *(unsigned int *) ADR_AMBER_TEST_LED; |
*(unsigned int *) ADR_AMBER_TEST_LED = (current_value & 1) | value<<1; |
} |
/sw/boot-loader-ethmac/packet.h
134,7 → 134,7
unsigned char src_mac[6]; |
unsigned char dst_mac[6]; |
unsigned int eth_type; |
|
|
/* IPv4 */ |
unsigned char src_ip[4]; |
unsigned char dst_ip[4]; |
141,8 → 141,8
unsigned int ip_len; // IP; in bytres |
unsigned int ip_header_len; // IP; in 32-bit words |
unsigned int ip_proto; |
|
/* TCP */ |
|
/* TCP */ |
unsigned int tcp_src_port; |
unsigned int tcp_dst_port; |
unsigned int tcp_hdr_len; |
153,7 → 153,7
unsigned int tcp_len; |
unsigned int tcp_payload_len; |
unsigned int tcp_src_time_stamp; |
|
|
/* Telnet */ |
unsigned int telnet_payload_len; |
} packet_t; |
160,38 → 160,6
|
|
|
typedef struct { |
|
packet_buffer_t** tcp_buf; |
int tcp_current_buf; |
|
/* Telnet rx and tx line buffers */ |
line_buf_t* telnet_rxbuf; |
line_buf_t* telnet_txbuf; |
|
int telnet_sent_opening_message; |
int telnet_echo_mode; |
int telnet_connection_state; |
int telnet_options_sent; |
|
int packets_sent; |
int packets_received; |
int packets_resent; |
|
int tcp_connection_state; |
int tcp_reset; |
int tcp_disconnect; |
int tcp_seq; /* should be random initial seq number for tcp */ |
int tcp_last_seq; |
unsigned int tcp_last_ack; |
|
int id; |
|
packet_t* rx_packet; /* Header info from last packet received */ |
} socket_t; |
|
|
|
/* Enumerated types */ |
enum mdi_ctrl { |
mdi_write = 0x04000000, |
209,13 → 177,10
|
/* Global Variables */ |
extern mac_ip_t self_g; |
extern packet_t* rx_packet_g; |
extern socket_t* socket0_g; |
extern socket_t* socket1_g; |
|
|
/* Functions */ |
void init_packet_buffers (socket_t*); |
void init_packet (); |
unsigned short header_checksum16 (unsigned char *buf, unsigned short len, unsigned int sum); |
|
void arp_reply (char *buf, mac_ip_t*); |
229,10 → 194,8
void parse_ip_packet (char*, packet_t*); |
void parse_ping_packet (char*, packet_t*); |
|
socket_t* init_socket (int); |
|
|
|
|
|
|
/sw/boot-loader-ethmac/tftp.c
0,0 → 1,256
/*---------------------------------------------------------------- |
// // |
// boot-loader-ethmac.c // |
// // |
// This file is part of the Amber project // |
// http://www.opencores.org/project,amber // |
// // |
// Description // |
// The main functions for the boot loader application. This // |
// application is embedded in the FPGA's SRAM and is used // |
// to load larger applications into the DDR3 memory on // |
// the development board. // |
// // |
// Author(s): // |
// - Conor Santifort, csantifort.amber@gmail.com // |
// // |
////////////////////////////////////////////////////////////////// |
// // |
// Copyright (C) 2011 Authors and OPENCORES.ORG // |
// // |
// This source file may be used and distributed without // |
// restriction provided that this copyright statement is not // |
// removed from the file and that any derivative work contains // |
// the original copyright notice and the associated disclaimer. // |
// // |
// This source file is free software; you can redistribute it // |
// and/or modify it under the terms of the GNU Lesser General // |
// Public License as published by the Free Software Foundation; // |
// either version 2.1 of the License, or (at your option) any // |
// later version. // |
// // |
// This source is distributed in the hope that it will be // |
// useful, but WITHOUT ANY WARRANTY; without even the implied // |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // |
// PURPOSE. See the GNU Lesser General Public License for more // |
// details. // |
// // |
// You should have received a copy of the GNU Lesser General // |
// Public License along with this source; if not, download it // |
// from http://www.opencores.org/lgpl.shtml // |
// // |
----------------------------------------------------------------*/ |
|
#include "amber_registers.h" |
#include "address_map.h" |
#include "line-buffer.h" |
#include "timer.h" |
#include "utilities.h" |
#include "packet.h" |
#include "udp.h" |
#include "tcp.h" |
#include "tftp.h" |
#include "elfsplitter.h" |
|
|
block_t* udp_file_g = NULL; |
block_t* udp_current_block_g = NULL; |
time_t* reboot_timer_g; |
int reboot_stage_g; |
|
|
block_t* init_buffer_512() |
{ |
block_t* block = malloc(sizeof(block_t)); |
block->buf512 = malloc(512); |
block->next = NULL; |
block->bytes = 0; |
block->last_block = 0; |
block->total_bytes = 0; |
block->total_blocks = 0; |
block->ready = 0; |
block->filename = NULL; |
block->linux_boot = 0; |
return block; |
} |
|
|
void parse_tftp_packet(char * buf, packet_t* rx_packet, int tftp_len, unsigned int udp_src_port, unsigned int udp_dst_port) |
{ |
int mode_offset; |
int binary_mode; |
|
unsigned int opcode = buf[8]<<8|buf[9]; |
unsigned int block = buf[10]<<8|buf[11]; |
|
mode_offset = next_string(&buf[10]); |
binary_mode = strcmp("octet", &buf[10+mode_offset]); |
|
switch (opcode) { |
|
case UDP_READ: |
udp_reply(rx_packet, udp_dst_port, udp_src_port, 0, UDP_ERROR); |
break; |
|
case UDP_WRITE: |
udp_file_g = init_buffer_512(); |
udp_file_g->filename = malloc(256); |
strcpy(udp_file_g->filename, &buf[10]); |
|
if (strncmp(&buf[10], "vmlinux", 7) == 0) |
udp_file_g->linux_boot = 1; |
|
udp_current_block_g = udp_file_g; |
|
if (binary_mode) |
udp_reply(rx_packet, udp_dst_port, udp_src_port, 0, UDP_ACK); |
else |
udp_reply(rx_packet, udp_dst_port, udp_src_port, 0, UDP_ERROR); |
break; |
|
|
case UDP_DATA: |
udp_reply(rx_packet, udp_dst_port, udp_src_port, block, UDP_ACK); |
|
if (block > udp_file_g->last_block) { |
// Have not already received this block |
udp_file_g->last_block = block; |
|
/* receive and save a block */ |
udp_current_block_g->bytes = tftp_len; |
udp_file_g->total_bytes += tftp_len; |
udp_file_g->total_blocks++; |
|
memcpy(udp_current_block_g->buf512, &buf[12], tftp_len); |
|
/* Prepare the next block */ |
if (tftp_len == 512) { |
udp_current_block_g->next = init_buffer_512(); |
udp_current_block_g = udp_current_block_g->next; |
} |
else { /* Last block */ |
udp_file_g->ready = 1; |
} |
} |
break; |
|
|
default: break; |
} |
} |
|
|
|
void init_tftp() |
{ |
reboot_timer_g = new_timer(); |
reboot_stage_g = 0; |
} |
|
|
void process_tftp () |
{ |
socket_t* socket; |
|
/* Check for newly downloaded tftp file. Add to all tx buffers */ |
/* Has a file been uploaded via tftp ? */ |
if (udp_file_g != NULL) { |
/* Notify telnet clients that file has been received */ |
if (udp_file_g->ready) { |
udp_file_g->ready = 0; |
|
print_serial("Received file %s, %d bytes", |
udp_file_g->filename, udp_file_g->total_bytes); |
if (udp_file_g->linux_boot) |
print_serial(", linux image detected\r\n"); |
else |
print_serial("\r\n"); |
|
if (process_file() == 0) { |
/* Disconnect in 1 second */ |
set_timer(reboot_timer_g, 1000); |
} |
else |
print_serial("Not an elf file\r\n"); |
} |
} |
|
/* reboot timer expired */ |
if (timer_expired(reboot_timer_g)) { |
/* First stage of reboot sequence is to nicely disconnect */ |
if (reboot_stage_g == 0) { |
set_timer(reboot_timer_g, 1000); |
reboot_stage_g = 1; |
socket = first_socket_g; |
for(;;){ |
socket->tcp_disconnect = 1; |
if (socket->next!=NULL) |
socket=socket->next; |
else |
break; |
} |
} |
else { |
/* Second stage of reboot sequence is to turn off ethmac and then jump to restart vector */ |
close_link(); |
reboot(); |
} |
} |
} |
|
|
|
/* copy tftp file into a single contiguous buffer so |
if can be processed by elf splitter */ |
int process_file() |
{ |
block_t* block; |
char* buf512; |
char* tftp_file; |
char* line; |
int line_len; |
int ret; |
|
tftp_file = malloc(udp_file_g->total_bytes); |
|
block = udp_file_g; |
buf512= tftp_file; |
|
while (block->next) { |
memcpy(buf512, block->buf512, block->bytes); |
buf512=&buf512[512]; |
block=block->next; |
} |
memcpy(buf512, block->buf512, block->bytes); |
buf512=&buf512[512]; |
|
return elfsplitter(tftp_file); |
} |
|
|
/* Disable interrupts |
Load new values into the interrupt vector memory space |
Jump to address 0 |
*/ |
void reboot() |
{ |
int i; |
|
/* Disable all interrupts */ |
/* Disable ethmac_int interrupt */ |
/* Disable timer 0 interrupt in interrupt controller */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x120; |
|
for(i=0;i<MEM_BUF_ENTRIES;i++) |
if (elf_mem0_g->entry[i].valid) |
*(char *)(i) = elf_mem0_g->entry[i].data; |
|
if (udp_file_g->linux_boot) { |
print_serial("linux reboot\n\r"); |
_jump_to_program(LINUX_JUMP_ADR); |
} |
else { |
print_serial("normal reboot\n\r"); |
_restart(); |
} |
} |
/sw/boot-loader-ethmac/timer.c
50,7 → 50,8
time_t* current_time_g; |
|
|
time_t* init_timer() |
/* Create a timer object */ |
time_t* new_timer() |
{ |
time_t* timer; |
timer= malloc(sizeof(time_t)); |
65,8 → 66,11
track of the current up time. Timers are |
compared against this running value. |
*/ |
void init_current_time() |
void init_timer() |
{ |
/* Initialize the current time object */ |
current_time_g = new_timer(); |
|
/* Configure timer 0 */ |
/* Counts down from this value and generates an interrupt every 1/100 seconds */ |
*(unsigned int *) ( ADR_AMBER_TM_TIMER0_LOAD ) = 1562; // 16-bit, x 256 |
74,14 → 78,28
|
/* Enable timer 0 interrupt */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLESET ) = 0x020; |
} |
|
current_time_g = malloc(sizeof(time_t)); |
current_time_g->milliseconds = 0; |
current_time_g->seconds = 0; |
|
/* Set the timer to current time plus a number of milliseconds */ |
void set_timer (time_t* timer, int milliseconds) |
{ |
int seconds = _div(milliseconds, 1000); |
int mseconds = milliseconds - seconds*1000; /* milliseconds % 1000 */ |
|
if (current_time_g->milliseconds >= (1000 - mseconds)) { |
timer->seconds = current_time_g->seconds + 1; |
timer->milliseconds = current_time_g->milliseconds + mseconds - 1000; |
} |
else { |
timer->seconds = current_time_g->seconds; |
timer->milliseconds = current_time_g->milliseconds + mseconds; |
} |
|
timer->seconds += seconds; |
} |
|
|
|
void timer_interrupt() |
{ |
/* Clear timer 0 interrupt in timer */ |
120,22 → 138,4
} |
|
|
/* Set the timer to current time plus 5 seconds */ |
void set_timer (time_t* timer, int milliseconds) |
{ |
int seconds = _div(milliseconds, 1000); |
int mseconds = milliseconds - seconds*1000; /* milliseconds % 1000 */ |
|
|
if (current_time_g->milliseconds >= (1000 - mseconds)) { |
timer->seconds = current_time_g->seconds + 1; |
timer->milliseconds = current_time_g->milliseconds + mseconds - 1000; |
} |
else { |
timer->seconds = current_time_g->seconds; |
timer->milliseconds = current_time_g->milliseconds + mseconds; |
} |
|
timer->seconds += seconds; |
} |
|
/sw/boot-loader-ethmac/utilities.h
39,6 → 39,7
----------------------------------------------------------------*/ |
#define NULL 0 |
|
/* function prototypes */ |
void udelay20 (void); |
void * malloc (unsigned int); |
int get_hex (char*, unsigned int*); |
45,11 → 46,4
int next_string (char*); |
int strcmp (char*, char*); |
int serial_putchar_ (char *); |
|
void led_clear (void); |
void led_flip (int); |
void led_on (int); |
void led_off (int); |
void led_123 (int); |
|
void phy_rst (int); |
/sw/boot-loader-ethmac/tftp.h
0,0 → 1,69
/*---------------------------------------------------------------- |
// // |
// boot-loader.h // |
// // |
// This file is part of the Amber project // |
// http://www.opencores.org/project,amber // |
// // |
// Description // |
// Defines for the boot-loader application. // |
// // |
// Author(s): // |
// - Conor Santifort, csantifort.amber@gmail.com // |
// // |
////////////////////////////////////////////////////////////////// |
// // |
// Copyright (C) 2010 Authors and OPENCORES.ORG // |
// // |
// This source file may be used and distributed without // |
// restriction provided that this copyright statement is not // |
// removed from the file and that any derivative work contains // |
// the original copyright notice and the associated disclaimer. // |
// // |
// This source file is free software; you can redistribute it // |
// and/or modify it under the terms of the GNU Lesser General // |
// Public License as published by the Free Software Foundation; // |
// either version 2.1 of the License, or (at your option) any // |
// later version. // |
// // |
// This source is distributed in the hope that it will be // |
// useful, but WITHOUT ANY WARRANTY; without even the implied // |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // |
// PURPOSE. See the GNU Lesser General Public License for more // |
// details. // |
// // |
// You should have received a copy of the GNU Lesser General // |
// Public License along with this source; if not, download it // |
// from http://www.opencores.org/lgpl.shtml // |
// // |
----------------------------------------------------------------*/ |
#define LINUX_JUMP_ADR 0x00080000 |
|
|
typedef struct { |
char * buf512; |
void * next; |
unsigned int bytes; |
unsigned int last_block; |
unsigned int total_bytes; |
unsigned int total_blocks; |
unsigned int ready; |
unsigned int linux_boot; |
char* filename; |
} block_t; |
|
|
/* Global variables */ |
extern time_t* reboot_timer_g; |
extern int reboot_stage_g; |
|
/* Function prototypes */ |
void process_tftp (); |
void init_tftp (); |
block_t* init_buffer_512 (); |
int process_file (); |
void reboot (); |
void parse_tftp_packet(char*, packet_t*, int, unsigned int, unsigned int); |
|
|
|
/sw/boot-loader-ethmac/timer.h
42,14 → 42,15
typedef struct { |
volatile unsigned int seconds; |
volatile unsigned int milliseconds; |
void * expired; |
} time_t; |
|
|
void init_current_time (); |
time_t* init_timer (); |
time_t* new_timer (); |
void init_timer (); |
void timer_interrupt (); |
void set_timer (time_t*, int); |
int timer_expired (time_t*); |
|
/* Global variables */ |
extern time_t* current_time_g; |
extern time_t* current_time_g; |
/sw/boot-loader-ethmac/tcp.c
7,7 → 7,7
// // |
// Description // |
// The main functions for the boot loader application. This // |
// application is embedded in the FPGA's SRAM and is used // |
// application is embedded in the FPGA's SRAM and is used // |
// to load larger applications into the DDR3 memory on // |
// the development board. // |
// // |
54,75 → 54,157
|
/* Global variables */ |
int tcp_checksum_errors_g = 0; |
socket_t* first_socket_g; |
socket_t* socket1_g; |
|
/* input argument is a pointer to the previous socket, |
if this is the first socket object, then it is NULL */ |
socket_t* new_socket(socket_t* prev) |
{ |
socket_t* socket; |
int i; |
|
socket = (socket_t*) malloc(sizeof(socket_t)); |
socket->rx_packet = (packet_t*) malloc(sizeof(packet_t)); |
|
/* Create space for an array of pointers */ |
socket->tcp_buf = malloc (TCP_TX_BUFFERS * sizeof (void *)); |
|
/* Create space for a set of buffers, each pointed to by an element of the array */ |
for (i=0;i<TCP_TX_BUFFERS;i=i+1) { |
socket->tcp_buf[i] = (packet_buffer_t*) malloc (sizeof (packet_buffer_t)); |
socket->tcp_buf[i]->payload_valid = 0; |
socket->tcp_buf[i]->starting_seq = 0; |
socket->tcp_buf[i]->ending_seq = 0; |
socket->tcp_buf[i]->len_bytes = 0; |
socket->tcp_buf[i]->ack_received = 0; |
} |
|
socket->telnet_txbuf = init_line_buffer(0x80000); |
socket->telnet_rxbuf = init_line_buffer(0x1000); |
|
socket->packets_sent = 0; |
socket->packets_received = 0; |
socket->packets_resent = 0; |
|
socket->telnet_sent_opening_message = 0; |
socket->telnet_echo_mode = 0; |
socket->telnet_connection_state = TELNET_CLOSED; |
socket->telnet_options_sent = 0; |
|
socket->tcp_current_buf = 0; |
socket->tcp_reset = 0; |
socket->tcp_connection_state = TCP_CLOSED; |
socket->tcp_disconnect = 0; |
socket->tcp_seq = 0x100; /* should be random initial seq number for tcp */ |
socket->tcp_last_seq = socket->tcp_seq; |
socket->tcp_last_ack = 0; |
|
|
/* Chain the socket objects together */ |
if (prev == NULL){ |
socket->first = socket; |
socket->id = 0; |
} |
else { |
socket->first = prev->first; |
socket->id = prev->id + 1; |
prev->next = socket; |
} |
socket->next = NULL; |
|
return socket; |
} |
|
|
/* All received tcp packets with dset ip == me arrive here */ |
void parse_tcp_packet(char * buf, packet_t* rx_packet) |
{ |
int i; |
int ptr; |
socket_t* socket; |
|
int found=0; |
|
/* TCP Length */ |
rx_packet->tcp_len = rx_packet->ip_len - rx_packet->ip_header_len*4; |
rx_packet->tcp_hdr_len = (buf[12]>>4)*4; |
|
|
// Guard against incorrect tcp_hdr_len value |
if (rx_packet->tcp_hdr_len < rx_packet->tcp_len) |
rx_packet->tcp_payload_len = rx_packet->tcp_len - rx_packet->tcp_hdr_len; |
else |
rx_packet->tcp_payload_len = 0; |
|
|
/* Verify the TCP checksum is correct */ |
if (tcp_checksum(buf, rx_packet, 0)) { |
tcp_checksum_errors_g++; |
goto error_out; |
return; |
} |
|
|
|
|
rx_packet->tcp_src_port = buf[0]<<8|buf[1]; |
rx_packet->tcp_dst_port = buf[2]<<8|buf[3]; |
rx_packet->tcp_seq = buf[4]<<24|buf[5]<<16|buf[6]<<8|buf[7]; |
rx_packet->tcp_ack = buf[8]<<24|buf[9]<<16|buf[10]<<8|buf[11]; |
rx_packet->tcp_flags = buf[13]; |
rx_packet->tcp_window_size = buf[14]<<8|buf[15]; |
rx_packet->tcp_window_size = buf[14]<<8|buf[15]; |
|
|
|
/* only interested in telnet packet to dest port xx */ |
if (rx_packet->tcp_dst_port != 23) { |
return; |
} |
|
if (rx_packet->tcp_hdr_len > 20) { |
/* Get the source time stamp */ |
parse_tcp_options(buf, rx_packet); |
parse_tcp_options(buf, rx_packet); |
} |
|
|
/* -------------------------------------------------- |
Assign the received packet to a socket |
Assign the received packet to a socket |
-------------------------------------------------- */ |
/* seach for an open socket that matches the tcp connection */ |
socket = first_socket_g; |
for(;;){ |
if (socket->tcp_connection_state != TCP_CLOSED && |
socket->rx_packet->tcp_src_port == rx_packet->tcp_src_port) { |
found=1; |
break; |
} |
if (socket->next!=NULL) |
socket=socket->next; |
else |
break; |
} |
|
/* socket 0 open and matches ? */ |
if (socket0_g->tcp_connection_state != TCP_CLOSED && |
socket0_g->rx_packet->tcp_src_port == rx_packet->tcp_src_port) |
socket = socket0_g; |
|
/* socket 1 open and matches ? */ |
else if (socket1_g->tcp_connection_state != TCP_CLOSED && |
socket1_g->rx_packet->tcp_src_port == rx_packet->tcp_src_port) |
socket = socket1_g; |
/* Search for an available closed soeckt to reuse */ |
if (!found){ |
socket = first_socket_g; |
for(;;){ |
if (socket->tcp_connection_state == TCP_CLOSED) { |
found=1; |
break; |
} |
if (socket->next!=NULL) |
socket=socket->next; |
else |
break; |
} |
} |
|
/* no matches. Pick an unused socket */ |
else if (socket0_g->tcp_connection_state == TCP_CLOSED) |
socket = socket0_g; |
else if (socket1_g->tcp_connection_state == TCP_CLOSED) |
socket = socket1_g; |
else |
goto error_out; |
|
/* All available sockets being used. Add a new one to the end of the chain */ |
if (!found) { |
socket = new_socket(socket); |
} |
|
|
/* Copy the rx_packet structure into the socket */ |
memcpy(socket->rx_packet, rx_packet, sizeof(packet_t)); |
|
|
tcp_response(buf, socket); |
|
error_out: |
return; |
} |
|
|
136,22 → 218,22
switch (buf[ptr]) { |
case 0: ptr=rx_packet->tcp_hdr_len; break; // end of options |
case 1: ptr++; break; |
case 2: ptr = ptr + buf[ptr+1]; break; // max segment size |
case 2: ptr = ptr + buf[ptr+1]; break; // max segment size |
case 3: ptr = ptr + buf[ptr+1]; break; // Window Scale |
case 4: ptr = ptr + buf[ptr+1]; break; // SACK Permitted |
case 5: ptr = ptr + buf[ptr+1]; break; // SACK |
case 8: |
// Time Stamp Option |
case 8: |
// Time Stamp Option |
rx_packet->tcp_src_time_stamp = buf[ptr+2]<<24|buf[ptr+3]<<16|buf[ptr+4]<<8|buf[ptr+5]; |
ptr = ptr + buf[ptr+1]; |
ptr = ptr + buf[ptr+1]; |
break; |
|
|
case 28: // User Timeout Option |
ptr = ptr + buf[ptr+1]; break; |
|
ptr = ptr + buf[ptr+1]; break; |
|
default: |
ptr++; break; |
} |
ptr++; break; |
} |
} |
} |
|
159,56 → 241,56
void tcp_response(char * buf, socket_t* socket) |
{ |
socket->packets_received++; |
|
|
/* Mark the ack in the tcp tx packet buffer so the tx packet does not get resent */ |
if (socket->rx_packet->tcp_flags & 0x10) // ack flag set ? |
if (socket->rx_packet->tcp_flags & 0x10) // ack flag set ? |
tcp_ack(socket); |
|
|
|
// Other side requesting to reset a connection ? |
if (socket->rx_packet->tcp_flags & 0x04) { // RST |
if (socket->rx_packet->tcp_flags & 0x04) { // RST |
// Reset the connection |
socket->tcp_disconnect = 1; |
} |
|
|
// open a connection |
else if (socket->tcp_connection_state == TCP_CLOSED) { |
|
if (socket->rx_packet->tcp_flags & 0x02) { // SYN |
else if (socket->tcp_connection_state == TCP_CLOSED) { |
|
if (socket->rx_packet->tcp_flags & 0x02) { // SYN |
// Open connection |
tcp_open(socket); |
socket->tcp_connection_state = TCP_PENDING; |
} |
|
|
/* ACK any FIN received */ |
else if (socket->rx_packet->tcp_flags & 0x01) // FIN |
tcp_reply(socket, NULL, 0); |
else if (socket->rx_packet->tcp_flags & 0x01) // FIN |
tcp_reply(socket, NULL, 0); |
} |
|
|
|
// Sent the first ack packet to establish a connection. |
// Have just received the second packet from the server |
else if (socket->tcp_connection_state == TCP_PENDING) { |
// Have just received the second packet from the server |
else if (socket->tcp_connection_state == TCP_PENDING) { |
/* Add 1 to the sequence number as a special case to open |
the connection */ |
socket->tcp_seq++; |
socket->tcp_connection_state = TCP_OPEN; |
socket->tcp_seq++; |
socket->tcp_connection_state = TCP_OPEN; |
} |
|
|
|
|
// connection is already open |
else { |
|
|
/* contains tcp payload */ |
if (socket->rx_packet->tcp_payload_len != 0) { |
/* Ack the packet only if the payload length is non-zero */ |
tcp_reply(socket, NULL, 0); |
|
|
/* Process the tcp contents */ |
if (socket->rx_packet->tcp_dst_port == TELNET_PORT) |
/* telnet */ |
parse_telnet_options(&buf[socket->rx_packet->tcp_hdr_len], socket); |
} |
} |
} |
} |
|
229,16 → 311,16
|
|
/* Transmit a string of length line_len |
Suspend interrupts so this process does not get interrupted */ |
Suspend interrupts so this process does not get interrupted */ |
void tcp_tx(socket_t* socket, char* buf, int len) |
{ |
/* Disable ethmac_int interrupt */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x100; |
|
tcp_reply(socket, buf, len); |
|
/* Enable ethmac_int interrupt */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLESET ) = 0x100; |
/* Disable ethmac_int interrupt */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x100; |
|
tcp_reply(socket, buf, len); |
|
/* Enable ethmac_int interrupt */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLESET ) = 0x100; |
} |
|
|
253,10 → 335,10
int ip_length; |
char * buf; |
|
|
|
buf = socket->tcp_buf[socket->tcp_current_buf]->buf; |
|
|
|
|
target.mac[0] = socket->rx_packet->src_mac[0]; |
target.mac[1] = socket->rx_packet->src_mac[1]; |
target.mac[2] = socket->rx_packet->src_mac[2]; |
271,18 → 353,18
|
/* Include 20 bytes of tcp options */ |
ip_length = 20+20+20; /* 20 bytes ip header, 20 bytes tcp header, 20 bytes tcp options */ |
|
|
socket->tcp_buf[socket->tcp_current_buf]->payload_valid = 1; |
socket->tcp_buf[socket->tcp_current_buf]->ack_received = 0; |
socket->tcp_buf[socket->tcp_current_buf]->starting_seq = tcp_header(&buf[34], socket, 0, TCP_NEW); |
socket->tcp_buf[socket->tcp_current_buf]->starting_seq = tcp_header(&buf[34], socket, 0, TCP_NEW); |
socket->tcp_buf[socket->tcp_current_buf]->ending_seq = socket->tcp_buf[socket->tcp_current_buf]->starting_seq + 1; |
set_timer(&socket->tcp_buf[socket->tcp_current_buf]->resend_time, 500); |
|
|
ip_header(&buf[14], &target, ip_length, 6); /* 20 byes of tcp options, bytes 14 to 33, ip_proto = 6, TCP*/ |
ethernet_header(buf, &target, 0x0800); /* bytes 0 to 13*/ |
|
|
socket->tcp_buf[socket->tcp_current_buf]->len_bytes = 14+ip_length; |
|
|
strncpy((char*)ETHMAC_TX_BUFFER, buf, socket->tcp_buf[socket->tcp_current_buf]->len_bytes); |
|
tx_packet(socket->tcp_buf[socket->tcp_current_buf]->len_bytes); // MAC header, IP header, TCP header, TCP options |
289,7 → 371,7
socket->packets_sent++; |
|
|
/* Pick the next tx buffer to use */ |
/* Pick the next tx buffer to use */ |
if (socket->tcp_current_buf == TCP_TX_BUFFERS-1) |
socket->tcp_current_buf=0; |
else |
306,9 → 388,9
int ip_length; |
char * buf; |
|
|
|
buf = socket->tcp_buf[socket->tcp_current_buf]->buf; |
|
|
target.mac[0] = socket->rx_packet->src_mac[0]; |
target.mac[1] = socket->rx_packet->src_mac[1]; |
target.mac[2] = socket->rx_packet->src_mac[2]; |
321,7 → 403,7
target.ip[3] = socket->rx_packet->src_ip[3]; |
|
ip_length = 20+20 + telnet_payload_length; |
|
|
/* Copy the payload into the transmit buffer */ |
if (telnet_payload_length != 0) { |
for (i=14+ip_length-telnet_payload_length, j=0; i<14+ip_length;i++,j++) { |
328,14 → 410,14
buf[i] = telnet_payload[j]; |
} |
} |
|
|
if (telnet_payload_length) |
socket->tcp_buf[socket->tcp_current_buf]->payload_valid = 1; |
else |
socket->tcp_buf[socket->tcp_current_buf]->payload_valid = 0; |
|
|
socket->tcp_buf[socket->tcp_current_buf]->ack_received = 0; |
socket->tcp_buf[socket->tcp_current_buf]->starting_seq = tcp_header(&buf[34], socket, telnet_payload_length, TCP_NORMAL); |
socket->tcp_buf[socket->tcp_current_buf]->starting_seq = tcp_header(&buf[34], socket, telnet_payload_length, TCP_NORMAL); |
socket->tcp_buf[socket->tcp_current_buf]->ending_seq = socket->tcp_buf[socket->tcp_current_buf]->starting_seq + telnet_payload_length; |
set_timer(&socket->tcp_buf[socket->tcp_current_buf]->resend_time, 500); |
|
343,7 → 425,7
ethernet_header(buf, &target, 0x0800); /*bytes 0 to 13*/ |
|
socket->tcp_buf[socket->tcp_current_buf]->len_bytes = 14+ip_length; |
|
|
strncpy((char*)ETHMAC_TX_BUFFER, buf, socket->tcp_buf[socket->tcp_current_buf]->len_bytes); |
|
tx_packet(socket->tcp_buf[socket->tcp_current_buf]->len_bytes); // MAC header, IP header, TCP header, TCP options |
350,7 → 432,7
socket->packets_sent++; |
|
|
/* Pick the next tx buffer to use */ |
/* Pick the next tx buffer to use */ |
if (socket->tcp_current_buf == TCP_TX_BUFFERS-1) |
socket->tcp_current_buf=0; |
else |
366,12 → 448,12
int i, ack_valid; |
unsigned int ack = socket->rx_packet->tcp_ack; |
unsigned int last_ack = socket->tcp_last_ack; |
|
|
for (i=0;i<TCP_TX_BUFFERS;i=i+1) { |
if (socket->tcp_buf[i]->payload_valid) { |
|
|
if (ack > last_ack) { |
ack_valid = (socket->tcp_buf[i]->ending_seq > last_ack) && |
ack_valid = (socket->tcp_buf[i]->ending_seq > last_ack) && |
(socket->tcp_buf[i]->ending_seq <= ack); |
} |
else { /* ack is a little after 0, last_ack is a little before 0 */ |
381,7 → 463,7
else |
ack_valid = 1; |
} |
|
|
if (ack_valid) { |
socket->tcp_buf[i]->ack_received = 1; |
if (socket->tcp_buf[i]->ending_seq == ack) break; |
388,34 → 470,34
} |
} |
} |
|
|
socket->tcp_last_ack = ack; |
} |
|
|
/* Check if any tcp packets need to be re-transmitted */ |
void tcp_retransmit(socket_t* socket) |
void tcp_retransmit(socket_t* socket) |
{ |
int i; |
|
|
/* Find the packet that matches seq */ |
for (i=0;i<TCP_TX_BUFFERS;i=i+1) { |
if (socket->tcp_buf[i]->payload_valid && !socket->tcp_buf[i]->ack_received) { |
if (timer_expired(&socket->tcp_buf[i]->resend_time)) { |
|
|
/* Update the timer to trigger again in another little while */ |
set_timer(&socket->tcp_buf[i]->resend_time, 500); |
|
|
socket->packets_resent++; |
|
|
/* Disable ethmac_int interrupt */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x100; |
|
|
strncpy((char*)ETHMAC_TX_BUFFER, socket->tcp_buf[i]->buf, socket->tcp_buf[i]->len_bytes); |
tx_packet(socket->tcp_buf[i]->len_bytes); // MAC header, IP header, TCP header, TCP options |
socket->packets_sent++; |
|
|
|
|
/* Enable ethmac_int interrupt */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLESET ) = 0x100; |
break; |
434,14 → 516,14
char flags = 0; |
unsigned short len_tcp; |
unsigned int starting_seq; |
|
|
/* Source Port */ |
buf[0] = socket->rx_packet->tcp_dst_port >>8; |
buf[1] = socket->rx_packet->tcp_dst_port &0xff; |
buf[0] = socket->rx_packet->tcp_dst_port >>8; |
buf[1] = socket->rx_packet->tcp_dst_port &0xff; |
|
/* Destination Port */ |
buf[2] = socket->rx_packet->tcp_src_port >>8; |
buf[3] = socket->rx_packet->tcp_src_port &0xff; |
buf[2] = socket->rx_packet->tcp_src_port >>8; |
buf[3] = socket->rx_packet->tcp_src_port &0xff; |
|
/* Sequence Number */ |
/* Increment the sequence number for the next packet */ |
448,23 → 530,23
starting_seq = socket->tcp_seq; |
socket->tcp_last_seq = socket->tcp_seq; |
socket->tcp_seq += payload_length; |
|
|
|
|
buf[4] = starting_seq>>24; |
buf[5] = (starting_seq>>16)&0xff; |
buf[6] = (starting_seq>>8)&0xff; |
buf[7] = starting_seq&0xff; |
|
|
|
/* Ack Number */ |
if (options == TCP_NEW) |
ack_num = socket->rx_packet->tcp_seq + 1; |
else if (socket->rx_packet->tcp_flags & 0x01) // FIN |
else if (socket->rx_packet->tcp_flags & 0x01) // FIN |
// +1 to the final ack |
ack_num = socket->rx_packet->tcp_seq + 1; |
else |
ack_num = socket->rx_packet->tcp_seq + socket->rx_packet->tcp_payload_len; |
|
|
buf[8] = ack_num>>24; |
buf[9] = (ack_num>>16)&0xff; |
buf[10] = (ack_num>>8)&0xff; |
477,42 → 559,42
else |
buf[12] = 0x50; /* upper 4 bits, min is 5 */ |
|
|
|
/* Flags */ |
flags = 0x10; /* ACK */ |
flags = 0x10; /* ACK */ |
if (options == TCP_NEW) /* Valid in first reply in new connection only */ |
flags |= 0x02; /* SYNchronise */ |
if (socket->tcp_disconnect) |
if (socket->tcp_disconnect) |
flags |= 0x01; /* FINish */ |
if (socket->tcp_reset) |
if (socket->tcp_reset) |
flags |= 0x04; /* Reset */ |
|
|
buf[13] = flags; |
|
|
/* Window Size */ |
buf[14] = socket->rx_packet->tcp_window_size >> 8; |
buf[15] = socket->rx_packet->tcp_window_size & 0xff; |
|
|
/* Checksum */ |
buf[16] = 0; |
buf[17] = 0; |
|
|
/* Urgent Pointer */ |
buf[18] = 0; |
buf[19] = 0; |
|
|
|
|
if (options == TCP_NEW) { |
/* OPTION: max seg size */ |
buf[20] = 0x02; |
buf[21] = 0x04; |
buf[21] = 0x04; |
buf[22] = 0x05; |
buf[23] = 0xb4; |
|
|
/* OPTION Sack OK */ |
buf[24] = 0x04; |
buf[25] = 0x02; |
|
|
/* OPTION Time Stamp */ |
buf[26] = 0x08; |
buf[27] = 0x0a; |
524,7 → 606,7
buf[33] = (socket->rx_packet->tcp_src_time_stamp>>16)&0xff; |
buf[34] = (socket->rx_packet->tcp_src_time_stamp>>8)&0xff; |
buf[35] = socket->rx_packet->tcp_src_time_stamp&0xff; |
|
|
/* OPTION: NOP */ |
buf[36] = 0x01; |
|
534,19 → 616,19
buf[39] = 0x06; |
} |
|
|
|
/* Length */ |
if (options == TCP_NEW) |
len_tcp = 40+payload_length; |
else |
len_tcp = 20+payload_length; |
|
|
|
|
/* header checksum */ |
header_checksum = tcp_checksum(buf, socket->rx_packet, len_tcp); |
header_checksum = tcp_checksum(buf, socket->rx_packet, len_tcp); |
buf[16] = (header_checksum>>8)&0xff; |
buf[17] = header_checksum&0xff; |
|
|
return starting_seq; |
} |
|
555,23 → 637,23
{ |
unsigned short prot_tcp=6; |
unsigned short word16; |
unsigned long sum; |
unsigned long sum; |
int i; |
|
|
//initialize sum to zero |
sum=0; |
if (!len_tcp) len_tcp = rx_packet->tcp_len; |
|
|
|
|
// add the TCP pseudo header which contains: |
// the IP source and destinationn addresses, |
for (i=0;i<4;i=i+2){ |
word16 =((rx_packet->src_ip[i]<<8)&0xFF00)+(rx_packet->src_ip[i+1]&0xFF); |
sum=sum+word16; |
sum=sum+word16; |
} |
for (i=0;i<4;i=i+2){ |
word16 =((rx_packet->dst_ip[i]<<8)&0xFF00)+(rx_packet->dst_ip[i+1]&0xFF); |
sum=sum+word16; |
sum=sum+word16; |
} |
// the protocol number and the length of the TCP packet |
sum = sum + prot_tcp + len_tcp; |
580,3 → 662,31
return header_checksum16(buf, len_tcp, sum); |
} |
|
|
/* handle tcp connections and process buffers |
Poll all sockets in turn for activity */ |
void process_tcp(socket_t* socket) |
{ |
/* Check if any tcp packets need to be re-transmitted */ |
tcp_retransmit(socket); |
|
/* Handle exit command */ |
if (socket->tcp_disconnect && socket->tcp_connection_state == TCP_OPEN) { |
tcp_disconnect(socket); |
} |
|
/* Reset connection */ |
else if (socket->tcp_reset) { |
socket->tcp_connection_state = TCP_CLOSED; |
socket->telnet_connection_state = TELNET_CLOSED; |
socket->telnet_options_sent = 0; |
tcp_reply(socket, NULL, 0); |
socket->tcp_reset = 0; |
} |
|
/* handle telnet messages */ |
else if (socket->tcp_connection_state == TCP_OPEN){ |
process_telnet(socket); |
} |
} |
|
/sw/boot-loader-ethmac/udp.c
51,8 → 51,6
|
|
int udp_checksum_errors_g = 0; |
block_t* udp_file_g = NULL; |
block_t* udp_current_block_g = NULL; |
|
|
void parse_udp_packet(char * buf, packet_t* rx_packet) |
88,66 → 86,9
|
|
/* TFTP */ |
if (udp_dst_port == 69 && !checksum) { |
unsigned int opcode = buf[8]<<8|buf[9]; |
unsigned int block = buf[10]<<8|buf[11]; |
int tftp_len = udp_len - 12; |
if (udp_dst_port == 69 && !checksum) |
parse_tftp_packet(buf, rx_packet, udp_len-12, udp_src_port, udp_dst_port); |
|
mode_offset = next_string(&buf[10]); |
binary_mode = strcmp("octet", &buf[10+mode_offset]); |
|
switch (opcode) { |
|
case UDP_READ: |
udp_reply(rx_packet, udp_dst_port, udp_src_port, 0, UDP_ERROR); |
break; |
|
case UDP_WRITE: |
udp_file_g = init_buffer_512(); |
udp_file_g->filename = malloc(256); |
strcpy(udp_file_g->filename, &buf[10]); |
|
if (strncmp(&buf[10], "vmlinux", 7) == 0) |
udp_file_g->linux_boot = 1; |
|
udp_current_block_g = udp_file_g; |
|
if (binary_mode) |
udp_reply(rx_packet, udp_dst_port, udp_src_port, 0, UDP_ACK); |
else |
udp_reply(rx_packet, udp_dst_port, udp_src_port, 0, UDP_ERROR); |
break; |
|
|
case UDP_DATA: |
udp_reply(rx_packet, udp_dst_port, udp_src_port, block, UDP_ACK); |
|
if (block > udp_file_g->last_block) { |
// Have not already received this block |
udp_file_g->last_block = block; |
|
/* receive and save a block */ |
udp_current_block_g->bytes = tftp_len; |
udp_file_g->total_bytes += tftp_len; |
udp_file_g->total_blocks++; |
|
memcpy(udp_current_block_g->buf512, &buf[12], tftp_len); |
|
/* Prepare the next block */ |
if (tftp_len == 512) { |
udp_current_block_g->next = init_buffer_512(); |
udp_current_block_g = udp_current_block_g->next; |
} |
else { /* Last block */ |
udp_file_g->ready = 1; |
} |
} |
break; |
|
|
default: break; |
} |
} |
} |
|
|
236,19 → 177,3
tx_packet(34+udp_len); // packet length in bytes |
} |
|
|
block_t* init_buffer_512() |
{ |
block_t* block = malloc(sizeof(block_t)); |
block->buf512 = malloc(512); |
block->next = NULL; |
block->bytes = 0; |
block->last_block = 0; |
block->total_bytes = 0; |
block->total_blocks = 0; |
block->ready = 0; |
block->filename = NULL; |
block->linux_boot = 0; |
return block; |
} |
|
/sw/boot-loader-ethmac/tcp.h
53,6 → 53,49
}; |
|
|
typedef struct { |
|
packet_buffer_t** tcp_buf; |
int tcp_current_buf; |
|
/* Telnet rx and tx line buffers */ |
line_buf_t* telnet_rxbuf; |
line_buf_t* telnet_txbuf; |
|
int telnet_sent_opening_message; |
int telnet_echo_mode; |
int telnet_connection_state; |
int telnet_options_sent; |
|
int packets_sent; |
int packets_received; |
int packets_resent; |
|
int tcp_connection_state; |
int tcp_reset; |
int tcp_disconnect; |
int tcp_seq; /* should be random initial seq number for tcp */ |
int tcp_last_seq; |
unsigned int tcp_last_ack; |
|
int id; |
|
packet_t* rx_packet; /* Header info from last packet received */ |
|
/* pointers to the next socket in the chain and the first socket in the chain */ |
void* next; |
void* first; |
} socket_t; |
|
|
/* Global Variables */ |
extern socket_t* first_socket_g; |
extern int tcp_checksum_errors_g; |
|
|
/* Function prototypes */ |
socket_t* new_socket (socket_t* prev); |
|
unsigned short tcp_checksum (unsigned char *, packet_t*, unsigned short); |
unsigned int tcp_header (char *, socket_t*, int, int); |
void tcp_reply (socket_t*, char*, int); |
64,7 → 107,6
void tcp_tx (socket_t*, char*, int); |
void parse_tcp_options (char*, packet_t*); |
void parse_tcp_packet (char*, packet_t*); |
void process_tcp (socket_t*); |
|
extern int tcp_checksum_errors_g; |
|
|
/sw/boot-loader-ethmac/telnet.c
41,7 → 41,7
// // |
----------------------------------------------------------------*/ |
|
|
#include "address_map.h" |
#include "timer.h" |
#include "line-buffer.h" |
#include "packet.h" |
179,3 → 179,114
} |
} |
|
|
void process_telnet(socket_t* socket) |
{ |
char* line; |
|
if (!socket->telnet_options_sent){ |
telnet_options(socket); |
socket->telnet_options_sent = 1; |
} |
|
else { |
/* Send telnet greeting */ |
if (!socket->telnet_sent_opening_message){ |
put_line (socket->telnet_txbuf, "Amber Processor Boot Loader\r\n> "); |
socket->telnet_sent_opening_message = 1; |
} |
|
/* Parse telnet rx buffer */ |
if (get_line(socket->telnet_rxbuf, &line)) |
parse_command (socket, line); |
|
/* Transmit text from telnet tx buffer */ |
telnet_tx(socket, socket->telnet_txbuf); |
} |
} |
|
|
|
/* Parse a command line passed from main and execute the command */ |
/* returns the length of the reply string */ |
int parse_command (socket_t* socket, char* line) |
{ |
unsigned int start_addr; |
unsigned int address; |
unsigned int range; |
int len, error = 0; |
|
/* All commands are just a single character. |
Just ignore anything else */ |
switch (line[0]) { |
/* Disconnect */ |
case 'e': |
case 'x': |
case 'q': |
socket->tcp_disconnect = 1; |
return 0; |
|
case 'r': /* Read mem */ |
{ |
if (len = get_hex (&line[2], &start_addr)) { |
if (len = get_hex (&line[3+len], &range)) { |
for (address=start_addr; address<start_addr+range; address+=4) { |
put_line (socket->telnet_txbuf, "0x%08x 0x%08x\r\n", |
address, *(unsigned int *)address); |
} |
} |
else { |
put_line (socket->telnet_txbuf, "0x%08x 0x%08x\r\n", |
start_addr, *(unsigned int *)start_addr); |
} |
} |
else |
error=1; |
break; |
} |
|
|
case 'h': {/* Help */ |
put_line (socket->telnet_txbuf, "You need help alright\r\n"); |
break; |
} |
|
|
case 's': {/* Status */ |
put_line (socket->telnet_txbuf, "Socket ID %d\r\n", socket->id); |
put_line (socket->telnet_txbuf, "Packets received %d\r\n", socket->packets_received); |
put_line (socket->telnet_txbuf, "Packets transmitted %d\r\n", socket->packets_sent); |
put_line (socket->telnet_txbuf, "Packets resent %d\r\n", socket->packets_resent); |
put_line (socket->telnet_txbuf, "TCP checksum errors %d\r\n", tcp_checksum_errors_g); |
|
put_line (socket->telnet_txbuf, "Counterparty IP %d.%d.%d.%d\r\n", |
socket->rx_packet->src_ip[0], |
socket->rx_packet->src_ip[1], |
socket->rx_packet->src_ip[2], |
socket->rx_packet->src_ip[3]); |
|
put_line (socket->telnet_txbuf, "Counterparty Port %d\r\n", |
socket->rx_packet->tcp_src_port); |
|
put_line (socket->telnet_txbuf, "Malloc pointer 0x%08x\r\n", |
*(unsigned int *)(ADR_MALLOC_POINTER)); |
put_line (socket->telnet_txbuf, "Malloc count %d\r\n", |
*(unsigned int *)(ADR_MALLOC_COUNT)); |
put_line (socket->telnet_txbuf, "Uptime %d seconds\r\n", current_time_g->seconds); |
break; |
} |
|
|
default: { |
error=1; break; |
} |
} |
|
|
if (error) |
put_line (socket->telnet_txbuf, "You're not making any sense\r\n", |
line[0], line[1], line[2]); |
|
put_line (socket->telnet_txbuf, "> "); |
return 0; |
} |
/sw/boot-loader-ethmac/Makefile
40,10 → 40,10
# ---------------------------------------------------------------- |
# Assembly source files |
|
SRC = boot-loader-ethmac.c line-buffer.c timer.c print.c elfsplitter.c utilities.c \ |
serial.c ethmac.c packet.c tcp.c udp.c telnet.c start.S ../mini-libc/memcpy.c |
DEP = address_map.h boot-loader-ethmac.h line-buffer.h timer.h utilities.h \ |
serial.h ethmac.h tcp.h udp.h telnet.h packet.h elfsplitter.h |
SRC = boot-loader-ethmac.c line-buffer.c timer.c print.c elfsplitter.c utilities.c led.c \ |
serial.c ethmac.c packet.c tcp.c udp.c tftp.c telnet.c start.S ../mini-libc/memcpy.c |
DEP = address_map.h line-buffer.h timer.h utilities.h led.h \ |
serial.h ethmac.h tcp.h udp.h telnet.h tftp.h packet.h elfsplitter.h |
TGT = boot-loader-ethmac.elf |
LDS = sections.lds |
|
/sw/boot-loader-ethmac/elfsplitter.c
45,12 → 45,13
#include "line-buffer.h" |
#include "timer.h" |
#include "packet.h" |
#include "tcp.h" |
#include "telnet.h" |
#include "elfsplitter.h" |
|
|
|
int elfsplitter (char* inbuf, socket_t* socket) |
int elfsplitter (char* inbuf) |
{ |
unsigned int i, j, k; |
ElfHeader* elfHeader; |
/sw/boot-loader-ethmac/udp.h
39,26 → 39,11
----------------------------------------------------------------*/ |
|
|
typedef struct { |
char * buf512; |
void * next; |
unsigned int bytes; |
unsigned int last_block; |
unsigned int total_bytes; |
unsigned int total_blocks; |
unsigned int ready; |
unsigned int linux_boot; |
char* filename; |
} block_t; |
/* Global variables */ |
extern int udp_checksum_errors_g; |
|
|
|
/* Function prototypes */ |
void parse_udp_packet (char*, packet_t*); |
void udp_reply (packet_t*, int, int, int, int); |
block_t* init_buffer_512 (); |
|
|
/* Global variables */ |
extern int udp_checksum_errors_g; |
extern block_t* udp_file_g; |
extern block_t* udp_current_block_g; |
/hw/fpga/flash/README.txt
39,6 → 39,9
M0=on, M1=off |
Then press the PROG button just below it to load that bitfile from the SPI flash into the FPGA. |
|
To use the Parallel flash |
M0=off, M1=off |
|
|
Online tutorial for instructions with pictures - |
http://www.digilentinc.com/Data/Documents/Tutorials/MCS%20File%20Creation%20with%20Xilinx%20ISE%20Tutorial.pdf |