/* vapi.c -- Verification API Interface
|
/* vapi.c -- Verification API Interface
|
|
|
Copyright (C) 2001, Marko Mlinar, markom@opencores.org
|
Copyright (C) 2001, Marko Mlinar, markom@opencores.org
|
Copyright (C) 2008 Embecosm Limited
|
Copyright (C) 2008 Embecosm Limited
|
|
|
Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
|
Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
|
|
|
This file is part of OpenRISC 1000 Architectural Simulator.
|
This file is part of OpenRISC 1000 Architectural Simulator.
|
|
|
This program is free software; you can redistribute it and/or modify it
|
This program is free software; you can redistribute it and/or modify it
|
under the terms of the GNU General Public License as published by the Free
|
under the terms of the GNU General Public License as published by the Free
|
Software Foundation; either version 3 of the License, or (at your option)
|
Software Foundation; either version 3 of the License, or (at your option)
|
any later version.
|
any later version.
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
more details.
|
more details.
|
|
|
You should have received a copy of the GNU General Public License along
|
You should have received a copy of the GNU General Public License along
|
with this program. If not, see <http://www.gnu.org/licenses/>. */
|
with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
/* This program is commented throughout in a fashion suitable for processing
|
/* This program is commented throughout in a fashion suitable for processing
|
with Doxygen. */
|
with Doxygen. */
|
|
|
|
|
/* Autoconf and/or portability configuration */
|
/* Autoconf and/or portability configuration */
|
#include "config.h"
|
#include "config.h"
|
#include "port.h"
|
#include "port.h"
|
|
|
/* System includes */
|
/* System includes */
|
#include <stdlib.h>
|
#include <stdlib.h>
|
#include <unistd.h>
|
#include <unistd.h>
|
#include <stdio.h>
|
#include <stdio.h>
|
#include <errno.h>
|
#include <errno.h>
|
#include <sys/poll.h>
|
#include <sys/poll.h>
|
#include <sys/socket.h>
|
#include <sys/socket.h>
|
#include <netinet/in.h>
|
#include <netinet/in.h>
|
#include <fcntl.h>
|
#include <fcntl.h>
|
#include <netdb.h>
|
#include <netdb.h>
|
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
|
|
/* Package includes */
|
/* Package includes */
|
#include "sim-config.h"
|
#include "sim-config.h"
|
#include "vapi.h"
|
#include "vapi.h"
|
|
|
|
|
static unsigned int serverIP = 0;
|
static unsigned int serverIP = 0;
|
|
|
static unsigned int server_fd = 0;
|
static unsigned int server_fd = 0;
|
static unsigned int nhandlers = 0;
|
static unsigned int nhandlers = 0;
|
|
|
static int tcp_level = 0;
|
static int tcp_level = 0;
|
|
|
static struct vapi_handler
|
static struct vapi_handler
|
{
|
{
|
int fd;
|
int fd;
|
unsigned long base_id, num_ids;
|
unsigned long base_id, num_ids;
|
void (*read_func) (unsigned long, unsigned long, void *);
|
void (*read_func) (unsigned long, unsigned long, void *);
|
void *priv_dat;
|
void *priv_dat;
|
struct vapi_handler *next;
|
struct vapi_handler *next;
|
int temp;
|
int temp;
|
} *vapi_handler = NULL;
|
} *vapi_handler = NULL;
|
|
|
/* Structure for polling, it is cached, that it doesn't have to be rebuilt each time */
|
/* Structure for polling, it is cached, that it doesn't have to be rebuilt each time */
|
static struct pollfd *fds = NULL;
|
static struct pollfd *fds = NULL;
|
static int nfds = 0;
|
static int nfds = 0;
|
|
|
/* Rebuilds the fds structures; see fds. */
|
/* Rebuilds the fds structures; see fds. */
|
void
|
void
|
rebuild_fds ()
|
rebuild_fds ()
|
{
|
{
|
struct vapi_handler *t;
|
struct vapi_handler *t;
|
if (fds)
|
if (fds)
|
free (fds);
|
free (fds);
|
fds = (struct pollfd *) malloc (sizeof (struct pollfd) * (nhandlers + 1));
|
fds = (struct pollfd *) malloc (sizeof (struct pollfd) * (nhandlers + 1));
|
if (!fds)
|
if (!fds)
|
{
|
{
|
fprintf (stderr, "FATAL: Out of memory.\n");
|
fprintf (stderr, "FATAL: Out of memory.\n");
|
exit (1);
|
exit (1);
|
}
|
}
|
|
|
nfds = 0;
|
nfds = 0;
|
fds[nfds].fd = server_fd;
|
fds[nfds].fd = server_fd;
|
fds[nfds].events = POLLIN;
|
fds[nfds].events = POLLIN;
|
fds[nfds++].revents = 0;
|
fds[nfds++].revents = 0;
|
|
|
for (t = vapi_handler; t; t = t->next)
|
for (t = vapi_handler; t; t = t->next)
|
{
|
{
|
if (t->fd)
|
if (t->fd)
|
{
|
{
|
t->temp = nfds;
|
t->temp = nfds;
|
fds[nfds].fd = t->fd;
|
fds[nfds].fd = t->fd;
|
fds[nfds].events = POLLIN;
|
fds[nfds].events = POLLIN;
|
fds[nfds++].revents = 0;
|
fds[nfds++].revents = 0;
|
}
|
}
|
else
|
else
|
t->temp = -1;
|
t->temp = -1;
|
}
|
}
|
}
|
}
|
|
|
/* Determines whether a certain handler handles an ID */
|
/* Determines whether a certain handler handles an ID */
|
static int
|
static int
|
handler_fits_id (const struct vapi_handler *t, unsigned long id)
|
handler_fits_id (const struct vapi_handler *t, unsigned long id)
|
{
|
{
|
return ((id >= t->base_id) && (id < t->base_id + t->num_ids));
|
return ((id >= t->base_id) && (id < t->base_id + t->num_ids));
|
}
|
}
|
|
|
/* Finds a handler with given ID, return it, NULL if not found. */
|
/* Finds a handler with given ID, return it, NULL if not found. */
|
static struct vapi_handler *
|
static struct vapi_handler *
|
find_handler (unsigned long id)
|
find_handler (unsigned long id)
|
{
|
{
|
struct vapi_handler *t = vapi_handler;
|
struct vapi_handler *t = vapi_handler;
|
while (t && !handler_fits_id (t, id))
|
while (t && !handler_fits_id (t, id))
|
t = t->next;
|
t = t->next;
|
return t;
|
return t;
|
}
|
}
|
|
|
/* Adds a handler with given id and returns it. */
|
/* Adds a handler with given id and returns it. */
|
static struct vapi_handler *
|
static struct vapi_handler *
|
add_handler (unsigned long base_id, unsigned long num_ids)
|
add_handler (unsigned long base_id, unsigned long num_ids)
|
{
|
{
|
struct vapi_handler **t = &vapi_handler;
|
struct vapi_handler **t = &vapi_handler;
|
struct vapi_handler *tt;
|
struct vapi_handler *tt;
|
while ((*t))
|
while ((*t))
|
t = &(*t)->next;
|
t = &(*t)->next;
|
tt = (struct vapi_handler *) malloc (sizeof (struct vapi_handler));
|
tt = (struct vapi_handler *) malloc (sizeof (struct vapi_handler));
|
tt->next = NULL;
|
tt->next = NULL;
|
tt->base_id = base_id;
|
tt->base_id = base_id;
|
tt->num_ids = num_ids;
|
tt->num_ids = num_ids;
|
tt->read_func = NULL;
|
tt->read_func = NULL;
|
tt->priv_dat = NULL;
|
tt->priv_dat = NULL;
|
tt->fd = 0;
|
tt->fd = 0;
|
(*t) = tt;
|
(*t) = tt;
|
free (fds);
|
free (fds);
|
fds = NULL;
|
fds = NULL;
|
nhandlers++;
|
nhandlers++;
|
rebuild_fds ();
|
rebuild_fds ();
|
return tt;
|
return tt;
|
}
|
}
|
|
|
void
|
void
|
vapi_write_log_file (VAPI_COMMAND command, unsigned long devid,
|
vapi_write_log_file (VAPI_COMMAND command, unsigned long devid,
|
unsigned long data)
|
unsigned long data)
|
{
|
{
|
if (!runtime.vapi.vapi_file)
|
if (!runtime.vapi.vapi_file)
|
return;
|
return;
|
if (!config.vapi.hide_device_id && devid <= VAPI_MAX_DEVID)
|
if (!config.vapi.hide_device_id && devid <= VAPI_MAX_DEVID)
|
fprintf (runtime.vapi.vapi_file, "%04lx", devid);
|
fprintf (runtime.vapi.vapi_file, "%04lx", devid);
|
fprintf (runtime.vapi.vapi_file, "%1x%08lx\n", command, data);
|
fprintf (runtime.vapi.vapi_file, "%1x%08lx\n", command, data);
|
}
|
}
|
|
|
static int
|
static int
|
vapi_write_stream (int fd, void *buf, int len)
|
vapi_write_stream (int fd, void *buf, int len)
|
{
|
{
|
int n;
|
int n;
|
char *w_buf = (char *) buf;
|
char *w_buf = (char *) buf;
|
struct pollfd block;
|
struct pollfd block;
|
|
|
while (len)
|
while (len)
|
{
|
{
|
if ((n = write (fd, w_buf, len)) < 0)
|
if ((n = write (fd, w_buf, len)) < 0)
|
{
|
{
|
switch (errno)
|
switch (errno)
|
{
|
{
|
case EWOULDBLOCK: /* or EAGAIN */
|
case EWOULDBLOCK: /* or EAGAIN */
|
/* We've been called on a descriptor marked
|
/* We've been called on a descriptor marked
|
for nonblocking I/O. We better simulate
|
for nonblocking I/O. We better simulate
|
blocking behavior. */
|
blocking behavior. */
|
block.fd = fd;
|
block.fd = fd;
|
block.events = POLLOUT;
|
block.events = POLLOUT;
|
block.revents = 0;
|
block.revents = 0;
|
poll (&block, 1, -1);
|
poll (&block, 1, -1);
|
continue;
|
continue;
|
case EINTR:
|
case EINTR:
|
continue;
|
continue;
|
case EPIPE:
|
case EPIPE:
|
close (fd);
|
close (fd);
|
fd = 0;
|
fd = 0;
|
return -1;
|
return -1;
|
default:
|
default:
|
return -1;
|
return -1;
|
}
|
}
|
}
|
}
|
else
|
else
|
{
|
{
|
len -= n;
|
len -= n;
|
w_buf += n;
|
w_buf += n;
|
}
|
}
|
}
|
}
|
return 0;
|
return 0;
|
}
|
}
|
|
|
static int
|
static int
|
vapi_read_stream (int fd, void *buf, int len)
|
vapi_read_stream (int fd, void *buf, int len)
|
{
|
{
|
int n;
|
int n;
|
char *r_buf = (char *) buf;
|
char *r_buf = (char *) buf;
|
struct pollfd block;
|
struct pollfd block;
|
|
|
while (len)
|
while (len)
|
{
|
{
|
if ((n = read (fd, r_buf, len)) < 0)
|
if ((n = read (fd, r_buf, len)) < 0)
|
{
|
{
|
switch (errno)
|
switch (errno)
|
{
|
{
|
case EWOULDBLOCK: /* or EAGAIN */
|
case EWOULDBLOCK: /* or EAGAIN */
|
/* We've been called on a descriptor marked
|
/* We've been called on a descriptor marked
|
for nonblocking I/O. We better simulate
|
for nonblocking I/O. We better simulate
|
blocking behavior. */
|
blocking behavior. */
|
block.fd = fd;
|
block.fd = fd;
|
block.events = POLLIN;
|
block.events = POLLIN;
|
block.revents = 0;
|
block.revents = 0;
|
poll (&block, 1, -1);
|
poll (&block, 1, -1);
|
continue;
|
continue;
|
case EINTR:
|
case EINTR:
|
continue;
|
continue;
|
default:
|
default:
|
return -1;
|
return -1;
|
}
|
}
|
}
|
}
|
else if (n == 0)
|
else if (n == 0)
|
{
|
{
|
close (fd);
|
close (fd);
|
fd = 0;
|
fd = 0;
|
return -1;
|
return -1;
|
}
|
}
|
else
|
else
|
{
|
{
|
len -= n;
|
len -= n;
|
r_buf += n;
|
r_buf += n;
|
}
|
}
|
}
|
}
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Added by CZ 24/05/01 */
|
/* Added by CZ 24/05/01 */
|
int
|
int
|
get_server_socket (const char *name, const char *proto, int port)
|
get_server_socket (const char *name, const char *proto, int port)
|
{
|
{
|
struct servent *service;
|
struct servent *service;
|
struct protoent *protocol;
|
struct protoent *protocol;
|
struct sockaddr_in sa;
|
struct sockaddr_in sa;
|
struct hostent *hp;
|
struct hostent *hp;
|
int sockfd;
|
int sockfd;
|
socklen_t len;
|
socklen_t len;
|
char myname[256];
|
char myname[256];
|
int flags;
|
int flags;
|
char sTemp[256];
|
char sTemp[256];
|
|
|
/* First, get the protocol number of TCP */
|
/* First, get the protocol number of TCP */
|
if (!(protocol = getprotobyname (proto)))
|
if (!(protocol = getprotobyname (proto)))
|
{
|
{
|
sprintf (sTemp, "Unable to load protocol \"%s\"", proto);
|
sprintf (sTemp, "Unable to load protocol \"%s\"", proto);
|
perror (sTemp);
|
perror (sTemp);
|
return 0;
|
return 0;
|
}
|
}
|
tcp_level = protocol->p_proto; /* Save for later */
|
tcp_level = protocol->p_proto; /* Save for later */
|
|
|
/* If we weren't passed a non standard port, get the port
|
/* If we weren't passed a non standard port, get the port
|
from the services directory. */
|
from the services directory. */
|
if (!port)
|
if (!port)
|
{
|
{
|
if ((service = getservbyname (name, protocol->p_name)))
|
if ((service = getservbyname (name, protocol->p_name)))
|
port = ntohs (service->s_port);
|
port = ntohs (service->s_port);
|
}
|
}
|
|
|
/* Create the socket using the TCP protocol */
|
/* Create the socket using the TCP protocol */
|
if ((sockfd = socket (PF_INET, SOCK_STREAM, protocol->p_proto)) < 0)
|
if ((sockfd = socket (PF_INET, SOCK_STREAM, protocol->p_proto)) < 0)
|
{
|
{
|
perror ("Unable to create socket");
|
perror ("Unable to create socket");
|
return 0;
|
return 0;
|
}
|
}
|
|
|
flags = 1;
|
flags = 1;
|
if (setsockopt
|
if (setsockopt
|
(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char *) &flags,
|
(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char *) &flags,
|
sizeof (int)) < 0)
|
sizeof (int)) < 0)
|
{
|
{
|
sprintf (sTemp, "Can not set SO_REUSEADDR option on socket %d", sockfd);
|
sprintf (sTemp, "Can not set SO_REUSEADDR option on socket %d", sockfd);
|
perror (sTemp);
|
perror (sTemp);
|
close (sockfd);
|
close (sockfd);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* The server should also be non blocking. Get the current flags. */
|
/* The server should also be non blocking. Get the current flags. */
|
if (fcntl (sockfd, F_GETFL, &flags) < 0)
|
if (fcntl (sockfd, F_GETFL, &flags) < 0)
|
{
|
{
|
sprintf (sTemp, "Unable to get flags for socket %d", sockfd);
|
sprintf (sTemp, "Unable to get flags for socket %d", sockfd);
|
perror (sTemp);
|
perror (sTemp);
|
close (sockfd);
|
close (sockfd);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Set the nonblocking flag */
|
/* Set the nonblocking flag */
|
if (fcntl (sockfd, F_SETFL, flags | O_NONBLOCK) < 0)
|
if (fcntl (sockfd, F_SETFL, flags | O_NONBLOCK) < 0)
|
{
|
{
|
sprintf (sTemp, "Unable to set flags for socket %d to value 0x%08x",
|
sprintf (sTemp, "Unable to set flags for socket %d to value 0x%08x",
|
sockfd, flags | O_NONBLOCK);
|
sockfd, flags | O_NONBLOCK);
|
perror (sTemp);
|
perror (sTemp);
|
close (sockfd);
|
close (sockfd);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Find out what our address is */
|
/* Find out what our address is */
|
memset (&sa, 0, sizeof (struct sockaddr_in));
|
memset (&sa, 0, sizeof (struct sockaddr_in));
|
gethostname (myname, sizeof (myname));
|
gethostname (myname, sizeof (myname));
|
if (!(hp = gethostbyname (myname)))
|
if (!(hp = gethostbyname (myname)))
|
{
|
{
|
perror ("Unable to read hostname");
|
perror ("Unable to read hostname");
|
close (sockfd);
|
close (sockfd);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Bind our socket to the appropriate address */
|
/* Bind our socket to the appropriate address */
|
sa.sin_family = hp->h_addrtype;
|
sa.sin_family = hp->h_addrtype;
|
sa.sin_port = htons (port);
|
sa.sin_port = htons (port);
|
if (bind (sockfd, (struct sockaddr *) &sa, sizeof (struct sockaddr_in)) < 0)
|
if (bind (sockfd, (struct sockaddr *) &sa, sizeof (struct sockaddr_in)) < 0)
|
{
|
{
|
sprintf (sTemp, "Unable to bind socket %d to port %d", sockfd, port);
|
sprintf (sTemp, "Unable to bind socket %d to port %d", sockfd, port);
|
perror (sTemp);
|
perror (sTemp);
|
close (sockfd);
|
close (sockfd);
|
return 0;
|
return 0;
|
}
|
}
|
serverIP = sa.sin_addr.s_addr;
|
serverIP = sa.sin_addr.s_addr;
|
len = sizeof (struct sockaddr_in);
|
len = sizeof (struct sockaddr_in);
|
if (getsockname (sockfd, (struct sockaddr *) &sa, &len) < 0)
|
if (getsockname (sockfd, (struct sockaddr *) &sa, &len) < 0)
|
{
|
{
|
sprintf (sTemp, "Unable to get socket information for socket %d",
|
sprintf (sTemp, "Unable to get socket information for socket %d",
|
sockfd);
|
sockfd);
|
perror (sTemp);
|
perror (sTemp);
|
close (sockfd);
|
close (sockfd);
|
return 0;
|
return 0;
|
}
|
}
|
runtime.vapi.server_port = ntohs (sa.sin_port);
|
runtime.vapi.server_port = ntohs (sa.sin_port);
|
|
|
/* Set the backlog to 1 connections */
|
/* Set the backlog to 1 connections */
|
if (listen (sockfd, 1) < 0)
|
if (listen (sockfd, 1) < 0)
|
{
|
{
|
sprintf (sTemp, "Unable to set backlog on socket %d to %d", sockfd, 1);
|
sprintf (sTemp, "Unable to set backlog on socket %d to %d", sockfd, 1);
|
perror (sTemp);
|
perror (sTemp);
|
close (sockfd);
|
close (sockfd);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
return sockfd;
|
return sockfd;
|
}
|
}
|
|
|
static void
|
static void
|
server_request ()
|
server_request ()
|
{
|
{
|
struct sockaddr_in sa;
|
struct sockaddr_in sa;
|
struct sockaddr *addr = (struct sockaddr *) &sa;
|
struct sockaddr *addr = (struct sockaddr *) &sa;
|
socklen_t len = sizeof (struct sockaddr_in);
|
socklen_t len = sizeof (struct sockaddr_in);
|
int fd = accept (server_fd, addr, &len);
|
int fd = accept (server_fd, addr, &len);
|
int on_off = 0; /* Turn off Nagel's algorithm on the socket */
|
int on_off = 0; /* Turn off Nagel's algorithm on the socket */
|
int flags;
|
int flags;
|
char sTemp[256];
|
char sTemp[256];
|
|
|
if (fd < 0)
|
if (fd < 0)
|
{
|
{
|
/* This is valid, because a connection could have started,
|
/* This is valid, because a connection could have started,
|
and then terminated due to a protocol error or user
|
and then terminated due to a protocol error or user
|
initiation before the accept could take place. */
|
initiation before the accept could take place. */
|
if (errno != EWOULDBLOCK && errno != EAGAIN)
|
if (errno != EWOULDBLOCK && errno != EAGAIN)
|
{
|
{
|
perror ("accept");
|
perror ("accept");
|
close (server_fd);
|
close (server_fd);
|
server_fd = 0;
|
server_fd = 0;
|
runtime.vapi.enabled = 0;
|
runtime.vapi.enabled = 0;
|
serverIP = 0;
|
serverIP = 0;
|
}
|
}
|
return;
|
return;
|
}
|
}
|
|
|
if (fcntl (fd, F_GETFL, &flags) < 0)
|
if (fcntl (fd, F_GETFL, &flags) < 0)
|
{
|
{
|
sprintf (sTemp, "Unable to get flags for vapi socket %d", fd);
|
sprintf (sTemp, "Unable to get flags for vapi socket %d", fd);
|
perror (sTemp);
|
perror (sTemp);
|
close (fd);
|
close (fd);
|
return;
|
return;
|
}
|
}
|
|
|
if (fcntl (fd, F_SETFL, flags | O_NONBLOCK) < 0)
|
if (fcntl (fd, F_SETFL, flags | O_NONBLOCK) < 0)
|
{
|
{
|
sprintf (sTemp,
|
sprintf (sTemp,
|
"Unable to set flags for vapi socket %d to value 0x%08x", fd,
|
"Unable to set flags for vapi socket %d to value 0x%08x", fd,
|
flags | O_NONBLOCK);
|
flags | O_NONBLOCK);
|
perror (sTemp);
|
perror (sTemp);
|
close (fd);
|
close (fd);
|
return;
|
return;
|
}
|
}
|
|
|
if (setsockopt (fd, tcp_level, TCP_NODELAY, &on_off, sizeof (int)) < 0)
|
if (setsockopt (fd, tcp_level, TCP_NODELAY, &on_off, sizeof (int)) < 0)
|
{
|
{
|
sprintf (sTemp,
|
sprintf (sTemp,
|
"Unable to disable Nagel's algorithm for socket %d.\nsetsockopt",
|
"Unable to disable Nagel's algorithm for socket %d.\nsetsockopt",
|
fd);
|
fd);
|
perror (sTemp);
|
perror (sTemp);
|
close (fd);
|
close (fd);
|
return;
|
return;
|
}
|
}
|
|
|
/* Install new handler */
|
/* Install new handler */
|
{
|
{
|
unsigned long id;
|
unsigned long id;
|
struct vapi_handler *t;
|
struct vapi_handler *t;
|
if (vapi_read_stream (fd, &id, sizeof (id)))
|
if (vapi_read_stream (fd, &id, sizeof (id)))
|
{
|
{
|
perror ("Cannot get id");
|
perror ("Cannot get id");
|
close (fd);
|
close (fd);
|
return;
|
return;
|
}
|
}
|
t = find_handler (id);
|
t = find_handler (id);
|
if (t)
|
if (t)
|
{
|
{
|
if (t->fd)
|
if (t->fd)
|
{
|
{
|
fprintf (stderr,
|
fprintf (stderr,
|
"WARNING: Test with id %lx already connected. Ignoring.\n",
|
"WARNING: Test with id %lx already connected. Ignoring.\n",
|
id);
|
id);
|
close (fd);
|
close (fd);
|
return;
|
return;
|
}
|
}
|
else
|
else
|
{
|
{
|
t->fd = fd;
|
t->fd = fd;
|
rebuild_fds ();
|
rebuild_fds ();
|
}
|
}
|
}
|
}
|
else
|
else
|
{
|
{
|
fprintf (stderr,
|
fprintf (stderr,
|
"WARNING: Test with id %lx not registered. Ignoring.\n", id);
|
"WARNING: Test with id %lx not registered. Ignoring.\n", id);
|
close (fd); /* kill the connection */
|
close (fd); /* kill the connection */
|
return;
|
return;
|
}
|
}
|
if (config.sim.verbose)
|
if (config.sim.verbose)
|
PRINTF ("\nConnection with test (id %lx) established.\n", id);
|
PRINTF ("\nConnection with test (id %lx) established.\n", id);
|
}
|
}
|
}
|
}
|
|
|
static int
|
static int
|
write_packet (unsigned long id, unsigned long data)
|
write_packet (unsigned long id, unsigned long data)
|
{
|
{
|
struct vapi_handler *t = find_handler (id);
|
struct vapi_handler *t = find_handler (id);
|
if (!t || !t->fd)
|
if (!t || !t->fd)
|
return 1;
|
return 1;
|
id = htonl (id);
|
id = htonl (id);
|
if (vapi_write_stream (t->fd, &id, sizeof (id)) < 0)
|
if (vapi_write_stream (t->fd, &id, sizeof (id)) < 0)
|
return 1;
|
return 1;
|
data = htonl (data);
|
data = htonl (data);
|
if (vapi_write_stream (t->fd, &data, sizeof (data)) < 0)
|
if (vapi_write_stream (t->fd, &data, sizeof (data)) < 0)
|
return 1;
|
return 1;
|
return 0;
|
return 0;
|
}
|
}
|
|
|
static int
|
static int
|
read_packet (int fd, unsigned long *id, unsigned long *data)
|
read_packet (int fd, unsigned long *id, unsigned long *data)
|
{
|
{
|
if (fd <= 0)
|
if (fd <= 0)
|
return 1;
|
return 1;
|
if (vapi_read_stream (fd, id, sizeof (unsigned long)) < 0)
|
if (vapi_read_stream (fd, id, sizeof (unsigned long)) < 0)
|
return 1;
|
return 1;
|
*id = ntohl (*id);
|
*id = ntohl (*id);
|
if (vapi_read_stream (fd, data, sizeof (unsigned long)) < 0)
|
if (vapi_read_stream (fd, data, sizeof (unsigned long)) < 0)
|
return 1;
|
return 1;
|
*data = ntohl (*data);
|
*data = ntohl (*data);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
static void
|
static void
|
vapi_request (struct vapi_handler *t)
|
vapi_request (struct vapi_handler *t)
|
{
|
{
|
unsigned long id, data;
|
unsigned long id, data;
|
|
|
if (read_packet (t->fd, &id, &data))
|
if (read_packet (t->fd, &id, &data))
|
{
|
{
|
if (t->fd > 0)
|
if (t->fd > 0)
|
{
|
{
|
perror ("vapi read");
|
perror ("vapi read");
|
close (t->fd);
|
close (t->fd);
|
t->fd = 0;
|
t->fd = 0;
|
rebuild_fds ();
|
rebuild_fds ();
|
}
|
}
|
return;
|
return;
|
}
|
}
|
|
|
vapi_write_log_file (VAPI_COMMAND_REQUEST, id, data);
|
vapi_write_log_file (VAPI_COMMAND_REQUEST, id, data);
|
|
|
/* This packet may be for another handler */
|
/* This packet may be for another handler */
|
if (!handler_fits_id (t, id))
|
if (!handler_fits_id (t, id))
|
t = find_handler (id);
|
t = find_handler (id);
|
if (!t || !t->read_func)
|
if (!t || !t->read_func)
|
fprintf (stderr,
|
fprintf (stderr,
|
"WARNING: Received packet for undefined id %08lx, data %08lx\n",
|
"WARNING: Received packet for undefined id %08lx, data %08lx\n",
|
id, data);
|
id, data);
|
else
|
else
|
t->read_func (id, data, t->priv_dat);
|
t->read_func (id, data, t->priv_dat);
|
}
|
}
|
|
|
void
|
void
|
vapi_check ()
|
vapi_check ()
|
{
|
{
|
struct vapi_handler *t;
|
struct vapi_handler *t;
|
|
|
if (!server_fd || !fds)
|
if (!server_fd || !fds)
|
{
|
{
|
fprintf (stderr, "FATAL: Unable to maintain VAPI server.\n");
|
fprintf (stderr, "FATAL: Unable to maintain VAPI server.\n");
|
exit (1);
|
exit (1);
|
}
|
}
|
|
|
/* Handle everything in queue. */
|
/* Handle everything in queue. */
|
while (1)
|
while (1)
|
{
|
{
|
switch (poll (fds, nfds, 0))
|
switch (poll (fds, nfds, 0))
|
{
|
{
|
case -1:
|
case -1:
|
if (errno == EINTR)
|
if (errno == EINTR)
|
continue;
|
continue;
|
perror ("poll");
|
perror ("poll");
|
if (server_fd)
|
if (server_fd)
|
close (server_fd);
|
close (server_fd);
|
runtime.vapi.enabled = 0;
|
runtime.vapi.enabled = 0;
|
serverIP = 0;
|
serverIP = 0;
|
return;
|
return;
|
case 0: /* Nothing interesting going on */
|
case 0: /* Nothing interesting going on */
|
return;
|
return;
|
default:
|
default:
|
/* Handle the vapi ports first. */
|
/* Handle the vapi ports first. */
|
for (t = vapi_handler; t; t = t->next)
|
for (t = vapi_handler; t; t = t->next)
|
if (t->temp >= 0 && fds[t->temp].revents)
|
if (t->temp >= 0 && fds[t->temp].revents)
|
vapi_request (t);
|
vapi_request (t);
|
|
|
if (fds[0].revents)
|
if (fds[0].revents)
|
{
|
{
|
if (fds[0].revents & POLLIN)
|
if (fds[0].revents & POLLIN)
|
server_request ();
|
server_request ();
|
else
|
else
|
{ /* Error Occurred */
|
{ /* Error Occurred */
|
fprintf (stderr,
|
fprintf (stderr,
|
"Received flags 0x%08x on server. Shutting down.\n",
|
"Received flags 0x%08x on server. Shutting down.\n",
|
fds[0].revents);
|
fds[0].revents);
|
if (server_fd)
|
if (server_fd)
|
close (server_fd);
|
close (server_fd);
|
server_fd = 0;
|
server_fd = 0;
|
runtime.vapi.enabled = 0;
|
runtime.vapi.enabled = 0;
|
serverIP = 0;
|
serverIP = 0;
|
}
|
}
|
}
|
}
|
break;
|
break;
|
} /* End of switch statement */
|
} /* End of switch statement */
|
} /* End of while statement */
|
} /* End of while statement */
|
}
|
}
|
|
|
/* Inits the VAPI, according to sim-config */
|
/* Inits the VAPI, according to sim-config */
|
int
|
int
|
vapi_init ()
|
vapi_init ()
|
{
|
{
|
nhandlers = 0;
|
nhandlers = 0;
|
vapi_handler = NULL;
|
vapi_handler = NULL;
|
if (!runtime.vapi.enabled)
|
if (!runtime.vapi.enabled)
|
return 0; /* Nothing to do */
|
return 0; /* Nothing to do */
|
|
|
runtime.vapi.server_port = config.vapi.server_port;
|
runtime.vapi.server_port = config.vapi.server_port;
|
if (!runtime.vapi.server_port)
|
if (!runtime.vapi.server_port)
|
{
|
{
|
fprintf (stderr, "WARNING: server_port = 0, shutting down VAPI\n");
|
fprintf (stderr, "WARNING: server_port = 0, shutting down VAPI\n");
|
runtime.vapi.enabled = 0;
|
runtime.vapi.enabled = 0;
|
return 1;
|
return 1;
|
}
|
}
|
if ((server_fd =
|
if ((server_fd =
|
get_server_socket ("or1ksim", "tcp", runtime.vapi.server_port)))
|
get_server_socket ("or1ksim", "tcp", runtime.vapi.server_port)))
|
PRINTF ("VAPI Server started on port %d\n", runtime.vapi.server_port);
|
PRINTF ("VAPI Server started on port %d\n", runtime.vapi.server_port);
|
else
|
else
|
{
|
{
|
perror ("Connection");
|
perror ("Connection");
|
return 1;
|
return 1;
|
}
|
}
|
|
|
rebuild_fds ();
|
rebuild_fds ();
|
|
|
if ((runtime.vapi.vapi_file = fopen (config.vapi.vapi_fn, "wt+")) == NULL)
|
if ((runtime.vapi.vapi_file = fopen (config.vapi.vapi_fn, "wt+")) == NULL)
|
fprintf (stderr, "WARNING: cannot open VAPI log file\n");
|
fprintf (stderr, "WARNING: cannot open VAPI log file\n");
|
|
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Closes the VAPI */
|
/* Closes the VAPI */
|
void
|
void
|
vapi_done ()
|
vapi_done ()
|
{
|
{
|
int i;
|
int i;
|
struct vapi_handler *t = vapi_handler;
|
struct vapi_handler *t = vapi_handler;
|
|
|
for (i = 0; i < nfds; i++)
|
for (i = 0; i < nfds; i++)
|
if (fds[i].fd)
|
if (fds[i].fd)
|
close (fds[i].fd);
|
close (fds[i].fd);
|
server_fd = 0;
|
server_fd = 0;
|
runtime.vapi.enabled = 0;
|
runtime.vapi.enabled = 0;
|
serverIP = 0;
|
serverIP = 0;
|
free (fds);
|
free (fds);
|
fds = 0;
|
fds = 0;
|
if (runtime.vapi.vapi_file)
|
if (runtime.vapi.vapi_file)
|
{
|
{
|
/* Mark end of simulation */
|
/* Mark end of simulation */
|
vapi_write_log_file (VAPI_COMMAND_END, 0, 0);
|
vapi_write_log_file (VAPI_COMMAND_END, 0, 0);
|
fclose (runtime.vapi.vapi_file);
|
fclose (runtime.vapi.vapi_file);
|
}
|
}
|
|
|
while (vapi_handler)
|
while (vapi_handler)
|
{
|
{
|
t = vapi_handler;
|
t = vapi_handler;
|
vapi_handler = vapi_handler->next;
|
vapi_handler = vapi_handler->next;
|
free (t);
|
free (t);
|
}
|
}
|
}
|
}
|
|
|
/* Installs a vapi handler for one VAPI id */
|
/* Installs a vapi handler for one VAPI id */
|
void
|
void
|
vapi_install_handler (unsigned long id,
|
vapi_install_handler (unsigned long id,
|
void (*read_func) (unsigned long, unsigned long,
|
void (*read_func) (unsigned long, unsigned long,
|
void *), void *dat)
|
void *), void *dat)
|
{
|
{
|
vapi_install_multi_handler (id, 1, read_func, dat);
|
vapi_install_multi_handler (id, 1, read_func, dat);
|
}
|
}
|
|
|
/* Installs a vapi handler for many VAPI id */
|
/* Installs a vapi handler for many VAPI id */
|
void
|
void
|
vapi_install_multi_handler (unsigned long base_id, unsigned long num_ids,
|
vapi_install_multi_handler (unsigned long base_id, unsigned long num_ids,
|
void (*read_func) (unsigned long, unsigned long,
|
void (*read_func) (unsigned long, unsigned long,
|
void *), void *dat)
|
void *), void *dat)
|
{
|
{
|
struct vapi_handler *tt;
|
struct vapi_handler *tt;
|
|
|
if (read_func == NULL)
|
if (read_func == NULL)
|
{
|
{
|
struct vapi_handler **t = &vapi_handler;
|
struct vapi_handler **t = &vapi_handler;
|
while ((*t) && !handler_fits_id (*t, base_id))
|
while ((*t) && !handler_fits_id (*t, base_id))
|
t = &(*t)->next;
|
t = &(*t)->next;
|
if (!t)
|
if (!t)
|
{
|
{
|
fprintf (stderr, "Cannot uninstall VAPI read handler from id %lx\n",
|
fprintf (stderr, "Cannot uninstall VAPI read handler from id %lx\n",
|
base_id);
|
base_id);
|
exit (1);
|
exit (1);
|
}
|
}
|
tt = *t;
|
tt = *t;
|
(*t) = (*t)->next;
|
(*t) = (*t)->next;
|
free (tt);
|
free (tt);
|
nhandlers--;
|
nhandlers--;
|
}
|
}
|
else
|
else
|
{
|
{
|
tt = find_handler (base_id);
|
tt = find_handler (base_id);
|
if (!tt)
|
if (!tt)
|
{
|
{
|
tt = add_handler (base_id, num_ids);
|
tt = add_handler (base_id, num_ids);
|
tt->read_func = read_func;
|
tt->read_func = read_func;
|
tt->priv_dat = dat;
|
tt->priv_dat = dat;
|
}
|
}
|
else
|
else
|
{
|
{
|
tt->read_func = read_func;
|
tt->read_func = read_func;
|
tt->priv_dat = dat;
|
tt->priv_dat = dat;
|
rebuild_fds ();
|
rebuild_fds ();
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
/* Returns number of unconnected handles. */
|
/* Returns number of unconnected handles. */
|
int
|
int
|
vapi_num_unconnected (int printout)
|
vapi_num_unconnected (int printout)
|
{
|
{
|
struct vapi_handler *t = vapi_handler;
|
struct vapi_handler *t = vapi_handler;
|
int numu = 0;
|
int numu = 0;
|
for (; t; t = t->next)
|
for (; t; t = t->next)
|
{
|
{
|
if (!t->fd)
|
if (!t->fd)
|
{
|
{
|
numu++;
|
numu++;
|
if (printout)
|
if (printout)
|
{
|
{
|
if (t->num_ids == 1)
|
if (t->num_ids == 1)
|
PRINTF (" 0x%lx", t->base_id);
|
PRINTF (" 0x%lx", t->base_id);
|
else
|
else
|
PRINTF (" 0x%lx..0x%lx", t->base_id,
|
PRINTF (" 0x%lx..0x%lx", t->base_id,
|
t->base_id + t->num_ids - 1);
|
t->base_id + t->num_ids - 1);
|
}
|
}
|
}
|
}
|
}
|
}
|
return numu;
|
return numu;
|
}
|
}
|
|
|
/* Sends a packet to specified test */
|
/* Sends a packet to specified test */
|
void
|
void
|
vapi_send (unsigned long id, unsigned long data)
|
vapi_send (unsigned long id, unsigned long data)
|
{
|
{
|
vapi_write_log_file (VAPI_COMMAND_SEND, id, data);
|
vapi_write_log_file (VAPI_COMMAND_SEND, id, data);
|
write_packet (id, data);
|
write_packet (id, data);
|
}
|
}
|
|
|
/*
|
/*
|
int main ()
|
int main ()
|
{
|
{
|
runtime.vapi.enabled = 1;
|
runtime.vapi.enabled = 1;
|
config.vapi.server_port = 9999;
|
config.vapi.server_port = 9999;
|
vapi_init ();
|
vapi_init ();
|
while (1) {
|
while (1) {
|
vapi_check();
|
vapi_check();
|
usleep(1);
|
usleep(1);
|
}
|
}
|
vapi_done ();
|
vapi_done ();
|
}*/
|
}*/
|
|
|
/*---------------------------------------------------[ VAPI configuration ]---*/
|
/*---------------------------------------------------[ VAPI configuration ]---*/
|
|
|
static void
|
static void
|
vapi_enabled (union param_val val, void *dat)
|
vapi_enabled (union param_val val, void *dat)
|
{
|
{
|
config.vapi.enabled = val.int_val;
|
config.vapi.enabled = val.int_val;
|
}
|
}
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
/*!Set the VAPI server port
|
/*!Set the VAPI server port
|
|
|
Ensure the value chosen is valid
|
Ensure the value chosen is valid
|
|
|
@param[in] val The value to use
|
@param[in] val The value to use
|
@param[in] dat The config data structure (not used here) */
|
@param[in] dat The config data structure (not used here) */
|
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
static void
|
static void
|
vapi_server_port (union param_val val, void *dat)
|
vapi_server_port (union param_val val, void *dat)
|
{
|
{
|
if ((val.int_val < 1) || (val.int_val > 65535))
|
if ((val.int_val < 1) || (val.int_val > 65535))
|
{
|
{
|
fprintf (stderr, "Warning: invalid VAPI port specified: ignored\n");
|
fprintf (stderr, "Warning: invalid VAPI port specified: ignored\n");
|
}
|
}
|
else
|
else
|
{
|
{
|
config.vapi.server_port = val.int_val;
|
config.vapi.server_port = val.int_val;
|
}
|
}
|
} /* vapi_server_port() */
|
} /* vapi_server_port() */
|
|
|
|
|
static void
|
static void
|
vapi_log_enabled (union param_val val, void *dat)
|
vapi_log_enabled (union param_val val, void *dat)
|
{
|
{
|
config.vapi.log_enabled = val.int_val;
|
config.vapi.log_enabled = val.int_val;
|
}
|
}
|
|
|
static void
|
static void
|
vapi_hide_device_id (union param_val val, void *dat)
|
vapi_hide_device_id (union param_val val, void *dat)
|
{
|
{
|
config.vapi.hide_device_id = val.int_val;
|
config.vapi.hide_device_id = val.int_val;
|
}
|
}
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
/*!Set the log file
|
/*!Set the log file
|
|
|
Free any existing string.
|
Free any existing string.
|
|
|
@param[in] val The value to use
|
@param[in] val The value to use
|
@param[in] dat The config data structure (not used here) */
|
@param[in] dat The config data structure (not used here) */
|
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
static void
|
static void
|
vapi_log_fn (union param_val val,
|
vapi_log_fn (union param_val val,
|
void *dat)
|
void *dat)
|
{
|
{
|
if (NULL != config.vapi.vapi_fn)
|
if (NULL != config.vapi.vapi_fn)
|
{
|
{
|
free (config.vapi.vapi_fn);
|
free (config.vapi.vapi_fn);
|
}
|
}
|
|
|
config.vapi.vapi_fn = strdup (val.str_val);
|
config.vapi.vapi_fn = strdup (val.str_val);
|
|
|
} /* vapi_log_fn() */
|
} /* vapi_log_fn() */
|
|
|
|
|
void
|
void
|
reg_vapi_sec (void)
|
reg_vapi_sec (void)
|
{
|
{
|
struct config_section *sec = reg_config_sec ("VAPI", NULL, NULL);
|
struct config_section *sec = reg_config_sec ("VAPI", NULL, NULL);
|
|
|
reg_config_param (sec, "enabled", paramt_int, vapi_enabled);
|
reg_config_param (sec, "enabled", PARAMT_INT, vapi_enabled);
|
reg_config_param (sec, "server_port", paramt_int, vapi_server_port);
|
reg_config_param (sec, "server_port", PARAMT_INT, vapi_server_port);
|
reg_config_param (sec, "log_enabled", paramt_int, vapi_log_enabled);
|
reg_config_param (sec, "log_enabled", PARAMT_INT, vapi_log_enabled);
|
reg_config_param (sec, "hide_device_id", paramt_int, vapi_hide_device_id);
|
reg_config_param (sec, "hide_device_id", PARAMT_INT, vapi_hide_device_id);
|
reg_config_param (sec, "vapi_log_file", paramt_str, vapi_log_fn);
|
reg_config_param (sec, "vapi_log_file", PARAMT_STR, vapi_log_fn);
|
reg_config_param (sec, "vapi_log_fn", paramt_str, vapi_log_fn);
|
reg_config_param (sec, "vapi_log_fn", PARAMT_STR, vapi_log_fn);
|
}
|
}
|
|
|