Files
epics-base/modules/libcom/RTEMS/posix/rtems_init.c
Brendan Chandler 74fa27d316 Add commented code that starts an RTEMS shell, useful for debugging
In the future, it would be nice to add an ioc shell command to launch
into an RTEMS shell, but for now, it can be helpful when debugging to
enable this section for poking around in an RTEMS shell check network
configuration and stuff like that.
2021-02-22 16:18:00 -06:00

1176 lines
34 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
* Author: W. Eric Norum
* eric.norum@usask.ca
* (306) 966-5394
*/
/*
* This is the first implementation with posix and rtems5.
* Currently only dhcp is supported with libbsd. The reading of the
* environment variables from e.g. u-boot environment is still missing.
* Extensive tests so far only with qemu.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <rtems.h>
#include <rtems/malloc.h>
#include <rtems/error.h>
#include <rtems/stackchk.h>
#include <rtems/imfs.h>
#include <rtems/shell.h>
#include <pthread.h>
#include <signal.h>
#include <sched.h>
#include <rtems/libio.h>
#include <rtems/rtc.h>
#include <time.h>
#include <sys/unistd.h>
#if __RTEMS_MAJOR__ > 4
#include <rtems/tod.h>
#else
#include <rtems/score/tod.h>
#endif
#ifdef RTEMS_LEGACY_STACK
#include <rtems/rtems_bsdnet.h>
#include <librtemsNfs.h>
#else // libbsd stack
#include <rtems/bsd/bsd.h>
#include <rtems/bsd/modules.h>
#include <rtems/dhcpcd.h>
#include <machine/rtems-bsd-commands.h>
#endif
#include <rtems/telnetd.h>
#if __RTEMS_MAJOR__ > 4
#include <rtems/printer.h>
#endif
#include "epicsVersion.h"
#include "epicsThread.h"
#include "epicsTime.h"
#include "epicsExit.h"
#include "envDefs.h"
#include "errlog.h"
#include "logClient.h"
#include "osiUnistd.h"
#include "iocsh.h"
#include "osdTime.h"
#include "epicsMemFs.h"
#include "epicsEvent.h"
#include "errlog.h"
#include "epicsRtemsInitHooks.h"
#ifdef RTEMS_LEGACY_STACK
#pragma message "RTEMS uses legacy stack"
#else
#pragma message "RTEMS uses libbsd stack"
// setup own ntp-client to get time
#include "epicsNtp.h"
epicsEventId dhcpDone;
#endif
/* these settings are needed by the rtems startup
* may provide by dhcp/bootp
* or environments from the "BIOS" like u-boot, motboot etc.
*/
char rtemsInit_NTP_server_ip[16] = "10.0.5.1";
char bootp_server_name_init[128] = "1001.1001@10.0.5.1:/epics";
char bootp_boot_file_name_init[128] = "/epics/myExample/bin/RTEMS-beatnik/myExample.boot";
char bootp_cmdline_init[128] = "/epics/myExample/iocBoot/iocmyExample/st.cmd";
struct in_addr rtems_bsdnet_bootp_server_address;
/* TODO check rtems_bsdnet_bootp_cmdline */
#ifndef RTEMS_LEGACY_STACK
char *rtems_bsdnet_bootp_server_name = bootp_server_name_init;
char *rtems_bsdnet_bootp_boot_file_name = bootp_boot_file_name_init;
char *rtems_bsdnet_bootp_cmdline = bootp_cmdline_init;
#endif // not LEGACY Stack
/*
* Prototypes for some functions not in header files
*/
//void tzset(void);
int fileno(FILE *);
int main(int argc, char **argv);
static void
logReset (void)
{
void rtems_bsp_reset_cause(char *buf, size_t capacity) __attribute__((weak));
void (*fp)(char *buf, size_t capacity) = rtems_bsp_reset_cause;
if (fp) {
char buf[80];
fp(buf, sizeof buf);
errlogPrintf ("Startup after %s.\n", buf);
}
else {
errlogPrintf ("Startup.\n");
}
}
/*
***********************************************************************
* FATAL ERROR REPORTING *
***********************************************************************
*/
/*
* Delay for a while, then terminate
*/
static void
delayedPanic (const char *msg)
{
rtems_task_wake_after (rtems_clock_get_ticks_per_second());
rtems_task_wake_after (rtems_clock_get_ticks_per_second());
rtems_panic ("%s", 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", msg);
return p;
}
/*
***********************************************************************
* REMOTE FILE ACCESS *
***********************************************************************
*/
#ifdef OMIT_NFS_SUPPORT
# include <rtems/tftp.h>
#endif
const epicsMemFS *epicsRtemsFSImage __attribute__((weak));
const epicsMemFS *epicsRtemsFSImage = (void*)&epicsRtemsFSImage;
/* hook to allow app specific FS setup */
int
epicsRtemsMountLocalFilesystem(char **argv) __attribute__((weak));
int
epicsRtemsMountLocalFilesystem(char **argv)
{
if(epicsRtemsFSImage==(void*)&epicsRtemsFSImage)
return -1; /* no FS image provided. */
else if(epicsRtemsFSImage==NULL)
return 0; /* no FS image provided, but none is needed. */
else {
printf("***** Using compiled in file data *****\n");
if (epicsMemFsLoad(epicsRtemsFSImage) != 0) {
printf("Can't unpack tar filesystem\n");
return -1;
} else {
argv[1] = "/";
return 0;
}
}
}
static int
initialize_local_filesystem(char **argv)
{
extern char _DownloadLocation[] __attribute__((weak));
extern char _FlashBase[] __attribute__((weak));
extern char _FlashSize[] __attribute__((weak));
argv[0] = rtems_bsdnet_bootp_boot_file_name;
if (epicsRtemsMountLocalFilesystem(argv)==0) {
return 1; /* FS setup successful */
#ifdef RTEMS_LEGACY_STACK
} else if (_FlashSize && (_DownloadLocation || _FlashBase)) {
extern char _edata[];
size_t flashIndex = _edata - _DownloadLocation;
char *header = _FlashBase + flashIndex;
if (memcmp(header + 257, "ustar ", 8) == 0) {
int fd;
printf ("***** Unpack in-memory file system (IMFS) *****\n");
if (rtems_tarfs_load("/", (unsigned char *)header, (size_t)_FlashSize - flashIndex) != 0) {
printf("Can't unpack tar filesystem\n");
return 0;
}
if ((fd = open(rtems_bsdnet_bootp_cmdline, 0)) >= 0) {
close(fd);
printf ("***** Found startup script (%s) in IMFS *****\n", rtems_bsdnet_bootp_cmdline);
argv[1] = rtems_bsdnet_bootp_cmdline;
return 1;
}
printf ("***** Startup script (%s) not in IMFS *****\n", rtems_bsdnet_bootp_cmdline);
}
#endif /* only with old stack, check check libbsd dependency! */
}
return 0;
}
#ifndef OMIT_NFS_SUPPORT
int
nfsMount(char *uidhost, char *path, char *mntpoint)
{
int devl = strlen(uidhost) + strlen(path) + 2;
char *dev;
int rval = -1;
if ((dev = malloc(devl)) == NULL) {
fprintf(stderr,"nfsMount: out of memory\n");
return -1;
}
sprintf(dev, "%s:%s", uidhost, path);
printf("Mount %s on %s\n", dev, mntpoint);
rval = mount_and_make_target_path (
dev, mntpoint, RTEMS_FILESYSTEM_TYPE_NFS,
RTEMS_FILESYSTEM_READ_WRITE, NULL );
if(rval)
perror("mount failed");
free(dev);
return rval;
}
#define NFS_INIT
#endif
static void
initialize_remote_filesystem(char **argv, int hasLocalFilesystem)
{
#ifdef OMIT_NFS_SUPPORT
printf ("***** Initializing TFTP *****\n");
mount_and_make_target_path(NULL,
"/TFTP",
RTEMS_FILESYSTEM_TYPE_TFTPFS,
RTEMS_FILESYSTEM_READ_WRITE,
NULL);
if (!hasLocalFilesystem) {
char *path;
int pathsize = 200;
int l;
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_name;
char *server_path;
char *mount_point;
char *cp;
int l = 0;
printf ("***** Initializing NFS *****\n");
NFS_INIT
if (env_nfsServer && env_nfsPath && env_nfsMountPoint) {
server_name = env_nfsServer;
server_path = env_nfsPath;
mount_point = env_nfsMountPoint;
cp = mount_point;
while ((cp = strchr(cp+1, '/')) != NULL) {
*cp = '\0';
if ((mkdir (mount_point, 0755) != 0)
&& (errno != EEXIST))
LogFatal("Can't create directory \"%s\": %s.\n",
mount_point, strerror(errno));
*cp = '/';
}
argv[1] = rtems_bsdnet_bootp_cmdline;
}
else if (hasLocalFilesystem) {
return;
}
else {
/*
* 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;
server_name = rtems_bsdnet_bootp_server_name;
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;
/*
* Its probably common to embed the mount point in the server
* name so, when this is occurring, dont clobber the mount point
* by appending the first node from the command path. This allows
* the mount point to be a different path then the server's mount
* path.
*
* This allows for example a line similar to as follows the DHCP
* configuration file.
*
* server-name "159.233@192.168.0.123:/vol/vol0/bootRTEMS";
*/
if ( server_name ) {
const size_t allocSize = strlen ( server_name ) + 2;
char * const pServerName = mustMalloc( allocSize,
"NFS mount paths");
char * const pServerPath = mustMalloc ( allocSize,
"NFS mount paths");
const int scanfStatus = sscanf (
server_name,
"%[^:] : / %s",
pServerName,
pServerPath + 1u );
if ( scanfStatus == 2 ) {
pServerPath[0u]= '/';
server_name = pServerName;
// is this a general solution?
server_path = mount_point = pServerPath;
}
else {
free ( pServerName );
free ( pServerPath );
}
}
}
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;
}
}
errlogPrintf("nfsMount(\"%s\", \"%s\", \"%s\")\n",
server_name, server_path, mount_point);
nfsMount(server_name, server_path, mount_point);
#endif
}
static
char rtems_etc_hosts[] = "127.0.0.1 localhost\n";
/* If it doesn't already exist, create /etc/hosts with an entry for 'localhost' */
static
void fixup_hosts(void)
{
FILE *fp;
int ret;
struct stat STAT;
ret=stat("/etc/hosts", &STAT);
if(ret==0)
{
return; /* already exists, assume file */
} else if(errno!=ENOENT) {
perror("error: fixup_hosts stat /etc/hosts");
return;
}
ret = mkdir("/etc", 0775);
if(ret!=0 && errno!=EEXIST)
{
perror("error: fixup_hosts create /etc");
return;
}
if((fp=fopen("/etc/hosts", "w"))==NULL)
{
perror("error: fixup_hosts create /etc/hosts");
}
if(fwrite(rtems_etc_hosts, 1, sizeof(rtems_etc_hosts)-1, fp)!=sizeof(rtems_etc_hosts)-1)
{
perror("error: failed to write /etc/hosts");
}
fclose(fp);
}
/*
* 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 = 0;
cp = "/";
}
else {
l = cp - commandline;
cp = commandline;
}
directoryPath = mustMalloc(l + 2, "Command path directory ");
strncpy(directoryPath, cp, l);
directoryPath[l] = '/';
directoryPath[l+1] = '\0';
if (chdir (directoryPath) < 0)
LogFatal ("Can't set initial directory(%s): %s\n", directoryPath, strerror(errno));
else
errlogPrintf("chdir(\"%s\")\n", directoryPath);
free(directoryPath);
}
/*
***********************************************************************
* RTEMS/EPICS COMMANDS *
***********************************************************************
*/
static const iocshArg rtshellArg0 = { "cmd", iocshArgString};
static const iocshArg rtshellArg1 = { "args", iocshArgArgv};
static const iocshArg * rtshellArgs[2] = { &rtshellArg0, &rtshellArg1};
static const iocshFuncDef rtshellFuncDef = { "rt",2, rtshellArgs
#ifdef IOCSHFUNCDEF_HAS_USAGE
, "run rtems shell command"
#endif
};
static void rtshellCallFunc(const iocshArgBuf *args)
{
rtems_shell_cmd_t *cmd = rtems_shell_lookup_cmd(args[0].sval);
int ret;
if (!cmd) {
fprintf(stderr, "ERR: No such command\n");
} else {
fflush(stdout);
fflush(stderr);
ret = (*cmd->command)(args[1].aval.ac,args[1].aval.av);
fflush(stdout);
fflush(stderr);
if(ret)
fprintf(stderr, "ERR: %d\n",ret);
}
}
/*
* RTEMS status
*/
static void
rtems_netstat (unsigned int level)
{
#ifndef RTEMS_LEGACY_STACK
printf ("***** Sorry not implemented yet with the new network stack (bsdlib)\n");
#else
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 ();
}
#endif
}
static const iocshArg netStatArg0 = { "level",iocshArgInt};
static const iocshArg * const netStatArgs[1] = {&netStatArg0};
static const iocshFuncDef netStatFuncDef = {"netstat",1,netStatArgs
#ifdef IOCSHFUNCDEF_HAS_USAGE
, "show network status"
#endif
};
static void netStatCallFunc(const iocshArgBuf *args)
{
rtems_netstat(args[0].ival);
}
static const iocshFuncDef heapSpaceFuncDef = {"heapSpace",0,NULL
#ifdef IOCSHFUNCDEF_HAS_USAGE
, "show malloc statistic"
#endif
};
static void heapSpaceCallFunc(const iocshArgBuf *args)
{
#if __RTEMS_MAJOR__ > 4
Heap_Information_block info;
double x;
malloc_info (&info);
x = info.Stats.size - (unsigned long)
(info.Stats.lifetime_allocated - info.Stats.lifetime_freed);
if (x >= 1024*1024)
printf("Heap space: %.1f MB\n", x / (1024 * 1024));
else
printf("Heap space: %.1f kB\n", x / 1024);
#else
rtems_malloc_statistics_t s;
double x;
malloc_get_statistics(&s);
x = s.space_available - (unsigned long)(s.lifetime_allocated - s.lifetime_freed);
if (x >= 1024*1024)
printf("Heap space: %.1f MB\n", x / (1024 * 1024));
else
printf("Heap space: %.1f kB\n", x / 1024);
#endif // RTEMS < 5
}
#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
#ifdef IOCSHFUNCDEF_HAS_USAGE
, "mount nfs drive"
#endif
};
static void nfsMountCallFunc(const iocshArgBuf *args)
{
char *cp = args[2].sval;
while ((cp = strchr(cp+1, '/')) != NULL) {
*cp = '\0';
if ((mkdir (args[2].sval, 0755) != 0) && (errno != EEXIST)) {
printf("Can't create directory \"%s\": %s.\n",
args[2].sval, strerror(errno));
return;
}
*cp = '/';
}
nfsMount(args[0].sval, args[1].sval, args[2].sval);
}
#endif
void zoneset(const char *zone)
{
if(zone)
setenv("TZ", zone, 1);
else
unsetenv("TZ");
tzset();
}
static const iocshArg zonesetArg0 = {"zone string", iocshArgString};
static const iocshArg * const zonesetArgs[1] = {&zonesetArg0};
static const iocshFuncDef zonesetFuncDef = {"zoneset",1,zonesetArgs
#ifdef IOCSHFUNCDEF_HAS_USAGE
, "set timezone (obsolete?)"
#endif
};
static void zonesetCallFunc(const iocshArgBuf *args)
{
zoneset(args[0].sval);
}
/*
* Register RTEMS-specific commands
*/
static void iocshRegisterRTEMS (void)
{
iocshRegister(&netStatFuncDef, netStatCallFunc);
iocshRegister(&heapSpaceFuncDef, heapSpaceCallFunc);
#ifndef OMIT_NFS_SUPPORT
iocshRegister(&nfsMountFuncDef, nfsMountCallFunc);
#endif
iocshRegister(&zonesetFuncDef, &zonesetCallFunc);
iocshRegister(&rtshellFuncDef, &rtshellCallFunc);
#if __RTEMS_MAJOR__ > 4
rtems_shell_init_environment();
#endif
}
/*
* Set up the console serial line (no handshaking)
*/
static void
initConsole (void)
{
struct termios t;
printf("\n initConsole --- Info ---\n");
printf("stdin: fileno: %d, ttyname: %s\n", fileno(stdin), ttyname(fileno(stdin)));
printf("stdout: fileno: %d, ttyname: %s\n", fileno(stdout), ttyname(fileno(stdout)));
printf("stderr: fileno: %d, ttyname: %s\n", fileno(stderr), ttyname(fileno(stderr)));
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;
}
}
/*
* Hook to ensure that BSP cleanup code gets run on exit
*/
static void
exitHandler(void)
{
rtems_shutdown_executive(0);
}
#ifndef RTEMS_LEGACY_STACK
static char* getPrimaryNetworkInterface(void)
{
// lookup available network interfaces
char ifnamebuf[IF_NAMESIZE];
char *ifname;
// get primary network interface
ifname = if_indextoname(1, &ifnamebuf[0]);
if (ifname == NULL) return (NULL);
printf("\n***** Primary Network interface : %s *****\n", ifname);
return (ifname);
}
static void
dhcpcd_hook_handler(rtems_dhcpcd_hook *hook, char *const *env)
{
int bound = 0;
char iName[16];
char *name;
char *value;
char * env_position;
(void)hook;
char ifnamebuf[IF_NAMESIZE];
sprintf(ifnamebuf, "%s", getPrimaryNetworkInterface());
while (*env != NULL) {
name = strtok_r(*env,"=", &env_position);
value = strtok_r(NULL,"=", &env_position);
printf("all out ---> %s = %s\n", name, value);
if (!strcmp(name, "interface") &&
!strcmp(value, ifnamebuf)) {
snprintf(iName, sizeof(iName), "%s", value);
}
if (!strcmp(name, "if_up") && !strcmp(value, "true")) {
printf ("Interface %s is up\n", iName);
bound = true;
}
if (bound) {
// as there is no ntp-support in rtems-libbsd, we call our own client
if (!strcmp(name, "new_ntp_servers"))
snprintf(rtemsInit_NTP_server_ip,
sizeof(rtemsInit_NTP_server_ip),
"%s", value);
if (!strcmp(name, "new_host_name"))
sethostname (value, strlen (value));
if (!strcmp(name, "new_tftp_server_name")) {
snprintf(rtems_bsdnet_bootp_server_name,
sizeof(bootp_server_name_init),
"%s", value);
printf(" rtems_bsdnet_bootp_server_name : %s\n", rtems_bsdnet_bootp_server_name);
}
if(!strcmp(name, "new_bootfile_name")){
snprintf(rtems_bsdnet_bootp_boot_file_name,
sizeof(bootp_boot_file_name_init),
"%s", value);
printf(" rtems_bsdnet_bootp_boot_file_name : %s\n", rtems_bsdnet_bootp_boot_file_name);
}
if(!strcmp(name, "new_rtems_cmdline")){
snprintf(rtems_bsdnet_bootp_cmdline,
sizeof(bootp_cmdline_init),
"%s", value);
printf(" rtems_bsdnet_bootp_cmdline : %s\n", rtems_bsdnet_bootp_cmdline);
}
}
++env;
}
if (bound)
epicsEventSignal(dhcpDone);
}
static rtems_dhcpcd_hook dhcpcd_hook = {
.name = "ioc boot",
.handler = dhcpcd_hook_handler
};
static void
default_network_on_exit(int exit_code, void *arg)
{
rtems_printer printer;
(void)arg;
rtems_print_printer_printf(&printer);
rtems_stack_checker_report_usage_with_plugin(&printer);
}
static void
default_network_set_self_prio(rtems_task_priority prio)
{
rtems_status_code sc;
sc = rtems_task_set_priority(RTEMS_SELF, prio, &prio);
assert(sc == RTEMS_SUCCESSFUL);
}
static void
default_network_dhcpcd(void)
{
static const char default_cfg[] = "clientid FHI test client\n";
rtems_status_code sc;
int fd;
int rv;
ssize_t n;
fd = open("/etc/dhcpcd.conf", O_CREAT | O_WRONLY,
S_IRWXU | S_IRWXG | S_IRWXO);
assert(fd >= 0);
n = write(fd, default_cfg, sizeof(default_cfg) - 1);
assert(n == (ssize_t) sizeof(default_cfg) - 1);
static const char fhi_cfg[] =
"nodhcp6\n"
"ipv4only\n"
"option ntp_servers\n"
"option rtems_cmdline\n"
"option tftp_server_name\n"
"option bootfile_name\n"
"define 129 string rtems_cmdline\n"
"timeout 0";
n = write(fd, fhi_cfg, sizeof(fhi_cfg) - 1);
assert(n == (ssize_t) sizeof(fhi_cfg) - 1);
rv = close(fd);
assert(rv == 0);
sc = rtems_dhcpcd_start(NULL);
assert(sc == RTEMS_SUCCESSFUL);
}
#endif // not RTEMS_LEGACY_STACK
#if __RTEMS_MAJOR__>4
/*
***********************************************************************
* TELNET DAEMON *
***********************************************************************
*/
#define LINE_SIZE 256
static void
telnet_pseudoIocsh(char *name, __attribute__((unused))void *arg)
{
char line[LINE_SIZE];
int fid[3], save_fid[3];
printf("info: pty dev name = %s\n", name);
save_fid[1] = dup2(1,1);
fid[1] = dup2( fileno(stdout), 1);
if (fid[1] == -1 ) printf("Can't dup stdout\n");
save_fid[2] = dup2(2,2);
fid[2] = dup2( fileno(stderr), 2);
if (fid[2] == -1 ) printf("Can't dup stderr\n");
const char *prompt = "tIocSh> ";
while (1) {
fputs(prompt, stdout);
fflush(stdout);
/* telnet close not detected ??? tbd */
if (fgets(line, LINE_SIZE, stdin) == NULL) {
dup2(save_fid[1],1);
dup2(save_fid[2],2);
return;
}
if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = 0;
if (!strncmp( line, "bye",3)) {
printf( "%s", "Will end session\n");
dup2(save_fid[1],1);
dup2(save_fid[2],2);
return;
}
iocshCmd(line);
}
}
#define SHELL_ENTRY telnet_pseudoIocsh
/*
* Telnet daemon configuration
* 0 or NULL for most fields in thsi struct indicate default values to RTEMS.
*/
rtems_telnetd_config_table rtems_telnetd_config = {
.command = SHELL_ENTRY,
.arg = NULL,
.priority = 0,
.stack_size = 0,
.client_maximum = 0,
.login_check = NULL,
.keep_stdio = false
};
#endif
/*
* RTEMS Startup task
*/
void *
POSIX_Init ( void *argument __attribute__((unused)))
{
int result;
char *argv[3] = { NULL, NULL, NULL };
// char *cp;
rtems_status_code sc;
struct timespec now;
char timeBuff[100];
initConsole ();
/*
* Use BSP-supplied time of day if available otherwise supply default time.
* It is very likely that other time synchronization facilities in EPICS
* will soon override this value.
*/
/* check for RTC ... unfortunately seems to be missing with libbsd and qemu ?
if (checkRealtime() >= 0) {
setRealTimeToRTEMS();
} else
*/
{
// set time to 14.4.2014
now.tv_sec = 1397460606;
now.tv_nsec = 0;
sc = clock_settime(CLOCK_REALTIME, &now);
if (sc < 0)
printf ("***** Can't set time: %s\n", rtems_status_text (sc));
}
sc = clock_gettime( CLOCK_REALTIME, &now);
if ( sc < 0) {
printf ("***** Can't get time: %s\n", rtems_status_text (sc));
} else {
strftime(timeBuff, sizeof timeBuff, "%D %T", gmtime(&now.tv_sec));
printf("time set to : %s.%09ld UTC\n", timeBuff, now.tv_nsec);
}
/*
* Explain why we're here
*/
logReset();
/* TBD ...
* Architecture-specific hooks
*/
#ifdef RTEMS_LEGACY_STACK
if (epicsRtemsInitPreSetBootConfigFromNVRAM(&rtems_bsdnet_config) != 0)
delayedPanic("epicsRtemsInitPreSetBootConfigFromNVRAM");
if (rtems_bsdnet_config.bootp == NULL) {
extern void setBootConfigFromNVRAM(void);
setBootConfigFromNVRAM();
}
if (epicsRtemsInitPostSetBootConfigFromNVRAM(&rtems_bsdnet_config) != 0)
delayedPanic("epicsRtemsInitPostSetBootConfigFromNVRAM");
#endif
/*
* Override RTEMS Posix configuration, it gets started with posix prio 2
*/
epicsThreadSetPriority(epicsThreadGetIdSelf(), epicsThreadPriorityIocsh);
/*
* Create a reasonable environment
*/
putenv ("TERM=xterm");
putenv ("IOCSH_HISTSIZE=20");
/*
* Display some OS information
*/
printf("\n***** RTEMS Version: %s *****\n",
rtems_get_version_string());
#ifndef RTEMS_LEGACY_STACK
/*
* Start network (libbsd)
*
* start qemu like this
* qemu-system-i386 -m 64 -no-reboot -serial stdio -display none \
* -net nic,model=rtl8139,macaddr=0e:b0:ba:5e:ba:11 -net user,restrict=yes \
* -append "--video=off --console=/dev/com1" -kernel libComTestHarness
*/
printf("\n***** Initializing network (libbsd, dhcpcd) *****\n");
rtems_bsd_setlogpriority("debug");
on_exit(default_network_on_exit, NULL);
/* Let other tasks run to complete background work */
default_network_set_self_prio(RTEMS_MAXIMUM_PRIORITY - 1U);
/* supress all output from bsd network initialization */
rtems_bsd_set_vprintf_handler(rtems_bsd_vprintf_handler_mute);
sc = rtems_bsd_initialize();
assert(sc == RTEMS_SUCCESSFUL);
/* Let the callout timer allocate its resources */
sc = rtems_task_wake_after(2);
assert(sc == RTEMS_SUCCESSFUL);
printf("\n***** ifconfig lo0 *****\n");
rtems_bsd_ifconfig_lo0();
printf("\n***** add dhcpcd hook *****\n");
dhcpDone = epicsEventMustCreate(epicsEventEmpty);
rtems_dhcpcd_add_hook(&dhcpcd_hook);
printf("\n***** Start default network dhcpcd *****\n");
// if MY_BOOTP???
default_network_dhcpcd();
/* this seems to be hard coded in the BSP -> Sebastian Huber ? */
printf("\n--Info (hpj)-- bsd task prio IRQS: %d -----\n", rtems_bsd_get_task_priority("IRQS"));
printf("\n--Info (hpj)-- bsd task prio TIME: %d -----\n", rtems_bsd_get_task_priority("TIME"));
// wait for dhcp done ... should be if SYNCDHCP is used
epicsEventWaitStatus stat;
printf("\n ---- Waiting for DHCP ...\n");
stat = epicsEventWaitWithTimeout(dhcpDone, 600);
if (stat == epicsEventOK)
epicsEventDestroy(dhcpDone);
else if (stat == epicsEventWaitTimeout)
printf("\n ---- DHCP timed out!\n");
else
printf("\n ---- dhcpDone Event Unknown state %d\n", stat);
const char* ifconfg_args[] = {
"ifconfig", NULL
};
const char* netstat_args[] = {
"netstat", "-rn", NULL
};
printf("-------------- IFCONFIG -----------------\n");
rtems_bsd_command_ifconfig(1, (char**) ifconfg_args);
printf("-------------- NETSTAT ------------------\n");
rtems_bsd_command_netstat(2, (char**) netstat_args);
/* until now there is no NTP support in libbsd -> Sebastian Huber ... */
printf("\n***** Until now no NTP support in RTEMS 5 with rtems-libbsd *****\n");
printf("\n***** Ask ntp server once... *****\n");
if (epicsNtpGetTime(rtemsInit_NTP_server_ip, &now) < 0) {
printf ("***** Can't get time from ntp ...\n");
} else {
if (clock_settime(CLOCK_REALTIME, &now) < 0){
printf ("***** Can't set time: %s\n", rtems_status_text (sc));
} else {
strftime(timeBuff, sizeof timeBuff, "%D %T", gmtime(&now.tv_sec));
printf("time from ntp : %s.%09ld UTC\n", timeBuff, now.tv_nsec);
}
}
#else // Legacy stack, old network initialization
char *cp;
if ((cp = getenv("EPICS_TS_NTP_INET")) != NULL)
rtems_bsdnet_config.ntp_server[0] = cp;
int rtems_bsdnet_ntpserver_count = 1;
struct in_addr rtems_bsdnet_ntpserver[rtems_bsdnet_ntpserver_count];
memcpy(rtems_bsdnet_ntpserver, rtems_bsdnet_config.ntp_server, sizeof(struct in_addr));
if (rtems_bsdnet_config.network_task_priority == 0)
{
unsigned int p;
if (epicsThreadHighestPriorityLevelBelow(epicsThreadPriorityScanLow, &p)
== epicsThreadBooleanStatusSuccess)
{
rtems_bsdnet_config.network_task_priority = p;
}
}
printf("\n***** Initializing network (Legacy Stack) *****\n");
rtems_bsdnet_initialize_network();
printf("\n***** Network Status *****\n");
rtems_netstat(3);
rtems_bsdnet_synchronize_ntp (0, 0);
#endif // not RTEMS_LEGACY_STACK
/* show messages from network after initialization ? good idea? */
//rtems_bsd_set_vprintf_handler(bsd_vprintf_handler_old);
printf("\n***** Setting up file system *****\n");
//???initialize_remote_filesystem(argv, initialize_local_filesystem(argv));
fixup_hosts();
/*
* More environment: iocsh prompt and hostname
*/
{
char hostname[1024];
gethostname(hostname, 1023);
char *cp = mustMalloc(strlen(hostname)+3, "iocsh prompt");
sprintf(cp, "%s> ", hostname);
epicsEnvSet ("IOCSH_PS1", cp);
epicsEnvSet("IOC_NAME", hostname);
}
if (getenv("") == NULL) {
const char *tzp = envGetConfigParamPtr(&EPICS_TZ);
if (tzp == NULL) {
printf("Warning -- no timezone information available -- times will be displayed as GMT.\n");
}
}
tzset();
printf(" check for time registered , C++ initialization ...\n");
//osdTimeRegister();
/*/Volumes/Epics/myExample/bin/RTEMS-xilinx_zynq_a9_qemu
* Run the EPICS startup script
*/
#if __RTEMS_MAJOR__>4
// if telnetd is requested ...
// printf(" Will try to start telnetd with prio %d ...\n", rtems_telnetd_config.priority);
// result = rtems_telnetd_initialize();
// printf (" telnetd initialized with result %d\n", result);
#endif
printf ("***** Preparing EPICS application *****\n");
iocshRegisterRTEMS ();
set_directory (argv[1]);
epicsEnvSet ("IOC_STARTUP_SCRIPT", argv[1]);
atexit(exitHandler);
errlogFlush();
printf ("***** Starting EPICS application *****\n");
#if 0
// Start an rtems shell before main, for debugging RTEMS system issues
rtems_shell_init("SHLL", RTEMS_MINIMUM_STACK_SIZE * 4,
100, "/dev/console",
false, true,
NULL);
#endif
result = main ((sizeof argv / sizeof argv[0]) - 1, argv);
printf ("***** IOC application terminating *****\n");
epicsThreadSleep(1.0);
epicsExit(result);
#if defined(__rtems__)
delayedPanic("will reset rtems ... end of POSIX_Init");
#endif
exit(0);
}
#if defined(QEMU_FIXUPS)
/* Override some hooks (weak symbols)
* if BSP defaults aren't configured for running tests.
*/
/* Ensure that stdio goes to serial (so it can be captured) */
#if defined(__i386__) && !USE_COM1_AS_CONSOLE
#include <uart.h>
#if __RTEMS_MAJOR__ > 4
#include <libchip/serial.h>
#endif
extern int BSPPrintkPort;
void bsp_predriver_hook(void)
{
#if __RTEMS_MAJOR__ > 4
Console_Port_Minor = BSP_CONSOLE_PORT_COM1;
#else
BSPConsolePort = BSP_CONSOLE_PORT_COM1;
#endif
BSPPrintkPort = BSP_CONSOLE_PORT_COM1;
}
#endif
/* reboot immediately when done. */
#if defined(__i386__) && BSP_PRESS_KEY_FOR_RESET
void bsp_cleanup(void)
{
void bsp_reset();
bsp_reset();
}
#endif
#endif /* QEMU_FIXUPS */
int cexpdebug __attribute__((weak));