Files
epics-base/src/RTEMS/base/rtems_init.c
2004-10-18 21:39:16 +00:00

460 lines
12 KiB
C

/*************************************************************************\
* Copyright (c) 2002 The University of Saskatchewan
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* RTEMS startup task for EPICS
* $Id$
* Author: W. Eric Norum
* eric.norum@usask.ca
* (306) 966-5394
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <sys/termios.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <rtems.h>
#include <rtems/error.h>
#include <rtems/stackchk.h>
#include <rtems/rtems_bsdnet.h>
#include <epicsThread.h>
#include <errlog.h>
#include <logClient.h>
#include <osiUnistd.h>
#include <iocsh.h>
/*
* Architecture-dependent routines
*/
#ifdef __mcpu32__
#include <m68360.h>
static void
logReset (void)
{
int bit, rsr;
int i;
const char *cp;
char cbuf[80];
rsr = m360.rsr;
for (i = 0, bit = 0x80 ; bit != 0 ; bit >>= 1) {
if (rsr & bit) {
switch (bit) {
case 0x80: cp = "RESETH*"; break;
case 0x40: cp = "POWER-UP"; break;
case 0x20: cp = "WATCHDOG"; break;
case 0x10: cp = "DOUBLE FAULT"; break;
case 0x04: cp = "LOST CLOCK"; break;
case 0x02: cp = "RESET"; break;
case 0x01: cp = "RESETS*"; break;
default: cp = "??"; break;
}
i += sprintf (cbuf+i, cp);
rsr &= ~bit;
if (rsr)
i += sprintf (cbuf+i, ", ");
else
break;
}
}
errlogPrintf ("Startup after %s.\n", cbuf);
m360.rsr = ~0;
}
#else
static void
logReset (void)
{
errlogPrintf ("Started.\n");
}
#endif
#ifdef __i386__
/*
* Remote debugger support
*
* i386-rtems-gdb -b 38400 example(binary from EPICS build -- not netbootable image!)
* (gdb) target remote /dev/ttyS0
*/
int enableRemoteDebugging = 0; /* Global so gdb can set before download */
static void
initRemoteGdb(int ticksPerSecond)
{
if (enableRemoteDebugging) {
init_remote_gdb();
rtems_task_wake_after(ticksPerSecond);
breakpoint();
}
}
#endif
/*
***********************************************************************
* FATAL ERROR REPORTING *
***********************************************************************
*/
/*
* Delay for a while, then terminate
*/
static void
delayedPanic (const char *msg)
{
rtems_interval ticksPerSecond;
rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticksPerSecond);
rtems_task_wake_after (ticksPerSecond);
rtems_panic (msg);
}
/*
* Log error and terminate
*/
void
LogFatal (const char *msg, ...)
{
va_list ap;
va_start (ap, msg);
errlogVprintf (msg, ap);
va_end (ap);
delayedPanic (msg);
}
/*
* Log RTEMS error and terminate
*/
void
LogRtemsFatal (const char *msg, rtems_status_code sc)
{
errlogPrintf ("%s: %s\n", msg, rtems_status_text (sc));
delayedPanic (msg);
}
/*
* Log network error and terminate
*/
void
LogNetFatal (const char *msg, int err)
{
errlogPrintf ("%s: %d\n", msg, err);
delayedPanic (msg);
}
void *
mustMalloc(int size, const char *msg)
{
void *p;
if ((p = malloc (size)) == NULL)
LogFatal ("Can't allocate space for %s.\n");
return p;
}
/*
***********************************************************************
* REMOTE FILE ACCESS *
***********************************************************************
*/
#ifdef OMIT_NFS_SUPPORT
# include <rtems/tftp.h>
#endif
static void
initialize_remote_filesystem(const char **argv)
{
#ifdef OMIT_NFS_SUPPORT
char *path;
int pathsize = 200;
int l;
printf ("***** Initializing TFTP *****\n");
rtems_bsdnet_initialize_tftp_filesystem ();
path = mustMalloc(pathsize, "Command path name ");
strcpy (path, "/TFTP/BOOTP_HOST/epics/");
l = strlen (path);
if (gethostname (&path[l], pathsize - l - 10) || (path[l] == '\0'))
LogFatal ("Can't get host name");
strcat (path, "/st.cmd");
argv[1] = path;
#else
char *server_path;
char *mount_point;
char *cp;
int l = 0;
printf ("***** Initializing NFS *****\n");
rpcUdpInit();
nfsInit(0,0);
/*
* Use first component of nvram/bootp command line pathname
* to set up initial NFS mount. A "/tftpboot/" is prepended
* if the pathname does not begin with a '/'. This allows
* NFS and TFTP to have a similar view of the remote system.
*/
if (rtems_bsdnet_bootp_cmdline[0] == '/')
cp = rtems_bsdnet_bootp_cmdline + 1;
else
cp = rtems_bsdnet_bootp_cmdline;
cp = strchr(cp, '/');
if ((cp == NULL)
|| ((l = cp - rtems_bsdnet_bootp_cmdline) == 0))
LogFatal("\"%s\" is not a valid command pathname.\n", rtems_bsdnet_bootp_cmdline);
cp = mustMalloc(l + 20, "NFS mount paths");
server_path = cp;
if (rtems_bsdnet_bootp_cmdline[0] == '/') {
mount_point = server_path;
strncpy(mount_point, rtems_bsdnet_bootp_cmdline, l);
mount_point[l] = '\0';
argv[1] = rtems_bsdnet_bootp_cmdline;
}
else {
char *abspath = mustMalloc(strlen(rtems_bsdnet_bootp_cmdline)+2,"Absolute command path");
strcpy(server_path, "/tftpboot/");
mount_point = server_path + strlen(server_path);
strncpy(mount_point, rtems_bsdnet_bootp_cmdline, l);
mount_point[l] = '\0';
mount_point--;
strcpy(abspath, "/");
strcat(abspath, rtems_bsdnet_bootp_cmdline);
argv[1] = abspath;
}
nfsMount(rtems_bsdnet_bootp_server_name, server_path, mount_point);
free(cp);
#endif
argv[0] = rtems_bsdnet_bootp_boot_file_name;
}
/*
* Get to the startup script directory
* The TFTP filesystem requires a trailing '/' on chdir arguments.
*/
static void
set_directory (const char *commandline)
{
const char *cp;
char *directoryPath;
int l;
cp = strrchr(commandline, '/');
if (cp == NULL)
l = strlen(commandline);
else
l = cp - commandline;
directoryPath = mustMalloc(l + 2, "Command path directory ");
strncpy(directoryPath, commandline, l);
directoryPath[l] = '/';
directoryPath[l+1] = '\0';
if (chdir (directoryPath) < 0)
LogFatal ("Can't set initial directory: %s\n", strerror(errno));
free(directoryPath);
}
/*
***********************************************************************
* RTEMS/EPICS COMMANDS *
***********************************************************************
*/
/*
* RTEMS status
*/
static void
rtems_netstat (unsigned int level)
{
rtems_bsdnet_show_if_stats ();
rtems_bsdnet_show_mbuf_stats ();
if (level >= 1) {
rtems_bsdnet_show_inet_routes ();
}
if (level >= 2) {
rtems_bsdnet_show_ip_stats ();
rtems_bsdnet_show_icmp_stats ();
rtems_bsdnet_show_udp_stats ();
rtems_bsdnet_show_tcp_stats ();
}
}
static const iocshArg netStatArg0 = { "level",iocshArgInt};
static const iocshArg * const netStatArgs[1] = {&netStatArg0};
static const iocshFuncDef netStatFuncDef = {"netstat",1,netStatArgs};
static void netStatCallFunc(const iocshArgBuf *args)
{
rtems_netstat(args[0].ival);
}
static const iocshFuncDef stackCheckFuncDef = {"stackCheck",0,NULL};
static void stackCheckCallFunc(const iocshArgBuf *args)
{
Stack_check_Dump_usage ();
}
#ifndef OMIT_NFS_SUPPORT
static const iocshArg nfsMountArg0 = { "[uid.gid@]host",iocshArgString};
static const iocshArg nfsMountArg1 = { "server path",iocshArgString};
static const iocshArg nfsMountArg2 = { "mount point",iocshArgString};
static const iocshArg * const nfsMountArgs[3] = {&nfsMountArg0,&nfsMountArg1,
&nfsMountArg2};
static const iocshFuncDef nfsMountFuncDef = {"nfsMount",3,nfsMountArgs};
static void nfsMountCallFunc(const iocshArgBuf *args)
{
nfsMount(args[0].sval, args[1].sval, args[2].sval);
}
#endif
/*
* Register RTEMS-specific commands
*/
static void iocshRegisterRTEMS (void)
{
iocshRegister(&netStatFuncDef, netStatCallFunc);
iocshRegister(&stackCheckFuncDef, stackCheckCallFunc);
#ifndef OMIT_NFS_SUPPORT
iocshRegister(&nfsMountFuncDef, nfsMountCallFunc);
#endif
}
/*
* Set up the console serial line (no handshaking)
*/
static void
initConsole (void)
{
struct termios t;
if (tcgetattr (fileno (stdin), &t) < 0) {
printf ("tcgetattr failed: %s\n", strerror (errno));
return;
}
t.c_iflag &= ~(IXOFF | IXON | IXANY);
if (tcsetattr (fileno (stdin), TCSANOW, &t) < 0) {
printf ("tcsetattr failed: %s\n", strerror (errno));
return;
}
}
/*
* Ensure that the configuration object files
* get pulled in from the library
*/
extern rtems_configuration_table Configuration;
extern struct rtems_bsdnet_config rtems_bsdnet_config;
const void *rtemsConfigArray[] = {
&Configuration,
&rtems_bsdnet_config
};
/*
* RTEMS Startup task
*/
rtems_task
Init (rtems_task_argument ignored)
{
int i;
const char *argv[3] = { NULL, NULL, NULL };
rtems_interval ticksPerSecond;
rtems_task_priority newpri;
rtems_status_code sc;
rtems_time_of_day now;
/*
* Get configuration
*/
rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticksPerSecond);
/*
* Architecture-specific hooks
*/
#if defined(__i386__)
initRemoteGdb(ticksPerSecond);
#endif
#if defined(HAVE_PPCBUG)
{
extern void setBootConfigFromPPCBUGNVRAM(void);
setBootConfigFromPPCBUGNVRAM();
}
#endif
#if defined(HAVE_MOTLOAD)
{
extern void setBootConfigFromMOTLOADNVRAM(void);
setBootConfigFromMOTLOADNVRAM();
}
#endif
/*
* Override RTEMS configuration
*/
rtems_task_set_priority (
RTEMS_SELF,
epicsThreadGetOssPriorityValue(epicsThreadPriorityIocsh),
&newpri);
/*
* Create a reasonable environment
*/
initConsole ();
putenv ("TERM=xterm");
putenv ("IOCSH_PS1=epics> ");
putenv ("IOCSH_HISTSIZE=20");
/*
* Start network
*/
if (rtems_bsdnet_config.network_task_priority == 0) {
unsigned int p;
if (epicsThreadHighestPriorityLevelBelow(epicsThreadPriorityScanLow, &p)
== epicsThreadBooleanStatusSuccess)
rtems_bsdnet_config.network_task_priority = epicsThreadGetOssPriorityValue(p);
}
printf ("***** Initializing network *****\n");
rtems_bsdnet_initialize_network ();
initialize_remote_filesystem (argv);
/*
* Use BSP-supplied time of day if available
*/
if (rtems_clock_get(RTEMS_CLOCK_GET_TOD,&now) != RTEMS_SUCCESSFUL) {
for (i = 0 ; ; i++) {
printf ("***** Initializing NTP *****\n");
if (rtems_bsdnet_synchronize_ntp (0, 0) >= 0)
break;
rtems_task_wake_after (5*ticksPerSecond);
if (i >= 12) {
printf (" *************** WARNING ***************\n");
printf (" ***** NO RESPONSE FROM NTP SERVER *****\n");
printf (" ***** TIME SET TO DEFAULT VALUE *****\n");
printf (" ***************************************\n");
now.year = 2001;
now.month = 1;
now.day = 1;
now.hour = 0;
now.minute = 0;
now.second = 0;
now.ticks = 0;
if ((sc = rtems_clock_set (&now)) != RTEMS_SUCCESSFUL)
printf ("***** Can't set time: %s\n", rtems_status_text (sc));
break;
}
}
}
/*
* Run the EPICS startup script
*/
printf ("***** Starting EPICS application *****\n");
iocshRegisterRTEMS ();
set_directory (argv[1]);
i = main ((sizeof argv / sizeof argv[0]) - 1, argv);
printf ("***** IOC application terminating *****\n");
exit (i);
}