diff --git a/.travis.yml b/.travis.yml
index 5079bff0c..9b092e0fd 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -11,8 +11,8 @@ env:
- CMPLR=clang STATIC=YES
- WINE=32 TEST=NO STATIC=YES
- WINE=32 TEST=NO STATIC=NO
- - RTEMS=4.10 TEST=NO
- - RTEMS=4.9 TEST=NO
+ - RTEMS=4.10 TEST=YES
+ - RTEMS=4.9 TEST=YES
addons:
apt:
packages:
@@ -25,8 +25,8 @@ addons:
- flex
- texinfo
- install-info
+ - qemu-system-x86
cache:
directories:
- $HOME/.cache
-install: sh ci/travis-prepare.sh > configure/os/CONFIG_SITE.Common.RTEMS
RTEMS_VERSION=$RTEMS
-RTEMS_BASE=/home/travis/.cache/rtems${RTEMS}-i386
+RTEMS_BASE=/home/travis/.rtems
EOF
cat << EOF >> configure/CONFIG_SITE
-CROSS_COMPILER_TARGET_ARCHS+=RTEMS-pc386
+CROSS_COMPILER_TARGET_ARCHS += RTEMS-pc386-qemu
+CROSS_COMPILER_RUNTEST_ARCHS += RTEMS-pc386-qemu
EOF
# find local qemu-system-i386
- export PATH="$HOME/.cache/qemu/usr/bin:$PATH"
echo -n "Using QEMU: "
type qemu-system-i386 || echo "Missing qemu"
- EXTRA=RTEMS_QEMU_FIXUPS=YES
fi
make -j2 $EXTRA
diff --git a/ci/travis-prepare.sh b/ci/travis-prepare.sh
deleted file mode 100644
index fd8c6fb4b..000000000
--- a/ci/travis-prepare.sh
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/bin/sh
-set -e -x
-
-die() {
- echo "$1" >&2
- exit 1
-}
-
-CURDIR="$PWD"
-
-QDIR="$HOME/.cache/qemu"
-
-if [ -n "$RTEMS" -a "$TEST" = "YES" ]
-then
- git clone --quiet --branch vme --depth 10 https://github.com/mdavidsaver/qemu.git "$HOME/.build/qemu"
- cd "$HOME/.build/qemu"
-
- HEAD=`git log -n1 --pretty=format:%H`
- echo "HEAD revision $HEAD"
-
- [ -e "$HOME/.cache/qemu/built" ] && BUILT=`cat "$HOME/.cache/qemu/built"`
- echo "Cached revision $BUILT"
-
- if [ "$HEAD" != "$BUILT" ]
- then
- echo "Building QEMU"
- git submodule --quiet update --init
-
- install -d "$HOME/.build/qemu/build"
- cd "$HOME/.build/qemu/build"
-
- "$HOME/.build/qemu/configure" --prefix="$HOME/.cache/qemu/usr" --target-list=i386-softmmu --disable-werror
- make -j2
- make install
-
- echo "$HEAD" > "$HOME/.cache/qemu/built"
- fi
-fi
-
-cd "$CURDIR"
diff --git a/configure/RULES_BUILD b/configure/RULES_BUILD
index 4f0d0a465..9aff11c8c 100644
--- a/configure/RULES_BUILD
+++ b/configure/RULES_BUILD
@@ -385,7 +385,7 @@ endif
# Generate a perl program to exec the real test binary.
%.t: %$(EXE) $(TOOLS)/makeTestfile.pl
@$(RM) $@
- $(PERL) $(TOOLS)/makeTestfile.pl $@ $<
+ $(PERL) $(TOOLS)/makeTestfile.pl $(T_A) $(EPICS_HOST_ARCH) $@ $<
#---------------------------------------------------------------
# Generate header with version number from VCS
diff --git a/configure/os/CONFIG.Common.RTEMS b/configure/os/CONFIG.Common.RTEMS
index c22e37a66..214ba794d 100644
--- a/configure/os/CONFIG.Common.RTEMS
+++ b/configure/os/CONFIG.Common.RTEMS
@@ -27,9 +27,13 @@ ifneq ($(CONFIG),$(TOP)/configure)
-include $(TOP)/configure/CONFIG_SITE.Common.RTEMS
endif
+#--------------------------------------------------
+# Set RTEMS_BSP from T_A if not already done
+RTEMS_BSP ?= $(subst RTEMS-,,$(T_A))
+
#-------------------------------------------------------
# Pick up the RTEMS tool/path definitions from the RTEMS BSP directory.
-include $(RTEMS_BASE)/$(RTEMS_TARGET_CPU)-rtems$(RTEMS_VERSION)/$(subst RTEMS-,,$(T_A))/Makefile.inc
+include $(RTEMS_BASE)/$(RTEMS_TARGET_CPU)-rtems$(RTEMS_VERSION)/$(RTEMS_BSP)/Makefile.inc
include $(RTEMS_CUSTOM)
include $(CONFIG.CC)
diff --git a/configure/os/CONFIG.Common.RTEMS-at91rm9200ek b/configure/os/CONFIG.Common.RTEMS-at91rm9200ek
index 6f5f97732..735c07bb5 100644
--- a/configure/os/CONFIG.Common.RTEMS-at91rm9200ek
+++ b/configure/os/CONFIG.Common.RTEMS-at91rm9200ek
@@ -9,5 +9,6 @@
#
# All RTEMS targets use the same Makefile fragment
#
-RTEMS_TARGET_CPU=arm
+RTEMS_BSP = at91rm9200ek
+RTEMS_TARGET_CPU = arm
include $(CONFIG)/os/CONFIG.Common.RTEMS
diff --git a/configure/os/CONFIG.Common.RTEMS-beatnik b/configure/os/CONFIG.Common.RTEMS-beatnik
index aaf611638..aaa45e4c9 100644
--- a/configure/os/CONFIG.Common.RTEMS-beatnik
+++ b/configure/os/CONFIG.Common.RTEMS-beatnik
@@ -5,6 +5,7 @@
# All RTEMS targets use the same Makefile fragment
#
EXE = .elf
+RTEMS_BSP = beatnik
RTEMS_TARGET_CPU = powerpc
GNU_TARGET = powerpc-rtems
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL
diff --git a/configure/os/CONFIG.Common.RTEMS-gen68360 b/configure/os/CONFIG.Common.RTEMS-gen68360
index a6663afc2..0a8a6e85e 100644
--- a/configure/os/CONFIG.Common.RTEMS-gen68360
+++ b/configure/os/CONFIG.Common.RTEMS-gen68360
@@ -5,5 +5,6 @@
#
# All RTEMS targets use the same Makefile fragment
#
-RTEMS_TARGET_CPU=m68k
+RTEMS_BSP = gen68360
+RTEMS_TARGET_CPU = m68k
include $(CONFIG)/os/CONFIG.Common.RTEMS
diff --git a/configure/os/CONFIG.Common.RTEMS-mcp750 b/configure/os/CONFIG.Common.RTEMS-mcp750
index d834ad9ec..035e6eb36 100644
--- a/configure/os/CONFIG.Common.RTEMS-mcp750
+++ b/configure/os/CONFIG.Common.RTEMS-mcp750
@@ -5,5 +5,6 @@
#
# All RTEMS targets use the same Makefile fragment
#
-RTEMS_TARGET_CPU=ppc
+RTEMS_BSP = mcp750
+RTEMS_TARGET_CPU = ppc
include $(CONFIG)/os/CONFIG.Common.RTEMS
diff --git a/configure/os/CONFIG.Common.RTEMS-mvme167 b/configure/os/CONFIG.Common.RTEMS-mvme167
index a6663afc2..3651f966f 100644
--- a/configure/os/CONFIG.Common.RTEMS-mvme167
+++ b/configure/os/CONFIG.Common.RTEMS-mvme167
@@ -5,5 +5,6 @@
#
# All RTEMS targets use the same Makefile fragment
#
-RTEMS_TARGET_CPU=m68k
+RTEMS_BSP = mvme167
+RTEMS_TARGET_CPU = m68k
include $(CONFIG)/os/CONFIG.Common.RTEMS
diff --git a/configure/os/CONFIG.Common.RTEMS-mvme2100 b/configure/os/CONFIG.Common.RTEMS-mvme2100
index 0ae64c791..a8e8bf76e 100644
--- a/configure/os/CONFIG.Common.RTEMS-mvme2100
+++ b/configure/os/CONFIG.Common.RTEMS-mvme2100
@@ -5,6 +5,7 @@
# All RTEMS targets use the same Makefile fragment
#
EXE = .elf
+RTEMS_BSP = mvme2100
RTEMS_TARGET_CPU = powerpc
GNU_TARGET = powerpc-rtems
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL
diff --git a/configure/os/CONFIG.Common.RTEMS-mvme2700 b/configure/os/CONFIG.Common.RTEMS-mvme2700
index 899fab17f..a5ad7fbf5 100644
--- a/configure/os/CONFIG.Common.RTEMS-mvme2700
+++ b/configure/os/CONFIG.Common.RTEMS-mvme2700
@@ -1,6 +1,7 @@
#
# Author: Matt Rippa
#
+RTEMS_BSP = mvme2700
RTEMS_TARGET_CPU = powerpc
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL
ARCH_DEP_CFLAGS += -DHAVE_PPCBUG
diff --git a/configure/os/CONFIG.Common.RTEMS-mvme3100 b/configure/os/CONFIG.Common.RTEMS-mvme3100
index e94d46211..283e7d680 100644
--- a/configure/os/CONFIG.Common.RTEMS-mvme3100
+++ b/configure/os/CONFIG.Common.RTEMS-mvme3100
@@ -5,6 +5,7 @@
# All RTEMS targets use the same Makefile fragment
#
EXE = .elf
+RTEMS_BSP = mvme3100
RTEMS_TARGET_CPU = powerpc
GNU_TARGET = powerpc-rtems
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL
diff --git a/configure/os/CONFIG.Common.RTEMS-mvme5500 b/configure/os/CONFIG.Common.RTEMS-mvme5500
index 44ef7ea3e..0329185bb 100644
--- a/configure/os/CONFIG.Common.RTEMS-mvme5500
+++ b/configure/os/CONFIG.Common.RTEMS-mvme5500
@@ -5,6 +5,7 @@
# All RTEMS targets use the same Makefile fragment
#
EXE = .elf
+RTEMS_BSP = mvme5500
RTEMS_TARGET_CPU = powerpc
GNU_TARGET = powerpc-rtems
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL
diff --git a/configure/os/CONFIG.Common.RTEMS-pc386 b/configure/os/CONFIG.Common.RTEMS-pc386
index 92ef4ac22..8dfa7d2ba 100644
--- a/configure/os/CONFIG.Common.RTEMS-pc386
+++ b/configure/os/CONFIG.Common.RTEMS-pc386
@@ -5,14 +5,15 @@
#
# All RTEMS targets use the same Makefile fragment
#
-RTEMS_TARGET_CPU=i386
+RTEMS_BSP = pc386
+RTEMS_TARGET_CPU = i386
MUNCH_SUFFIX = .boot
define MUNCH_CMD
- $(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary -R .comment -S $< temp.bin
+ $(RM) $*.bin
+ $(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary -R .comment -S $< $*.bin
$(BIN2BOOT) $@ 0x00097E00 \
- $(PROJECT_RELEASE)/lib/start16.bin 0x00097C00 0 temp.bin 0x00100000 0
- rm -f temp.bin
+ $(PROJECT_RELEASE)/lib/start16.bin 0x00097C00 0 $*.bin 0x00100000 0
endef
include $(CONFIG)/os/CONFIG.Common.RTEMS
diff --git a/configure/os/CONFIG.Common.RTEMS-pc386-qemu b/configure/os/CONFIG.Common.RTEMS-pc386-qemu
new file mode 100644
index 000000000..684f01a19
--- /dev/null
+++ b/configure/os/CONFIG.Common.RTEMS-pc386-qemu
@@ -0,0 +1,11 @@
+# CONFIG.Common.RTEMS-pc386-qemu
+#
+# Definitions for the RTEMS-pc386-qemu target
+# Site-specific overrides go in CONFIG_SITE.Common.RTEMS-pc386-qemu
+#
+#-------------------------------------------------------
+
+# Include definitions from RTEMS-pc386
+include $(CONFIG)/os/CONFIG.Common.RTEMS-pc386
+
+RTEMS_QEMU_FIXUPS = YES
diff --git a/configure/os/CONFIG.Common.RTEMS-psim b/configure/os/CONFIG.Common.RTEMS-psim
index 230d72e1f..58ad72852 100644
--- a/configure/os/CONFIG.Common.RTEMS-psim
+++ b/configure/os/CONFIG.Common.RTEMS-psim
@@ -5,5 +5,6 @@
#
# All RTEMS targets use the same Makefile fragment
#
-RTEMS_TARGET_CPU=ppc
+RTEMS_BSP = psim
+RTEMS_TARGET_CPU = ppc
include $(CONFIG)/os/CONFIG.Common.RTEMS
diff --git a/configure/os/CONFIG.Common.RTEMS-uC5282 b/configure/os/CONFIG.Common.RTEMS-uC5282
index 6b0903e07..2cb215aca 100644
--- a/configure/os/CONFIG.Common.RTEMS-uC5282
+++ b/configure/os/CONFIG.Common.RTEMS-uC5282
@@ -5,6 +5,7 @@
#
# All RTEMS targets use the same Makefile fragment
#
+RTEMS_BSP = uC5282
RTEMS_TARGET_CPU = m68k
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL
diff --git a/configure/os/CONFIG_SITE.Common.RTEMS-pc386 b/configure/os/CONFIG_SITE.Common.RTEMS-pc386
deleted file mode 100644
index c772c44fc..000000000
--- a/configure/os/CONFIG_SITE.Common.RTEMS-pc386
+++ /dev/null
@@ -1,3 +0,0 @@
-#
-# Site-specific overrides for RTEMS-pc386 target
-#
diff --git a/configure/os/CONFIG_SITE.Common.RTEMS-pc386-qemu b/configure/os/CONFIG_SITE.Common.RTEMS-pc386-qemu
new file mode 100644
index 000000000..027dcf4ab
--- /dev/null
+++ b/configure/os/CONFIG_SITE.Common.RTEMS-pc386-qemu
@@ -0,0 +1,9 @@
+# CONFIG_SITE.Common.RTEMS-pc386-qemu
+#
+# Site-specific overrides for the RTEMS-pc386-qemu target
+#
+
+# If you're building this architecture you _probably_ want to
+# run the tests for it under QEMU, but if not you can turn
+# them off here by commenting out this line:
+CROSS_COMPILER_RUNTEST_ARCHS += RTEMS-pc386-qemu
diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html
index 3f98c6f06..90ceb77e4 100644
--- a/documentation/RELEASE_NOTES.html
+++ b/documentation/RELEASE_NOTES.html
@@ -19,6 +19,32 @@
-->
+
RTEMS build configuration update, running tests under QEMU
+
+This release includes the ability to run the EPICS unit tests built for a
+special version of the RTEMS-pc386 target architecture on systems that have an
+appropriate QEMU emulator installed (qemu-system-i386). It is also now
+possible to create sub-architectures of RTEMS targets, whereas previously the
+EPICS target architecture name had to be RTEMS-$(RTEMS_BSP).
+
+The new target RTEMS-pc386-qemu builds binaries that can be run in
+the qemu-system-i386 PC System emulator. This target is a derivative of
+the original RTEMS-pc386 target but with additional software to build
+an in-memory file-system, and some minor modifications to allow the unit tests
+to work properly under QEMU. When this target is enabled, building any of the
+make targets that cause the built-in self-tests to be run (such as
+make runtests) will also run the tests for RTEMS using QEMU.
+
+To allow the new 3-component RTEMS target name, the EPICS build system for
+RTEMS was modified to allow a configure/os/CONFIG.Common.<arch>
+file to set the RTEMS_BSP variable to inform the build what RTEMS BSP
+to use. Previously this was inferred from the value of the T_A make
+variable, but that prevents having multiple EPICS targets that build against the
+same BSP. All the included RTEMS target configuration files have been updated;
+build configuration files for out-of-tree RTEMS targets will continue to work as
+the original rules are used to set RTEMS_BSP if it hasn't been set when
+needed.
+
Link type enhancements
This release adds three new link types: "state", "debug" and "trace". The
diff --git a/src/ioc/db/test/Makefile b/src/ioc/db/test/Makefile
index 37ec3da74..90ca9da35 100644
--- a/src/ioc/db/test/Makefile
+++ b/src/ioc/db/test/Makefile
@@ -175,6 +175,8 @@ testHarness_SRCS += epicsRunDbTests.c
dbTestHarness_SRCS += $(testHarness_SRCS)
dbTestHarness_SRCS_RTEMS += rtemsTestHarness.c
+PROD_SRCS_RTEMS += rtemsTestData.c
+
PROD_vxWorks = dbTestHarness
PROD_RTEMS = dbTestHarness
@@ -182,6 +184,10 @@ TESTSPEC_vxWorks = dbTestHarness.munch; epicsRunDbTests
TESTSPEC_RTEMS = dbTestHarness.boot; epicsRunDbTests
TESTSCRIPTS_HOST += $(TESTS:%=%.t)
+ifneq ($(filter $(T_A),$(CROSS_COMPILER_RUNTEST_ARCHS)),)
+TESTPROD_RTEMS = $(TESTPROD_HOST)
+TESTSCRIPTS_RTEMS += $(TESTS:%=%.t)
+endif
include $(TOP)/configure/RULES
@@ -193,3 +199,5 @@ devx$(DEP): $(COMMON_DIR)/xRecord.h
scanIoTest$(DEP): $(COMMON_DIR)/xRecord.h
xRecord$(DEP): $(COMMON_DIR)/xRecord.h
+rtemsTestData.c : $(TESTFILES) $(TOOLS)/epicsMakeMemFs.pl
+ $(PERL) $(TOOLS)/epicsMakeMemFs.pl $@ epicsRtemsFSImage $(TESTFILES)
diff --git a/src/ioc/db/test/dbStressLock.c b/src/ioc/db/test/dbStressLock.c
index 376587975..03a8e8b54 100644
--- a/src/ioc/db/test/dbStressLock.c
+++ b/src/ioc/db/test/dbStressLock.c
@@ -228,6 +228,11 @@ MAIN(dbStressTest)
testPlan(80+nworkers*3);
+#if defined(__rtems__)
+ testSkip(80+nworkers*3, "Test assumes time sliced preempting scheduling");
+ return testDone();
+#endif
+
priv = callocMustSucceed(nworkers, sizeof(*priv), "no memory");
testDiag("lock set stress test");
diff --git a/src/libCom/RTEMS/Makefile b/src/libCom/RTEMS/Makefile
index 4c0b64c04..22a92733c 100644
--- a/src/libCom/RTEMS/Makefile
+++ b/src/libCom/RTEMS/Makefile
@@ -10,7 +10,11 @@ TOP=../../..
include $(TOP)/configure/CONFIG
INC += epicsRtemsInitHooks.h
+INC += epicsMemFs.h
+ifeq ($(RTEMS_QEMU_FIXUPS),YES)
+rtems_init_CPPFLAGS += -DQEMU_FIXUPS
+endif
rtemsCom_SRCS += rtems_init.c
rtemsCom_SRCS += rtems_config.c
rtemsCom_SRCS += rtems_netconfig.c
@@ -18,6 +22,11 @@ rtemsCom_SRCS += rtems_util.c
rtemsCom_SRCS += setBootConfigFromNVRAM.c
rtemsCom_SRCS += epicsRtemsInitHookPre.c
rtemsCom_SRCS += epicsRtemsInitHookPost.c
+rtemsCom_SRCS += epicsMemFs.c
+
+ifeq ($(RTEMS_BSP),pc386)
+rtemsCom_SRCS += ne2kpci.c
+endif
LIBRARY_RTEMS = rtemsCom
diff --git a/src/libCom/RTEMS/epicsMemFs.c b/src/libCom/RTEMS/epicsMemFs.c
new file mode 100644
index 000000000..4689d210f
--- /dev/null
+++ b/src/libCom/RTEMS/epicsMemFs.c
@@ -0,0 +1,110 @@
+/*************************************************************************\
+* Copyright (c) 2014 Brookhaven National Laboratory.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include "epicsMemFs.h"
+
+#ifndef PATH_MAX
+# define PATH_MAX 100
+#endif
+
+int epicsMemFsLoad(const epicsMemFS *fs)
+{
+ char initdir[PATH_MAX];
+ const epicsMemFile * const *fileptr = fs->files;
+
+ if(getcwd(initdir, sizeof(initdir)-1)==NULL) {
+ perror("getcwd");
+ return errno;
+ }
+ initdir[sizeof(initdir)-1] = '\0';
+
+ for(;*fileptr; fileptr++) {
+ const epicsMemFile *curfile = *fileptr;
+ int fd;
+ ssize_t ret;
+ size_t sofar;
+ const char * const *dir = curfile->directory;
+ /* jump back to the root each time,
+ * slow but simple.
+ */
+ if(chdir(initdir)) {
+ perror("chdir");
+ return errno;
+ }
+
+ printf("-> /");
+
+ /* traverse directory tree, creating as necessary */
+ for(;*dir; dir++) {
+ int ret;
+ if(**dir=='.') continue; /* ignore '.' and '..' */
+ printf("%s/", *dir);
+ ret = chdir(*dir);
+ if(ret==-1 && errno==ENOENT) {
+ /* this directory doesn't exist */
+ if(mkdir(*dir,0744)==-1) {
+ printf("\n");
+ perror("mkdir");
+ return errno;
+ }
+ if(chdir(*dir)==-1) {
+ printf("\n");
+ perror("chdir2");
+ return errno;
+ }
+ } else if(ret==-1) {
+ printf("\n");
+ perror("chdir1");
+ return errno;
+ }
+ }
+
+ /* no file name creates an empty directory */
+ if(!curfile->name) {
+ printf("\n");
+ continue;
+ }
+ printf("%s", curfile->name);
+
+ /* create or overwrite */
+ fd = open(curfile->name, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+
+ if(fd==-1) {
+ printf("\n");
+ perror("open");
+ return errno;
+ }
+
+ sofar = 0;
+
+ while(sofarsize) {
+ ret = write(fd, curfile->data+sofar, curfile->size-sofar);
+ if(ret<=0) {
+ printf("\n");
+ perror("write");
+ return errno;
+ }
+ sofar += ret;
+ }
+
+ close(fd);
+ printf(" - ok\n");
+ }
+
+ if(chdir(initdir))
+ perror("chdir");
+
+ return 0;
+}
diff --git a/src/libCom/RTEMS/epicsMemFs.h b/src/libCom/RTEMS/epicsMemFs.h
new file mode 100644
index 000000000..c57f4d793
--- /dev/null
+++ b/src/libCom/RTEMS/epicsMemFs.h
@@ -0,0 +1,24 @@
+/*************************************************************************\
+* Copyright (c) 2014 Brookhaven National Laboratory.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+#ifndef EPICSMEMFS_H
+#define EPICSMEMFS_H
+
+#include
+
+typedef struct {
+ const char * const *directory; /* NULL terminated list of directories */
+ const char *name; /* file name */
+ const char *data; /* file contents */
+ size_t size; /* size of file contents in bytes */
+} epicsMemFile;
+
+typedef struct {
+ const epicsMemFile * const *files;
+} epicsMemFS;
+
+int epicsMemFsLoad(const epicsMemFS *fs);
+
+#endif // EPICSMEMFS_H
diff --git a/src/libCom/RTEMS/epicsRtemsInitHooks.h b/src/libCom/RTEMS/epicsRtemsInitHooks.h
index b7f09c100..4313f19e3 100644
--- a/src/libCom/RTEMS/epicsRtemsInitHooks.h
+++ b/src/libCom/RTEMS/epicsRtemsInitHooks.h
@@ -21,3 +21,5 @@ extern char *env_nfsMountPoint;
*/
int epicsRtemsInitPreSetBootConfigFromNVRAM(struct rtems_bsdnet_config *config);
int epicsRtemsInitPostSetBootConfigFromNVRAM(struct rtems_bsdnet_config *config);
+/* Return 0 if local file system was setup, or non-zero (will fall back to network */
+int epicsRtemsMountLocalFilesystem(char **argv);
diff --git a/src/libCom/RTEMS/ne2kpci.c b/src/libCom/RTEMS/ne2kpci.c
new file mode 100644
index 000000000..909d885f1
--- /dev/null
+++ b/src/libCom/RTEMS/ne2kpci.c
@@ -0,0 +1,58 @@
+/*************************************************************************\
+* Copyright (c) 2015 Brookhaven Science Associates, as Operator of
+* Brookhaven National Laboratory.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+/*
+ * Wrapper around the ISA ne2000 driver to support detection of the PCI variant.
+ * Can be used with the ne2k_pci device provided by QEMU.
+ *
+ * eg. "qemu-system-i386 ... -net nic,model=ne2k_pci"
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+/* The plain ISA driver attach()
+ * which doesn't (can't?) do any test to see if
+ * the HW is really present
+ */
+extern int
+rtems_ne_driver_attach (struct rtems_bsdnet_ifconfig *config, int attach);
+
+int
+rtems_ne2kpci_driver_attach (struct rtems_bsdnet_ifconfig *config, int attach)
+{
+ uint8_t irq;
+ uint32_t bar0;
+ int B, D, F, ret;
+ printk("Probing for NE2000 on PCI (aka. Realtek 8029)\n");
+
+ if(pci_find_device(PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8029, 0, &B, &D, &F))
+ {
+ printk("Not found\n");
+ return 0;
+ }
+
+ printk("Found %d:%d.%d\n", B, D, F);
+
+ ret = pci_read_config_dword(B, D, F, PCI_BASE_ADDRESS_0, &bar0);
+ ret|= pci_read_config_byte(B, D, F, PCI_INTERRUPT_LINE, &irq);
+
+ if(ret || (bar0&PCI_BASE_ADDRESS_SPACE)!=PCI_BASE_ADDRESS_SPACE_IO)
+ {
+ printk("Failed reading card config\n");
+ return 0;
+ }
+
+ config->irno = irq;
+ config->port = bar0&PCI_BASE_ADDRESS_IO_MASK;
+
+ printk("Using port=0x%x irq=%u\n", (unsigned)config->port, config->irno);
+
+ return rtems_ne_driver_attach(config, attach);
+}
diff --git a/src/libCom/RTEMS/rtems_init.c b/src/libCom/RTEMS/rtems_init.c
index 82871da0d..7dbf2594f 100644
--- a/src/libCom/RTEMS/rtems_init.c
+++ b/src/libCom/RTEMS/rtems_init.c
@@ -33,6 +33,7 @@
#include
#include
+#include "epicsVersion.h"
#include "epicsThread.h"
#include "epicsTime.h"
#include "epicsExit.h"
@@ -42,9 +43,12 @@
#include "osiUnistd.h"
#include "iocsh.h"
#include "osdTime.h"
+#include "epicsMemFs.h"
#include "epicsRtemsInitHooks.h"
+#define RTEMS_VERSION_INT VERSION_INT(__RTEMS_MAJOR__, __RTEMS_MINOR__, 0, 0)
+
/*
* Prototypes for some functions not in header files
*/
@@ -138,6 +142,31 @@ mustMalloc(int size, const char *msg)
# include
#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)
{
@@ -146,7 +175,9 @@ initialize_local_filesystem(char **argv)
extern char _FlashSize[] __attribute__((weak));
argv[0] = rtems_bsdnet_bootp_boot_file_name;
- if (_FlashSize && (_DownloadLocation || _FlashBase)) {
+ if (epicsRtemsMountLocalFilesystem(argv)==0) {
+ return 1; /* FS setup successful */
+ } else if (_FlashSize && (_DownloadLocation || _FlashBase)) {
extern char _edata[];
size_t flashIndex = _edata - _DownloadLocation;
char *header = _FlashBase + flashIndex;
@@ -596,6 +627,7 @@ Init (rtems_task_argument ignored)
}
printf("\n***** Initializing network *****\n");
rtems_bsdnet_initialize_network();
+ printf("\n***** Setting up file system *****\n");
initialize_remote_filesystem(argv, initialize_local_filesystem(argv));
fixup_hosts();
@@ -666,3 +698,37 @@ Init (rtems_task_argument ignored)
epicsThreadSleep(1.0);
epicsExit(result);
}
+
+#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
+extern int BSPPrintkPort;
+void bsp_predriver_hook(void)
+{
+ BSPConsolePort = BSP_CONSOLE_PORT_COM1;
+ BSPPrintkPort = BSP_CONSOLE_PORT_COM1;
+}
+#endif
+
+/* reboot immediately when done. */
+#if defined(__i386__) && BSP_PRESS_KEY_FOR_RESET
+void bsp_cleanup(void)
+{
+#if RTEMS_VERSION_INT>=VERSION_INT(4,10,0,0)
+ void bsp_reset();
+ bsp_reset();
+#else
+ rtemsReboot();
+#endif
+}
+#endif
+
+#endif /* QEMU_FIXUPS */
+
+int cexpdebug __attribute__((weak));
diff --git a/src/libCom/RTEMS/rtems_netconfig.c b/src/libCom/RTEMS/rtems_netconfig.c
index 832a6646b..d0c500c92 100644
--- a/src/libCom/RTEMS/rtems_netconfig.c
+++ b/src/libCom/RTEMS/rtems_netconfig.c
@@ -36,11 +36,19 @@ static struct rtems_bsdnet_ifconfig loopback_config = {
* application directory and make the appropriate changes.
*/
#if defined(__i386__)
+
+extern int
+rtems_ne2kpci_driver_attach (struct rtems_bsdnet_ifconfig *config, int attach);
+static struct rtems_bsdnet_ifconfig ne2k_driver_config = {
+ "ne2", /* name */
+ rtems_ne2kpci_driver_attach, /* attach function */
+ &loopback_config, /* link to next interface */
+};
extern int rtems_fxp_attach (struct rtems_bsdnet_ifconfig *, int);
static struct rtems_bsdnet_ifconfig fxp_driver_config = {
"fxp1", /* name */
rtems_fxp_attach, /* attach function */
- &loopback_config, /* link to next interface */
+ &ne2k_driver_config, /* link to next interface */
};
extern int rtems_3c509_driver_attach (struct rtems_bsdnet_ifconfig *, int);
static struct rtems_bsdnet_ifconfig e3c509_driver_config = {
diff --git a/src/libCom/misc/testMain.h b/src/libCom/misc/testMain.h
index 4db72c39e..7c4d9b29b 100644
--- a/src/libCom/misc/testMain.h
+++ b/src/libCom/misc/testMain.h
@@ -27,7 +27,13 @@
* }
*/
-#if defined(vxWorks) || defined(__rtems__)
+#if defined(__rtems__)
+ #ifdef __cplusplus
+ #define MAIN(prog) extern "C" int prog(void); extern "C" int main() __attribute__((weak, alias(#prog))); extern "C" int prog(void)
+ #else
+ #define MAIN(prog) int prog(); int main() __attribute__((weak, alias(#prog))); int prog()
+ #endif
+#elif defined(vxWorks)
#ifdef __cplusplus
#define MAIN(prog) extern "C" int prog(void)
#else
diff --git a/src/libCom/test/Makefile b/src/libCom/test/Makefile
index c78bdbb9f..faf97b718 100755
--- a/src/libCom/test/Makefile
+++ b/src/libCom/test/Makefile
@@ -14,11 +14,18 @@ PROD_LIBS += Com
PROD_SYS_LIBS_WIN32 += ws2_32 advapi32 user32
PROD_SYS_LIBS_solaris += socket nsl
+PROD_SRCS_RTEMS += rtemsTestData.c
+
+ifeq ($(EPICS_HOST_ARCH),$(T_A))
+# skip except for host arch due to custom .plt
+
TESTPROD_HOST += epicsUnitTestTest
epicsUnitTestTest_SRCS += epicsUnitTestTest.c
# Not much point running this on vxWorks or RTEMS...
TESTS += epicsUnitTestTest
+endif
+
TESTPROD_HOST += epicsTypesTest
epicsTypesTest_SRCS += epicsTypesTest.cpp
testHarness_SRCS += epicsTypesTest.cpp
@@ -237,6 +244,10 @@ TESTSPEC_vxWorks = libComTestHarness.munch; epicsRunLibComTests
TESTSPEC_RTEMS = libComTestHarness.boot; epicsRunLibComTests
TESTSCRIPTS_HOST += $(TESTS:%=%.t)
+ifneq ($(filter $(T_A),$(CROSS_COMPILER_RUNTEST_ARCHS)),)
+TESTPROD_RTEMS = $(TESTPROD_HOST)
+TESTSCRIPTS_RTEMS += $(filter-out epicsUnitTestTest.t, $(TESTS:%=%.t))
+endif
# The following are not test programs, they measure performance.
diff --git a/src/libCom/test/rtemsTestData.c b/src/libCom/test/rtemsTestData.c
new file mode 100644
index 000000000..7b68976c5
--- /dev/null
+++ b/src/libCom/test/rtemsTestData.c
@@ -0,0 +1,6 @@
+#include "epicsMemFs.h"
+
+/* no local files needed for these tests,
+ * so skip local FS setup
+ */
+const epicsMemFS *epicsRtemsFSImage = NULL;
diff --git a/src/std/filters/test/Makefile b/src/std/filters/test/Makefile
index 6e6ad79c6..d6d9973f6 100644
--- a/src/std/filters/test/Makefile
+++ b/src/std/filters/test/Makefile
@@ -62,6 +62,8 @@ testHarness_SRCS += epicsRunFilterTests.c
filterTestHarness_SRCS += $(testHarness_SRCS)
filterTestHarness_SRCS_RTEMS += rtemsTestHarness.c
+PROD_SRCS_RTEMS += rtemsTestData.c
+
PROD_vxWorks = filterTestHarness
PROD_RTEMS = filterTestHarness
@@ -69,6 +71,10 @@ TESTSPEC_vxWorks = filterTestHarness.munch; epicsRunFilterTests
TESTSPEC_RTEMS = filterTestHarness.boot; epicsRunFilterTests
TESTSCRIPTS_HOST += $(TESTS:%=%.t)
+ifneq ($(filter $(T_A),$(CROSS_COMPILER_RUNTEST_ARCHS)),)
+TESTPROD_RTEMS = $(TESTPROD_HOST)
+TESTSCRIPTS_RTEMS += $(TESTS:%=%.t)
+endif
include $(TOP)/configure/RULES
@@ -78,3 +84,6 @@ dbndTest$(DEP): $(COMMON_DIR)/xRecord.h
syncTest$(DEP): $(COMMON_DIR)/xRecord.h
arrRecord$(DEP): $(COMMON_DIR)/arrRecord.h
arrTest$(DEP): $(COMMON_DIR)/arrRecord.h
+
+rtemsTestData.c : $(TESTFILES) $(TOOLS)/epicsMakeMemFs.pl
+ $(PERL) $(TOOLS)/epicsMakeMemFs.pl $@ epicsRtemsFSImage $(TESTFILES)
diff --git a/src/std/rec/test/Makefile b/src/std/rec/test/Makefile
index 99fe4d9eb..3fcc6bdeb 100644
--- a/src/std/rec/test/Makefile
+++ b/src/std/rec/test/Makefile
@@ -138,6 +138,8 @@ testHarness_SRCS += epicsRunRecordTests.c
recordTestHarness_SRCS += $(testHarness_SRCS)
recordTestHarness_SRCS_RTEMS += rtemsTestHarness.c
+PROD_SRCS_RTEMS += rtemsTestData.c
+
PROD_vxWorks = recordTestHarness
PROD_RTEMS = recordTestHarness
@@ -145,5 +147,12 @@ TESTSPEC_vxWorks = recordTestHarness.munch; epicsRunRecordTests
TESTSPEC_RTEMS = recordTestHarness.boot; epicsRunRecordTests
TESTSCRIPTS_HOST += $(TESTS:%=%.t)
+ifneq ($(filter $(T_A),$(CROSS_COMPILER_RUNTEST_ARCHS)),)
+TESTPROD_RTEMS = $(TESTPROD_HOST)
+TESTSCRIPTS_RTEMS += $(TESTS:%=%.t)
+endif
include $(TOP)/configure/RULES
+
+rtemsTestData.c : $(TESTFILES) $(TOOLS)/epicsMakeMemFs.pl
+ $(PERL) $(TOOLS)/epicsMakeMemFs.pl $@ epicsRtemsFSImage $(TESTFILES)
diff --git a/src/tools/Makefile b/src/tools/Makefile
index c7594ccbe..00e83ecba 100644
--- a/src/tools/Makefile
+++ b/src/tools/Makefile
@@ -51,6 +51,7 @@ PERL_SCRIPTS += mkmf.pl
PERL_SCRIPTS += munch.pl
PERL_SCRIPTS += replaceVAR.pl
PERL_SCRIPTS += tap-to-junit-xml.pl
+PERL_SCRIPTS += epicsMakeMemFs.pl
PERL_SCRIPTS += useManifestTool.pl
PERL_SCRIPTS += genVersionHeader.pl
diff --git a/src/tools/epicsMakeMemFs.pl b/src/tools/epicsMakeMemFs.pl
new file mode 100644
index 000000000..a97074e0e
--- /dev/null
+++ b/src/tools/epicsMakeMemFs.pl
@@ -0,0 +1,83 @@
+#!/usr/bin/env perl
+#
+
+use File::Basename;
+
+use strict;
+
+my $outfile = shift;
+my $varname = shift;
+
+open(my $DST, '>', $outfile) or die "Failed to open $outfile";
+
+print $DST <
+EOF
+
+my $N = 0;
+
+for my $fname (@ARGV) {
+ print "<- $fname\n";
+ my $realfname = $fname;
+
+ # strip leading "../" "./" or "/"
+ while ($fname =~ /^\.*\/(.*)$/) { $fname = $1; }
+
+ my $file = basename($fname);
+ my @dirs = split('/', dirname($fname));
+
+ print $DST "/* begin $realfname */\nstatic const char * const file_${N}_dir[] = {";
+ for my $dpart (@dirs) {
+ print $DST "\"$dpart\", ";
+ }
+ print $DST "NULL};\nstatic const char file_${N}_data[] = {\n ";
+
+ open(my $SRC, '<', $realfname) or die "Failed to open $realfname";
+ binmode($SRC);
+
+ my $buf;
+ my $total = 0;
+ while (my $num = read($SRC, $buf, 32)) {
+ if($total != 0) {
+ print $DST ",\n ";
+ }
+ $total += $num;
+ my $out = join(",",map(ord,split(//,$buf)));
+ print $DST "$out";
+ }
+
+ close($SRC);
+
+ print $DST < target.t executable
+# target-arch and host-arch are EPICS build target names (eg. linux-x86)
# target.t is the name of the Perl script to generate
# executable is the name of the file the script runs
use strict;
-my ($target, $exe) = @ARGV;
+my ($TA, $HA, $target, $exe) = @ARGV;
+my $exec;
+
+# Use WINE to run windows target executables on non-windows host
+if( $TA =~ /^win32-x86/ && $HA !~ /^win/ ) {
+ # new deb. derivatives have wine32 and wine64
+ # older have wine and wine64
+ # prefer wine32 if present
+ my $wine32 = "/usr/bin/wine32";
+ $wine32 = "/usr/bin/wine" if ! -x $wine32;
+ $exec = "$wine32 $exe";
+} elsif( $TA =~ /^windows-x64/ && $HA !~ /^win/ ) {
+ $exec = "wine64 $exe";
+
+# Run pc386 test harness w/ QEMU
+} elsif( $TA =~ /^RTEMS-pc386-qemu$/ ) {
+ $exec = "qemu-system-i386 -m 64 -no-reboot -serial stdio -display none -net nic,model=ne2k_pci -net user,restrict=yes -kernel $exe";
+
+# Explicitly fail for other RTEMS targets
+} elsif( $TA =~ /^RTEMS-/ ) {
+ die "$0: I don't know how to create scripts for testing $TA on $HA\n";
+
+} else {
+ $exec = "./$exe";
+}
open(my $OUT, '>', $target) or die "Can't create $target: $!\n";
print $OUT <