Commit 0f4fb1ca authored by Tomasz Wlostowski's avatar Tomasz Wlostowski

improved LM32 loader

parent e3f4734f
......@@ -19,224 +19,133 @@
* zpu-loader uses rawrabbit kernel driver written by Alessandro Rubini.
*/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/ioctl.h>
#include"rawrabbit.h"
#define DEVNAME "/dev/rawrabbit"
#define RST_ADDR 0xE2000
int rst_zpu(int spec, int rst);
int copy(int spec, int srcbin, unsigned int baseaddr);
int verify(int spec, int srcbin, unsigned int baseaddr);
int conv_endian(int x);
int dump_to_file(int spec, char *filename, unsigned int baseaddr);
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main(int argc, char **argv)
{
unsigned int addr = 0x80000;
int spec, srcbin;
unsigned int bytes;
char *dumpfile =NULL;
if(argc<2)
{
fprintf(stderr, "No parameters specified !\n");
fprintf(stderr, "Usage:\n\t./%s [-r] <binary file> [base address]\n", argv[0]);
fprintf(stderr, "-r options dumps the memory contents to a given file.\n\n");
return -1;
}
#define BASE_PCIE 0x80000
#define BASE_MBONE 0x00000
if(!strcmp(argv[1], "-r"))
dumpfile = argv[2];
else if(argc==3)
addr = atoi(argv[2]);
#define RST_ADDR 0x62000
#define MEM_ADDR 0x0
#include "rr_io.h"
#include "minibone_lib.h"
spec = open(DEVNAME, O_RDWR);
if(spec < 0)
{
perror("Could not open device");
return -1;
}
if(dumpfile)
{
dump_to_file(spec, dumpfile, addr);
return 0;
}
static void *mb_handle = NULL;
srcbin = open(argv[1], O_RDONLY);
if(srcbin < 0)
{
perror("Could not open binary file");
close(spec);
return -1;
}
rst_zpu(spec, 1);
bytes = copy(spec, srcbin, addr);
if(bytes < 0)
{
close(srcbin);
close(spec);
return -1;
}
printf("Wrote %u bytes\n", bytes);
verify(spec, srcbin, addr);
rst_zpu(spec, 0);
close(srcbin);
close(spec);
return 0;
}
int copy(int spec, int srcbin, unsigned int baseaddr)
static void spec_writel(uint32_t value, uint32_t addr)
{
unsigned int bytes, word;
struct rr_iocmd iocmd;
int ret;
printf("Writing memory: ");
bytes=0;
while(1)
{
ret = read(srcbin, &word, 4); /*read 32-bit word*/
if(ret<0)
{
perror("Error while reading binary file");
return -1;
}
else if(ret==0)
{
printf("Done\n");
break;
}
iocmd.address = baseaddr+bytes;
bytes += ret; //address shift for next write
iocmd.address |= __RR_SET_BAR(0); //bar0
iocmd.datasize = 4;
iocmd.data32 = conv_endian(word);
ret = ioctl(spec, RR_WRITE, &iocmd);
if(ret<0)
{
perror("Error while writing to SPEC");
return -1;
}
printf(".");
}
return bytes;
if(mb_handle)
mbn_writel(mb_handle, value, BASE_MBONE + addr);
else
rr_writel(value, BASE_PCIE + addr);
}
int dump_to_file(int spec, char *filename, unsigned int baseaddr)
static uint32_t spec_readl(uint32_t addr)
{
unsigned int bytes, word;
struct rr_iocmd iocmd;
int ret;
FILE *f= fopen(filename,"wb");
if(!f)
return -1;
bytes=0;
while(bytes < 0x10000)
{
uint32_t rval;
if(mb_handle)
rval = mbn_readl(mb_handle, BASE_MBONE + addr);
else
rval = rr_readl(BASE_PCIE + addr);
iocmd.address = baseaddr+bytes;
// bytes += ret; //address shift for next write
iocmd.address |= __RR_SET_BAR(0); //bar0
iocmd.datasize = 4;
iocmd.data32 = 0;
ret = ioctl(spec, RR_READ, &iocmd);
word = conv_endian(iocmd.data32);
fwrite(&word, 4, 1, f);
// printf("readl: value %x addr %x\n", addr, rval);
bytes+=4;
return rval;
}
}
fclose(f);
int conv_endian(int x)
{
return ((x&0xff000000)>>24) + ((x&0x00ff0000)>>8) + ((x&0x0000ff00)<<8) + ((x&0x000000ff)<<24);
}
void rst_lm32(int rst)
{
spec_writel(rst ? 1 : 0, RST_ADDR);
}
int verify(int spec, int srcbin, unsigned int baseaddr)
void copy_lm32(uint32_t *buf, int buf_nwords, uint32_t base_addr)
{
unsigned int wbin;
struct rr_iocmd iocmd;
unsigned int bytes;
int ret;
int i;
printf("Writing memory: ");
for(i=0;i<buf_nwords;i++)
{
spec_writel(conv_endian(buf[i]), base_addr + i *4);
if(!(i & 0xfff)) { printf("."); fflush(stdout); }
}
printf("Verifing: ");
printf("\nVerifing memory: ");
bytes = 0;
while(1)
for(i=0;i<buf_nwords;i++)
{
ret = read(srcbin, &wbin, 4); /*read 32-bit word*/
if(ret<0)
{
perror("Error while reading binary file");
return -1;
}
else if(ret==0)
{
printf("OK !\n");
break;
}
iocmd.address = baseaddr+bytes;
bytes += ret;
iocmd.address |= __RR_SET_BAR(0); //bar0
iocmd.datasize = 4;
ret = ioctl(spec, RR_READ, &iocmd);
if(ret<0)
{
perror("Error while reading SPEC memory");
return -1;
}
if(iocmd.data32 != conv_endian(wbin))
{
printf("Error (@word %u)\n", bytes/4);
return -1;
}
printf(".");
return 0;
}
uint32_t x = spec_readl(base_addr+ i*4);
if(conv_endian(buf[i]) != x)
{
printf("Verify failed (%x vs %x)\n", conv_endian(buf[i]), x);
return ;
}
if(!(i & 0xfff)) { printf("."); fflush(stdout); }
}
return 0;
printf("OK.\n");
}
int rst_zpu(int spec, int rst)
int main(int argc, char **argv)
{
struct rr_iocmd iocmd;
iocmd.address = RST_ADDR;
iocmd.address |= __RR_SET_BAR(0); //bar0
iocmd.datasize = 4;
iocmd.data32 = rst;
if( ioctl(spec, RR_WRITE, &iocmd) < 0)
int num_words;
uint32_t *buf;
uint8_t target_mac[6];
FILE *f;
char if_name[16];
if(argc<2)
{
perror("Could not reset ZPU");
fprintf(stderr, "No parameters specified !\n");
fprintf(stderr, "Usage:\n\t%s <binary file> [-m network_if mac_addr]\n", argv[0]);
fprintf(stderr, "By default the loader assumes that the card is in a PCIe slot. \n");
fprintf(stderr, "-m option enables remove programming via ethernet. \n");
return -1;
}
return 0;
}
if(argc >= 4 && !strcmp(argv[2], "-m"))
{
sscanf(argv[3], "%s",if_name);
sscanf(argv[4], "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", &target_mac[0], &target_mac[1], &target_mac[2], &target_mac[3], &target_mac[4], &target_mac[5]);
mb_handle = mbn_open(if_name, target_mac);
if(!mb_handle)
{
fprintf(stderr,"Connection failed....\n");
return -1;
}
} else if( rr_init() < 0)
{
fprintf(stderr,"Can't initialize rawrabbit :(\n");
return -1;
}
f=fopen(argv[1],"rb");
if(!f)
{
fprintf(stderr, "Input file not found.\n");
return -1;
}
fseek(f, 0, SEEK_END);
int size = ftell(f);
rewind(f);
buf = malloc(size + 4);
fread(buf, 1, size, f);
fclose(f);
rst_lm32(1);
copy_lm32(buf, (size + 3) / 4, 0);
rst_lm32(0);
int conv_endian(int x)
{
return ((x&0xff000000)>>24) + ((x&0x00ff0000)>>8) + ((x&0x0000ff00)<<8) + ((x&0x000000ff)<<24);
return 0;
}
OBJS = minibone_lib.o ptpd_netif.o
all: $(OBJS)
gcc -o m $(OBJS)
\ No newline at end of file
/* MiniBone library. BUGGY CRAP CODE INTENDED FOR TESTING ONLY! */
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <sys/socket.h>
#include <sys/time.h>
#include "ptpd_netif.h"
#define F_SEL(x) (x & 0xf)
#define F_ERROR (1<<1)
#define F_READBACK (1<<0)
#define F_WRITE (1<<4)
#define RX_TIMEOUT 100
#define MBN_ETHERTYPE 0xa0a0
struct mbn_packet {
uint16_t flags ;
uint32_t a_d;
uint32_t d;
} __attribute__((packed));
struct mb_device {
mac_addr_t dest;
uint16_t ethertype;
wr_socket_t *sock;
};
typedef struct
{
uint64_t start_tics;
uint64_t timeout;
} timeout_t ;
static uint64_t get_tics()
{
struct timezone tz = {0, 0};
struct timeval tv;
gettimeofday(&tv, &tz);
return (uint64_t) tv.tv_sec * 1000000ULL + (uint64_t) tv.tv_usec;
}
static inline int tmo_init(timeout_t *tmo, uint32_t milliseconds)
{
tmo->start_tics = get_tics();
tmo->timeout = (uint64_t) milliseconds * 1000ULL;
return 0;
}
static inline int tmo_restart(timeout_t *tmo)
{
tmo->start_tics = get_tics();
return 0;
}
static inline int tmo_expired(timeout_t *tmo)
{
return (get_tics() - tmo->start_tics > tmo->timeout);
}
void *mbn_open(const char *if_name, mac_addr_t target)
{
struct mb_device *dev = malloc(sizeof(struct mb_device));
wr_sockaddr_t saddr;
if(!dev)
return NULL;
memcpy(dev->dest, target, 6);
strcpy(saddr.if_name, if_name);
memcpy(saddr.mac, target, 6);
saddr.ethertype = htons(MBN_ETHERTYPE);
saddr.family = PTPD_SOCK_RAW_ETHERNET;
dev->sock = ptpd_netif_create_socket(PTPD_SOCK_RAW_ETHERNET, 0, &saddr);
if(!dev->sock)
{
free(dev);
return NULL;
}
return (void *)dev;
}
static int mbn_send(void *priv, uint8_t *data, int size)
{
struct mb_device *dev = (struct mb_device *)priv;
wr_sockaddr_t to;
memcpy(to.mac, dev->dest, 6);
to.ethertype = MBN_ETHERTYPE;
return ptpd_netif_sendto(dev->sock, &to, (void*)data, size, NULL);
}
static int mbn_recv(void *handle, uint8_t *data, int size, int timeout)
{
struct mb_device *dev = (struct mb_device *)handle;
wr_sockaddr_t from;
timeout_t rx_tmo;
tmo_init(&rx_tmo, timeout);
do {
int n = ptpd_netif_recvfrom(dev->sock, &from, (void*)data, size, NULL);
if(n > 0 && from.ethertype == MBN_ETHERTYPE && !memcmp(from.mac, dev->dest, 6))
{
return n;
}
} while(!tmo_expired(&rx_tmo));
return 0;
}
void mbn_writel(void *handle, uint32_t d, uint32_t a)
{
int n_retries = 3;
struct mbn_packet pkt;
pkt.flags = htons(F_SEL(0xf) | F_WRITE);
pkt.a_d= htonl(a);
pkt.d=htonl(d);
while(n_retries--)
{
mbn_send(handle, (uint8_t *)&pkt, sizeof(pkt));
int n = mbn_recv(handle, (uint8_t *)&pkt, sizeof(pkt), RX_TIMEOUT);
pkt.flags = ntohs(pkt.flags);
if(n == sizeof(pkt) && !(pkt.flags && F_READBACK) && !(pkt.flags & F_ERROR))
{
return ;
}
}
fprintf(stderr, "No ack.\n");
}
uint32_t mbn_readl(void *handle, uint32_t a)
{
int n_retries = 3;
struct mbn_packet pkt;
pkt.flags = htons(F_SEL(0xf));
pkt.a_d= htonl(a);
while(n_retries--)
{
mbn_send(handle, (uint8_t *)&pkt, sizeof(pkt));
int n = mbn_recv(handle, (uint8_t *)&pkt, sizeof(pkt), RX_TIMEOUT);
pkt.flags = ntohs(pkt.flags);
if(n == sizeof(pkt) && (pkt.flags & F_READBACK) && !(pkt.flags & F_ERROR))
{
return ntohl(pkt.a_d);
}
}
fprintf(stderr, "No ack.\n");
}
void mbn_close(void *handle)
{
struct mb_device *dev = (struct mb_device *)handle;
ptpd_netif_close_socket(dev->sock);
}
\ No newline at end of file
/* MiniBone library. BUGGY CRAP CODE INTENDED FOR TESTING ONLY! */
#ifndef __MINIBONE_LIB_H
#define __MINIBONE_LIB_H
#include <stdint.h>
void *mbn_open(const char *if_name, uint8_t target_mac[]);
void mbn_writel(void *handle, uint32_t d, uint32_t a);
uint32_t mbn_readl(void *handle, uint32_t a);
void mbn_close(void *handle);
#endif
// Supports only raw ethernet now.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
#include <linux/errqueue.h>
#include <linux/sockios.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <asm/types.h>
#include <fcntl.h>
#include <errno.h>
#include <asm/socket.h>
#include "ptpd_netif.h"
#ifdef NETIF_VERBOSE
#define netif_dbg(...) printf(__VA_ARGS__)
#else
#define netif_dbg(...)
#endif
#define ETHER_MTU 1518
#define DMTD_UPDATE_INTERVAL 100
struct scm_timestamping {
struct timespec systime;
struct timespec hwtimetrans;
struct timespec hwtimeraw;
};
PACKED struct etherpacket {
struct ethhdr ether;
char data[ETHER_MTU];
};
struct tx_timestamp {
int valid;
wr_timestamp_t ts;
uint32_t tag;
uint64_t t_acq;
};
struct my_socket {
int fd;
wr_sockaddr_t bind_addr;
mac_addr_t local_mac;
int if_index;
// parameters for linearization of RX timestamps
uint32_t clock_period;
uint32_t phase_transition;
uint32_t dmtd_phase;
};
struct nasty_hack{
char if_name[20];
int clockedAsPrimary;
};
#ifdef MACIEK_HACKs
struct nasty_hack locking_hack;
#endif
wr_socket_t *ptpd_netif_create_socket(int sock_type, int flags,
wr_sockaddr_t *bind_addr)
{
struct my_socket *s;
struct sockaddr_ll sll;
struct ifreq f;
int fd;
// fprintf(stderr,"CreateSocket!\n");
if(sock_type != PTPD_SOCK_RAW_ETHERNET)
return NULL;
fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if(fd < 0)
{
perror("socket()");
return NULL;
}
fcntl(fd, F_SETFL, O_NONBLOCK);
// Put the controller in promiscious mode, so it receives everything
strcpy(f.ifr_name, bind_addr->if_name);
if(ioctl(fd, SIOCGIFFLAGS,&f) < 0) { perror("ioctl()"); return NULL; }
f.ifr_flags |= IFF_PROMISC;
if(ioctl(fd, SIOCSIFFLAGS,&f) < 0) { perror("ioctl()"); return NULL; }
// Find the inteface index
strcpy(f.ifr_name, bind_addr->if_name);
ioctl(fd, SIOCGIFINDEX, &f);
sll.sll_ifindex = f.ifr_ifindex;
sll.sll_family = AF_PACKET;
sll.sll_protocol = htons(bind_addr->ethertype);
sll.sll_halen = 6;
memcpy(sll.sll_addr, bind_addr->mac, 6);
if(bind(fd, (struct sockaddr *)&sll, sizeof(struct sockaddr_ll)) < 0)
{
close(fd);
perror("bind()");
return NULL;
}
s=calloc(sizeof(struct my_socket), 1);
s->if_index = f.ifr_ifindex;
// get interface MAC address
if (ioctl(fd, SIOCGIFHWADDR, &f) < 0) {
perror("ioctl()"); return NULL;
}
memcpy(s->local_mac, f.ifr_hwaddr.sa_data, 6);
memcpy(&s->bind_addr, bind_addr, sizeof(wr_sockaddr_t));
s->fd = fd;
return (wr_socket_t*)s;
}
int ptpd_netif_close_socket(wr_socket_t *sock)
{
struct my_socket *s = (struct my_socket *) sock;
if(!s)
return 0;
close(s->fd);
return 0;
}
int ptpd_netif_sendto(wr_socket_t *sock, wr_sockaddr_t *to, void *data,
size_t data_length, wr_timestamp_t *tx_ts)
{
struct etherpacket pkt;
struct my_socket *s = (struct my_socket *)sock;
struct sockaddr_ll sll;
int rval;
wr_timestamp_t ts;
if(s->bind_addr.family != PTPD_SOCK_RAW_ETHERNET)
return -ENOTSUP;
if(data_length > ETHER_MTU-8) return -EINVAL;
memset(&pkt, 0, sizeof(struct etherpacket));
memcpy(pkt.ether.h_dest, to->mac, 6);
memcpy(pkt.ether.h_source, s->local_mac, 6);
pkt.ether.h_proto =htons(to->ethertype);
memcpy(pkt.data, data, data_length);
size_t len = data_length + sizeof(struct ethhdr);
if(len < 64)
len = 64;
memset(&sll, 0, sizeof(struct sockaddr_ll));
sll.sll_ifindex = s->if_index;
sll.sll_family = AF_PACKET;
sll.sll_protocol = htons(to->ethertype);
sll.sll_halen = 6;
// fprintf(stderr,"fd %d ifi %d ethertype %d\n", s->fd,
// s->if_index, to->ethertype);
rval = sendto(s->fd, &pkt, len, 0, (struct sockaddr *)&sll,
sizeof(struct sockaddr_ll));
return rval;
}
int ptpd_netif_recvfrom(wr_socket_t *sock, wr_sockaddr_t *from, void *data,
size_t data_length, wr_timestamp_t *rx_timestamp)
{
struct my_socket *s = (struct my_socket *)sock;
struct etherpacket pkt;
struct msghdr msg;
struct iovec entry;
struct sockaddr_ll from_addr;
struct {
struct cmsghdr cm;
char control[1024];
} control;
struct cmsghdr *cmsg;
struct scm_timestamping *sts = NULL;