aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile13
-rw-r--r--libraries/libprof/Makefile20
-rw-r--r--libraries/libprof/README.txt65
-rw-r--r--libraries/libprof/gmon.c323
-rw-r--r--libraries/libprof/gmon.h177
-rw-r--r--libraries/libprof/profil.c93
-rw-r--r--libraries/libprof/profil.h60
-rw-r--r--libraries/libprof/profiler.S28
-rw-r--r--libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_it.c8
-rw-r--r--memfunc.c101
-rw-r--r--projects/hsm/Makefile23
-rw-r--r--projects/hsm/mgmt-misc.c28
-rw-r--r--projects/hsm/mgmt-task.c4
-rw-r--r--syscalls.c6
-rw-r--r--task.c8
-rw-r--r--task.h2
16 files changed, 946 insertions, 13 deletions
diff --git a/Makefile b/Makefile
index d8c9593..432260b 100644
--- a/Makefile
+++ b/Makefile
@@ -51,6 +51,9 @@ LIBCLI_BLD = $(LIBS_DIR)/libcli
LIBTFM_SRC = $(CRYPTECH_ROOT)/sw/thirdparty/libtfm
LIBTFM_BLD = $(LIBS_DIR)/libtfm
+LIBPROF_SRC = $(LIBS_DIR)/libprof
+LIBPROF_BLD = $(LIBS_DIR)/libprof
+
LIBS = $(MBED_DIR)/libstmf4.a
# linker script
@@ -140,11 +143,20 @@ $(LIBHAL_BLD)/libhal.a: $(LIBTFM_BLD)/libtfm.a .FORCE
$(LIBCLI_BLD)/libcli.a: .FORCE
$(MAKE) -C $(LIBCLI_BLD)
+$(LIBPROF_BLD)/libprof.a: .FORCE
+ $(MAKE) -C $(LIBPROF_BLD)
+
libhal-test: $(BOARD_OBJS) $(LIBS) $(LIBHAL_BLD)/libhal.a .FORCE
$(MAKE) -C projects/libhal-test
+ifdef DO_PROFILING
+CFLAGS += -pg -DDO_PROFILING
+hsm: $(BOARD_OBJS) $(LIBS) $(LIBHAL_BLD)/libhal.a $(LIBCLI_BLD)/libcli.a $(LIBPROF_BLD)/libprof.a .FORCE
+ $(MAKE) -C projects/hsm
+else
hsm: $(BOARD_OBJS) $(LIBS) $(LIBHAL_BLD)/libhal.a $(LIBCLI_BLD)/libcli.a .FORCE
$(MAKE) -C projects/hsm
+endif
bootloader: $(BOARD_OBJS) $(LIBS) $(LIBHAL_BLD)/libhal.a .FORCE
$(MAKE) -C projects/bootloader
@@ -176,3 +188,4 @@ distclean: clean
$(MAKE) -C $(MBED_DIR) clean
$(MAKE) -C $(LIBTFM_BLD) clean
$(MAKE) -C $(LIBCLI_BLD) clean
+ $(MAKE) -C $(LIBPROF_BLD) clean
diff --git a/libraries/libprof/Makefile b/libraries/libprof/Makefile
new file mode 100644
index 0000000..4fe5fb4
--- /dev/null
+++ b/libraries/libprof/Makefile
@@ -0,0 +1,20 @@
+LIB = libprof.a
+
+OBJS = gmon.o profil.o profiler.o
+
+# Don't profile the profiling code, because that way lies madness (and recursion).
+CFLAGS := $(subst -pg,,$(CFLAGS))
+
+all: $(LIB)
+
+%.o : %.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+%.o : %.S
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+$(LIB): $(OBJS)
+ $(AR) -r $@ $^
+
+clean:
+ rm -f $(OBJS) $(LIB)
diff --git a/libraries/libprof/README.txt b/libraries/libprof/README.txt
new file mode 100644
index 0000000..1fe378c
--- /dev/null
+++ b/libraries/libprof/README.txt
@@ -0,0 +1,65 @@
+Profiling the Cryptech Alpha
+============================
+
+Origin
+------
+
+This code was copied from https://github.com/ErichStyger/mcuoneclipse.git,
+directory Examples/KDS/FRDM-K64F120M/FRDM-K64F_Profiling/Profiling, commit
+9b7eedddd8b24968128582aedc63be95b61f782c, dated Mon Jan 9 16:56:17 2017 +0100.
+
+References
+----------
+
+I recommend reading both of these to understand how the profiling code works.
+
+[1]: https://mcuoneclipse.com/2015/08/23/tutorial-using-gnu-profiling-gprof-with-arm-cortex-m/
+"Tutorial: Using GNU Profiling (gprof) with ARM Cortex-M"
+
+[2]: http://bgamari.github.io/posts/2014-10-31-semihosting.html
+"Semihosting with ARM, GCC, and OpenOCD"
+
+How to build
+------------
+
+From the top level, run
+
+ make DO_PROFILING=1 hsm
+
+By default, all code is profiled, *except* the profiling code itself,
+because that would cause fatal recursion.
+
+How to run
+----------
+
+You need to start OpenOCD on the host, and enable semihosting, at least
+before you try to use it as a remote file system.
+
+I recommend executing the following in the projects/hsm directory, so that
+gmon.out ends up in the same directory as hsm.elf.
+
+Start OpenOCD:
+
+ $ openocd -f /usr/share/openocd/scripts/board/stm32f4discovery.cfg &
+
+Connect to OpenOCD:
+
+ $ telnet localhost 4444
+
+In the OpenOCD console, enable semihosting:
+
+ > arm semihosting enable
+
+In another window, start the debugger:
+
+ $ sw/stm32/bin/debug projects/hsm/hsm
+
+In the CLI, type `profile start`, then start the unit test or whatever
+will be exercising the hsm. Afterwards, in the CLI, type `profile stop`.
+
+After invoking `profile stop`, it can take several minutes to write
+gmon.out over OpenOCD to the host.
+
+In the projects/hsm directory, run gprof to analyse the gmon.out file:
+
+ $ gprof hsm.elf >gprof.txt
diff --git a/libraries/libprof/gmon.c b/libraries/libprof/gmon.c
new file mode 100644
index 0000000..92054fc
--- /dev/null
+++ b/libraries/libprof/gmon.c
@@ -0,0 +1,323 @@
+/*-
+ * Copyright (c) 1983, 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * This file is taken from Cygwin distribution. Please keep it in sync.
+ * The differences should be within __MINGW32__ guard.
+ */
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "gmon.h"
+#include "profil.h"
+#include <string.h>
+
+#define bzero(ptr,size) memset (ptr, 0, size);
+#define ERR(s) write(2, s, sizeof(s))
+
+struct gmonparam _gmonparam = { GMON_PROF_OFF, NULL, 0, NULL, 0, NULL, 0, 0L, 0, 0, 0};
+static char already_setup = 0; /* flag to indicate if we need to init */
+static int s_scale;
+/* see profil(2) where this is described (incorrectly) */
+#define SCALE_1_TO_1 0x10000L
+
+static void moncontrol(int mode);
+
+void monstartup (size_t lowpc, size_t highpc) {
+ register size_t o;
+ char *cp;
+ struct gmonparam *p = &_gmonparam;
+
+ if (already_setup) {
+ /* zero out cp as value will be added there */
+ bzero(p->tos, p->kcountsize + p->fromssize + p->tossize);
+ moncontrol(1); /* start */
+ return;
+ }
+ already_setup = 1;
+
+ /* enable semihosting, for eventual output */
+ extern void initialise_monitor_handles(void);
+ initialise_monitor_handles();
+
+ /*
+ * round lowpc and highpc to multiples of the density we're using
+ * so the rest of the scaling (here and in gprof) stays in ints.
+ */
+ p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
+ p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
+ p->textsize = p->highpc - p->lowpc + 0x20;
+ p->kcountsize = p->textsize / HISTFRACTION;
+ p->fromssize = p->textsize / HASHFRACTION;
+ p->tolimit = p->textsize * ARCDENSITY / 100;
+ if (p->tolimit < MINARCS) {
+ p->tolimit = MINARCS;
+ } else if (p->tolimit > MAXARCS) {
+ p->tolimit = MAXARCS;
+ }
+ p->tossize = p->tolimit * sizeof(struct tostruct);
+
+ extern void *hal_allocate_static_memory(const size_t size);
+ cp = hal_allocate_static_memory(p->kcountsize + p->fromssize + p->tossize);
+ if (cp == NULL) {
+ ERR("monstartup: out of memory\n");
+ return;
+ }
+
+ /* zero out cp as value will be added there */
+ bzero(cp, p->kcountsize + p->fromssize + p->tossize);
+
+ p->tos = (struct tostruct *)cp;
+ cp += p->tossize;
+ p->kcount = (unsigned short *)cp;
+ cp += p->kcountsize;
+ p->froms = (unsigned short *)cp;
+
+ p->tos[0].link = 0;
+
+ o = p->highpc - p->lowpc;
+ if (p->kcountsize < o) {
+#ifndef notdef
+ s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1;
+#else /* avoid floating point */
+ int quot = o / p->kcountsize;
+
+ if (quot >= 0x10000)
+ s_scale = 1;
+ else if (quot >= 0x100)
+ s_scale = 0x10000 / quot;
+ else if (o >= 0x800000)
+ s_scale = 0x1000000 / (o / (p->kcountsize >> 8));
+ else
+ s_scale = 0x1000000 / ((o << 8) / p->kcountsize);
+#endif
+ } else {
+ s_scale = SCALE_1_TO_1;
+ }
+ moncontrol(1); /* start */
+}
+
+void _mcleanup(void) {
+ static const char gmon_out[] = "gmon.out";
+ int fd;
+ int fromindex;
+ int endfrom;
+ size_t frompc;
+ int toindex;
+ struct rawarc rawarc;
+ struct gmonparam *p = &_gmonparam;
+ struct gmonhdr gmonhdr = {0}, *hdr;
+ const char *proffile;
+#ifdef DEBUG
+ int log, len;
+ char dbuf[200];
+#endif
+
+ if (p->state == GMON_PROF_ERROR) {
+ ERR("_mcleanup: tos overflow\n");
+ }
+ moncontrol(0); /* stop */
+ proffile = gmon_out;
+ fd = open(proffile , O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0666);
+ if (fd < 0) {
+ perror( proffile );
+ return;
+ }
+#ifdef DEBUG
+ log = open("gmon.log", O_CREAT|O_TRUNC|O_WRONLY, 0664);
+ if (log < 0) {
+ perror("mcount: gmon.log");
+ return;
+ }
+ len = sprintf(dbuf, "[mcleanup1] kcount 0x%x ssiz %d\n",
+ (unsigned int)p->kcount, p->kcountsize);
+ write(log, dbuf, len);
+#endif
+ hdr = (struct gmonhdr *)&gmonhdr;
+ hdr->lpc = p->lowpc;
+ hdr->hpc = p->highpc;
+ hdr->ncnt = p->kcountsize + sizeof(gmonhdr);
+ hdr->version = GMONVERSION;
+ hdr->profrate = PROF_HZ;
+ hdr->spare[0] = hdr->spare[1] = hdr->spare[2] = 0;
+ write(fd, (char *)hdr, sizeof *hdr);
+ write(fd, p->kcount, p->kcountsize);
+ endfrom = p->fromssize / sizeof(*p->froms);
+ for (fromindex = 0; fromindex < endfrom; fromindex++) {
+ if (p->froms[fromindex] == 0) {
+ continue;
+ }
+ frompc = p->lowpc;
+ frompc += fromindex * HASHFRACTION * sizeof(*p->froms);
+ for (toindex = p->froms[fromindex]; toindex != 0; toindex = p->tos[toindex].link) {
+#ifdef DEBUG
+ len = sprintf(dbuf,
+ "[mcleanup2] frompc 0x%x selfpc 0x%x count %ld\n" ,
+ frompc, p->tos[toindex].selfpc,
+ p->tos[toindex].count);
+ write(log, dbuf, len);
+#endif
+ rawarc.raw_frompc = frompc;
+ rawarc.raw_selfpc = p->tos[toindex].selfpc;
+ rawarc.raw_count = p->tos[toindex].count;
+ write(fd, &rawarc, sizeof rawarc);
+ }
+ }
+ close(fd);
+}
+
+/*
+ * Control profiling
+ * profiling is what mcount checks to see if
+ * all the data structures are ready.
+ */
+static void moncontrol(int mode) {
+ struct gmonparam *p = &_gmonparam;
+
+ if (mode) {
+ /* start */
+ profil((char *)p->kcount, p->kcountsize, p->lowpc, s_scale);
+ p->state = GMON_PROF_ON;
+ } else {
+ /* stop */
+ profil((char *)0, 0, 0, 0);
+ p->state = GMON_PROF_OFF;
+ }
+}
+
+void _mcount_internal(uint32_t *frompcindex, uint32_t *selfpc) {
+ register struct tostruct *top;
+ register struct tostruct *prevtop;
+ register long toindex;
+ struct gmonparam *p = &_gmonparam;
+
+ /*
+ * check that we are profiling
+ * and that we aren't recursively invoked.
+ */
+ if (p->state!=GMON_PROF_ON) {
+ goto out;
+ }
+ p->state++;
+ /*
+ * check that frompcindex is a reasonable pc value.
+ * for example: signal catchers get called from the stack,
+ * not from text space. too bad.
+ */
+ frompcindex = (uint32_t*)((long)frompcindex - (long)p->lowpc);
+ if ((unsigned long)frompcindex > p->textsize) {
+ goto done;
+ }
+ frompcindex = (uint32_t*)&p->froms[((long)frompcindex) / (HASHFRACTION * sizeof(*p->froms))];
+ toindex = *((unsigned short*)frompcindex); /* get froms[] value */
+ if (toindex == 0) {
+ /*
+ * first time traversing this arc
+ */
+ toindex = ++p->tos[0].link; /* the link of tos[0] points to the last used record in the array */
+ if (toindex >= p->tolimit) { /* more tos[] entries than we can handle! */
+ goto overflow;
+ }
+ *((unsigned short*)frompcindex) = (unsigned short)toindex; /* store new 'to' value into froms[] */
+ top = &p->tos[toindex];
+ top->selfpc = (size_t)selfpc;
+ top->count = 1;
+ top->link = 0;
+ goto done;
+ }
+ top = &p->tos[toindex];
+ if (top->selfpc == (size_t)selfpc) {
+ /*
+ * arc at front of chain; usual case.
+ */
+ top->count++;
+ goto done;
+ }
+ /*
+ * have to go looking down chain for it.
+ * top points to what we are looking at,
+ * prevtop points to previous top.
+ * we know it is not at the head of the chain.
+ */
+ for (; /* goto done */; ) {
+ if (top->link == 0) {
+ /*
+ * top is end of the chain and none of the chain
+ * had top->selfpc == selfpc.
+ * so we allocate a new tostruct
+ * and link it to the head of the chain.
+ */
+ toindex = ++p->tos[0].link;
+ if (toindex >= p->tolimit) {
+ goto overflow;
+ }
+ top = &p->tos[toindex];
+ top->selfpc = (size_t)selfpc;
+ top->count = 1;
+ top->link = *((unsigned short*)frompcindex);
+ *(unsigned short*)frompcindex = (unsigned short)toindex;
+ goto done;
+ }
+ /*
+ * otherwise, check the next arc on the chain.
+ */
+ prevtop = top;
+ top = &p->tos[top->link];
+ if (top->selfpc == (size_t)selfpc) {
+ /*
+ * there it is.
+ * increment its count
+ * move it to the head of the chain.
+ */
+ top->count++;
+ toindex = prevtop->link;
+ prevtop->link = top->link;
+ top->link = *((unsigned short*)frompcindex);
+ *((unsigned short*)frompcindex) = (unsigned short)toindex;
+ goto done;
+ }
+ }
+ done:
+ p->state--;
+ /* and fall through */
+ out:
+ return; /* normal return restores saved registers */
+ overflow:
+ p->state++; /* halt further profiling */
+ #define TOLIMIT "mcount: tos overflow\n"
+ write (2, TOLIMIT, sizeof(TOLIMIT));
+ goto out;
+}
+
+void _monInit(void) {
+ _gmonparam.state = GMON_PROF_OFF;
+ already_setup = 0;
+}
diff --git a/libraries/libprof/gmon.h b/libraries/libprof/gmon.h
new file mode 100644
index 0000000..8b5ecf0
--- /dev/null
+++ b/libraries/libprof/gmon.h
@@ -0,0 +1,177 @@
+/* $OpenBSD: gmon.h,v 1.3 1996/04/21 22:31:46 deraadt Exp $ */
+/* $NetBSD: gmon.h,v 1.5 1996/04/09 20:55:30 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1982, 1986, 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)gmon.h 8.2 (Berkeley) 1/4/94
+ */
+
+/*
+ * This file is taken from Cygwin distribution. Please keep it in sync.
+ * The differences should be within __MINGW32__ guard.
+ */
+
+#ifndef _SYS_GMON_H_
+#define _SYS_GMON_H_
+
+#ifndef __P
+#define __P(x) x
+#endif
+
+/* On POSIX systems, profile.h is a KRB5 header. To avoid collisions, just
+ pull in profile.h's content here. The profile.h header won't be provided
+ by Mingw-w64 anymore at one point. */
+#if 0
+#include <profile.h>
+#else
+#ifndef _WIN64
+#define _MCOUNT_CALL __attribute__ ((regparm (2)))
+extern void _mcount(void);
+#else
+#define _MCOUNT_CALL
+extern void mcount(void);
+#endif
+#define _MCOUNT_DECL __attribute__((gnu_inline)) __inline__ \
+ void _MCOUNT_CALL _mcount_private
+#define MCOUNT
+#endif
+
+/*
+ * Structure prepended to gmon.out profiling data file.
+ */
+struct gmonhdr {
+ size_t lpc; /* base pc address of sample buffer */
+ size_t hpc; /* max pc address of sampled buffer */
+ int ncnt; /* size of sample buffer (plus this header) */
+ int version; /* version number */
+ int profrate; /* profiling clock rate */
+ int spare[3]; /* reserved */
+};
+#define GMONVERSION 0x00051879
+
+/*
+ * histogram counters are unsigned shorts (according to the kernel).
+ */
+#define HISTCOUNTER unsigned short
+
+/*
+ * fraction of text space to allocate for histogram counters here, 1/2
+ */
+#define HISTFRACTION 2
+
+/*
+ * Fraction of text space to allocate for from hash buckets.
+ * The value of HASHFRACTION is based on the minimum number of bytes
+ * of separation between two subroutine call points in the object code.
+ * Given MIN_SUBR_SEPARATION bytes of separation the value of
+ * HASHFRACTION is calculated as:
+ *
+ * HASHFRACTION = MIN_SUBR_SEPARATION / (2 * sizeof(short) - 1);
+ *
+ * For example, on the VAX, the shortest two call sequence is:
+ *
+ * calls $0,(r0)
+ * calls $0,(r0)
+ *
+ * which is separated by only three bytes, thus HASHFRACTION is
+ * calculated as:
+ *
+ * HASHFRACTION = 3 / (2 * 2 - 1) = 1
+ *
+ * Note that the division above rounds down, thus if MIN_SUBR_FRACTION
+ * is less than three, this algorithm will not work!
+ *
+ * In practice, however, call instructions are rarely at a minimal
+ * distance. Hence, we will define HASHFRACTION to be 2 across all
+ * architectures. This saves a reasonable amount of space for
+ * profiling data structures without (in practice) sacrificing
+ * any granularity.
+ */
+#define HASHFRACTION 2
+
+/*
+ * percent of text space to allocate for tostructs with a minimum.
+ */
+#define ARCDENSITY 2 /* this is in percentage, relative to text size! */
+#define MINARCS 50
+#define MAXARCS ((1 << (8 * sizeof(HISTCOUNTER))) - 2)
+
+struct tostruct {
+ size_t selfpc; /* callee address/program counter. The caller address is in froms[] array which points to tos[] array */
+ long count; /* how many times it has been called */
+ unsigned short link; /* link to next entry in hash table. For tos[0] this points to the last used entry */
+ unsigned short pad; /* additional padding bytes, to have entries 4byte aligned */
+};
+
+/*
+ * a raw arc, with pointers to the calling site and
+ * the called site and a count.
+ */
+struct rawarc {
+ size_t raw_frompc;
+ size_t raw_selfpc;
+ long raw_count;
+};
+
+/*
+ * general rounding functions.
+ */
+#define ROUNDDOWN(x,y) (((x)/(y))*(y))
+#define ROUNDUP(x,y) ((((x)+(y)-1)/(y))*(y))
+
+/*
+ * The profiling data structures are housed in this structure.
+ */
+struct gmonparam {
+ int state;
+ unsigned short *kcount; /* histogram PC sample array */
+ size_t kcountsize; /* size of kcount[] array in bytes */
+ unsigned short *froms; /* array of hashed 'from' addresses. The 16bit value is an index into the tos[] array */
+ size_t fromssize; /* size of froms[] array in bytes */
+ struct tostruct *tos; /* to struct, contains histogram counter */
+ size_t tossize; /* size of tos[] array in bytes */
+ long tolimit;
+ size_t lowpc; /* low program counter of area */
+ size_t highpc; /* high program counter */
+ size_t textsize; /* code size */
+};
+extern struct gmonparam _gmonparam;
+
+/*
+ * Possible states of profiling.
+ */
+#define GMON_PROF_ON 0
+#define GMON_PROF_BUSY 1
+#define GMON_PROF_ERROR 2
+#define GMON_PROF_OFF 3
+
+void _mcleanup(void); /* routine to be called to write gmon.out file */
+void _monInit(void); /* initialization routine */
+
+#endif /* !_SYS_GMONH_ */
diff --git a/libraries/libprof/profil.c b/libraries/libprof/profil.c
new file mode 100644
index 0000000..0654879
--- /dev/null
+++ b/libraries/libprof/profil.c
@@ -0,0 +1,93 @@
+/* profil.c -- win32 profil.c equivalent
+
+ Copyright 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+
+ This file is part of Cygwin.
+
+ This software is a copyrighted work licensed under the terms of the
+ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+ details. */
+
+/*
+ * This file is taken from Cygwin distribution, adapted to be used for bare embedded targets.
+ */
+#include <stdio.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <math.h>
+#include "profil.h"
+#include <string.h>
+
+#include "stm32f4xx_hal.h" /* __get_MSP */
+
+/* global profinfo for profil() call */
+static struct profinfo prof = {
+ PROFILE_NOT_INIT, 0, 0, 0, 0
+};
+
+extern void set_SysTick_hook(void (*hook)(void));
+
+/* sample the current program counter */
+static void SysTick_hook(void) {
+ size_t pc = (size_t)((uint32_t *)__get_MSP())[8];
+ if (pc >= prof.lowpc && pc < prof.highpc) {
+ size_t idx = PROFIDX (pc, prof.lowpc, prof.scale);
+ prof.counter[idx]++;
+ }
+}
+
+/* Stop profiling to the profiling buffer pointed to by p. */
+static int profile_off (struct profinfo *p) {
+ set_SysTick_hook(NULL);
+ p->state = PROFILE_OFF;
+ return 0;
+}
+
+/* Create a timer thread and pass it a pointer P to the profiling buffer. */
+static int profile_on (struct profinfo *p) {
+ set_SysTick_hook(SysTick_hook);
+ p->state = PROFILE_ON;
+ return 0; /* ok */
+}
+
+/*
+ * start or stop profiling
+ *
+ * profiling goes into the SAMPLES buffer of size SIZE (which is treated
+ * as an array of unsigned shorts of size size/2)
+ *
+ * each bin represents a range of pc addresses from OFFSET. The number
+ * of pc addresses in a bin depends on SCALE. (A scale of 65536 maps
+ * each bin to two addresses, A scale of 32768 maps each bin to 4 addresses,
+ * a scale of 1 maps each bin to 128k address). Scale may be 1 - 65536,
+ * or zero to turn off profiling
+ */
+int profile_ctl (struct profinfo *p, char *samples, size_t size, size_t offset, unsigned int scale) {
+ size_t maxbin;
+
+ if (scale > 65536) {
+ errno = EINVAL;
+ return -1;
+ }
+ profile_off(p);
+ if (scale) {
+ memset(samples, 0, size);
+ memset(p, 0, sizeof *p);
+ maxbin = size >> 1;
+ prof.counter = (unsigned short*)samples;
+ prof.lowpc = offset;
+ prof.highpc = PROFADDR(maxbin, offset, scale);
+ prof.scale = scale;
+ return profile_on(p);
+ }
+ return 0;
+}
+
+/* Equivalent to unix profil()
+ Every SLEEPTIME interval, the user's program counter (PC) is examined:
+ offset is subtracted and the result is multiplied by scale.
+ The word pointed to by this address is incremented. */
+int profil (char *samples, size_t size, size_t offset, unsigned int scale) {
+ return profile_ctl (&prof, samples, size, offset, scale);
+}
+
diff --git a/libraries/libprof/profil.h b/libraries/libprof/profil.h
new file mode 100644
index 0000000..c72dc00
--- /dev/null
+++ b/libraries/libprof/profil.h
@@ -0,0 +1,60 @@
+/* profil.h: gprof profiling header file
+
+ Copyright 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+/*
+ * This file is taken from Cygwin distribution. Please keep it in sync.
+ * The differences should be within __MINGW32__ guard.
+ */
+
+#ifndef __PROFIL_H__
+#define __PROFIL_H__
+
+/* profiling frequency. (No larger than 1000) */
+#define PROF_HZ 1000
+
+/* convert an addr to an index */
+#define PROFIDX(pc, base, scale) \
+ ({ \
+ size_t i = (pc - base) / 2; \
+ if (sizeof (unsigned long long int) > sizeof (size_t)) \
+ i = (unsigned long long int) i * scale / 65536; \
+ else \
+ i = i / 65536 * scale + i % 65536 * scale / 65536; \
+ i; \
+ })
+
+/* convert an index into an address */
+#define PROFADDR(idx, base, scale) \
+ ((base) \
+ + ((((unsigned long long)(idx) << 16) \
+ / (unsigned long long)(scale)) << 1))
+
+/* convert a bin size into a scale */
+#define PROFSCALE(range, bins) (((bins) << 16) / ((range) >> 1))
+
+typedef void *_WINHANDLE;
+
+typedef enum {
+ PROFILE_NOT_INIT = 0,
+ PROFILE_ON,
+ PROFILE_OFF
+} PROFILE_State;
+
+struct profinfo {
+ PROFILE_State state; /* profiling state */
+ unsigned short *counter; /* profiling counters */
+ size_t lowpc, highpc; /* range to be profiled */
+ unsigned int scale; /* scale value of bins */
+};
+
+int profile_ctl(struct profinfo *, char *, size_t, size_t, unsigned int);
+int profil(char *, size_t, size_t, unsigned int);
+
+#endif /* __PROFIL_H__ */
diff --git a/libraries/libprof/profiler.S b/libraries/libprof/profiler.S
new file mode 100644
index 0000000..1aa5c97
--- /dev/null
+++ b/libraries/libprof/profiler.S
@@ -0,0 +1,28 @@
+/*
+ * profiler.S
+ * Implements the gprof profiler arc counting function.
+ * Created on: 06.08.2015
+ * Author: Erich Styger
+ */
+
+ .syntax unified
+ .arch armv7-m
+
+.globl __gnu_mcount_nc
+.type __gnu_mcount_nc, %function
+
+__gnu_mcount_nc:
+#if 0 /* dummy version, doing nothing */
+ mov ip, lr
+ pop { lr }
+ bx ip
+#else
+ push {r0, r1, r2, r3, lr} /* save registers */
+ bic r1, lr, #1 /* R1 contains callee address, with thumb bit cleared */
+ ldr r0, [sp, #20] /* R0 contains caller address */
+ bic r0, r0, #1 /* clear thumb bit */
+ bl _mcount_internal /* jump to internal _mcount() implementation */
+ pop {r0, r1, r2, r3, ip, lr} /* restore saved registers */
+ bx ip /* return to caller */
+#endif
+
diff --git a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_it.c b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_it.c
index 8e5cc73..4629e44 100644
--- a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_it.c
+++ b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_it.c
@@ -64,6 +64,13 @@ void HardFault_Handler(void)
while (1) { ; }
}
+static void default_SysTick_hook(void) { };
+static void (*SysTick_hook)(void) = default_SysTick_hook;
+void set_SysTick_hook(void (*hook)(void))
+{
+ SysTick_hook = (hook == NULL) ? default_SysTick_hook : hook;
+}
+
/**
* @brief This function handles SysTick Handler.
* @param None
@@ -72,6 +79,7 @@ void HardFault_Handler(void)
void SysTick_Handler(void)
{
HAL_IncTick();
+ SysTick_hook();
}
/******************************************************************************/
diff --git a/memfunc.c b/memfunc.c
new file mode 100644
index 0000000..fd94b28
--- /dev/null
+++ b/memfunc.c
@@ -0,0 +1,101 @@
+#include <stdint.h>
+#include <string.h>
+
+/*
+ * Profilable substitutes for mem*(), lacking libc_p.a
+ *
+ * This code was written with reference to newlib, but does not copy every
+ * quirk and loop-unrolling optimization from newlib. Its only purpose is
+ * to let us figure out who is calling memcpy 2 million times.
+ */
+
+#define is_word_aligned(x) (((size_t)(x) & 3) == 0)
+
+void *memcpy(void *dst, const void *src, size_t n)
+{
+ uint8_t *d8 = (uint8_t *)dst;
+ uint8_t *s8 = (uint8_t *)src;
+
+ if (n >= 4 && is_word_aligned(src) && is_word_aligned(dst)) {
+ uint32_t *d32 = (uint32_t *)dst;
+ uint32_t *s32 = (uint32_t *)src;
+ while (n >= 4) {
+ *d32++ = *s32++;
+ n -= 4;
+ }
+ d8 = (uint8_t *)d32;
+ s8 = (uint8_t *)s32;
+ }
+ while (n-- > 0) {
+ *d8++ = *s8++;
+ }
+
+ return dst;
+}
+
+void *memset(void *dst, int c, size_t n)
+{
+ uint8_t *d8 = (uint8_t *)dst;
+ uint8_t c8 = (uint8_t)c;
+
+ if (n >= 4 && is_word_aligned(dst)) {
+ uint32_t *d32 = (uint32_t *)dst;
+ uint32_t c32 = (c8 << 24) | (c8 << 16) | (c8 << 8) | (c8);
+ while (n >= 4) {
+ *d32++ = c32;
+ n -= 4;
+ }
+ d8 = (uint8_t *)d32;
+ }
+ while (n-- > 0) {
+ *d8++ = c8;
+ }
+
+ return dst;
+}
+
+int memcmp(const void *dst, const void *src, size_t n)
+{
+ uint8_t *d8 = (uint8_t *)dst;
+ uint8_t *s8 = (uint8_t *)src;
+
+ if (n >= 4 && is_word_aligned(src) && is_word_aligned(dst)) {
+ uint32_t *d32 = (uint32_t *)dst;
+ uint32_t *s32 = (uint32_t *)src;
+ while (n >= 4) {
+ if (*d32 != *s32)
+ break;
+ d32++;
+ s32++;
+ n -= 4;
+ }
+ d8 = (uint8_t *)d32;
+ s8 = (uint8_t *)s32;
+ }
+ while (n-- > 0) {
+ if (*d8 != *s8)
+ return (*d8 - *s8);
+ d8++;
+ s8++;
+ }
+
+ return 0;
+}
+
+void *memmove(void *dst, const void *src, size_t n)
+{
+ uint8_t *d8 = (uint8_t *)dst;
+ uint8_t *s8 = (uint8_t *)src;
+
+ if ((s8 < d8) && (d8 < s8 + n)) {
+ /* Destructive overlap...have to copy backwards */
+ s8 += n;
+ d8 += n;
+ while (n-- > 0) {
+ *--d8 = *--s8;
+ }
+ return dst;
+ }
+
+ return memcpy(dst, src, n);
+}
diff --git a/projects/hsm/Makefile b/projects/hsm/Makefile
index ecd1a5d..9a75b92 100644
--- a/projects/hsm/Makefile
+++ b/projects/hsm/Makefile
@@ -9,11 +9,8 @@ OBJS = mgmt-cli.o \
mgmt-masterkey.o \
mgmt-misc.o \
mgmt-task.o \
- log.o
-
-BOARD_OBJS += $(TOPLEVEL)/task.o
-
-CFLAGS += -DTASK_METRICS
+ log.o \
+ $(TOPLEVEL)/task.o
CFLAGS += -DNUM_RPC_TASK=4
@@ -23,10 +20,24 @@ CFLAGS += -I$(LIBCLI_SRC)
LIBS += $(LIBHAL_BLD)/libhal.a $(LIBTFM_BLD)/libtfm.a
LIBS += $(LIBCLI_BLD)/libcli.a
+LDFLAGS += -mcpu=cortex-m4 -mthumb -mlittle-endian -mthumb-interwork
+LDFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
+LDFLAGS += -Wl,--gc-sections
+
+ifdef DO_PROFILING
+OBJS += $(TOPLEVEL)/memfunc.o
+LIBS += $(LIBPROF_BLD)/libprof.a
+LDFLAGS += --specs=rdimon.specs -lc -lrdimon
+endif
+
+ifdef DO_TASK_METRICS
+CFLAGS += -DDO_TASK_METRICS
+endif
+
all: $(PROJ:=.elf)
%.elf: %.o $(BOARD_OBJS) $(OBJS) $(LIBS)
- $(CC) $(CFLAGS) $^ -o $@ -T$(LDSCRIPT) -g -Wl,-Map=$*.map
+ $(CC) $^ -o $@ -T$(LDSCRIPT) -g -Wl,-Map=$*.map $(LDFLAGS)
$(OBJCOPY) -O binary $*.elf $*.bin
$(SIZE) $*.elf
diff --git a/projects/hsm/mgmt-misc.c b/projects/hsm/mgmt-misc.c
index ccd032b..016d7cb 100644
--- a/projects/hsm/mgmt-misc.c
+++ b/projects/hsm/mgmt-misc.c
@@ -113,6 +113,25 @@ int cli_receive_data(struct cli_def *cli, uint8_t *buf, size_t len, cli_data_cal
return CLI_ERROR;
}
+#ifdef DO_PROFILING
+static int cmd_profile_start(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ extern uint32_t CRYPTECH_FIRMWARE_START;
+ extern char __etext; /* end of text/code symbol, defined by linker */
+ extern void monstartup (size_t lowpc, size_t highpc);
+ monstartup((size_t)&CRYPTECH_FIRMWARE_START, (size_t)&__etext);
+ return CLI_OK;
+}
+
+static int cmd_profile_stop(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ extern void _mcleanup(void);
+ _mcleanup();
+ return CLI_OK;
+}
+
+#endif
+
static int cmd_reboot(struct cli_def *cli, const char *command, char *argv[], int argc)
{
cli_print(cli, "\n\n\nRebooting\n\n\n");
@@ -124,6 +143,15 @@ static int cmd_reboot(struct cli_def *cli, const char *command, char *argv[], in
void configure_cli_misc(struct cli_def *cli)
{
+#ifdef DO_PROFILING
+ struct cli_command *c_profile = cli_register_command(cli, NULL, "profile", NULL, 0, 0, NULL);
+
+ /* profile start */
+ cli_register_command(cli, c_profile, "start", cmd_profile_start, 0, 0, "Start collecting profiling data");
+
+ /* profile stop */
+ cli_register_command(cli, c_profile, "stop", cmd_profile_stop, 0, 0, "Stop collecting profiling data");
+#endif
/* reboot */
cli_register_command(cli, NULL, "reboot", cmd_reboot, 0, 0, "Reboot the STM32");
}
diff --git a/projects/hsm/mgmt-task.c b/projects/hsm/mgmt-task.c
index 12ce2b8..1658a80 100644
--- a/projects/hsm/mgmt-task.c
+++ b/projects/hsm/mgmt-task.c
@@ -69,7 +69,7 @@ static int cmd_task_show(struct cli_def *cli, const char *command, char *argv[],
return CLI_OK;
}
-#ifdef TASK_METRICS
+#ifdef DO_TASK_METRICS
static int cmd_task_show_metrics(struct cli_def *cli, const char *command, char *argv[], int argc)
{
struct task_metrics tm;
@@ -97,7 +97,7 @@ void configure_cli_task(struct cli_def *cli)
/* task show */
struct cli_command *c_show = cli_register_command(cli, c, "show", cmd_task_show, 0, 0, "Show the active tasks");
-#ifdef TASK_METRICS
+#ifdef DO_TASK_METRICS
/* task show metrics */
cli_register_command(cli, c_show, "metrics", cmd_task_show_metrics, 0, 0, "Show task metrics");
diff --git a/syscalls.c b/syscalls.c
index d7b7211..1624454 100644
--- a/syscalls.c
+++ b/syscalls.c
@@ -48,6 +48,7 @@
/***************************************************************************/
+#ifndef DO_PROFILING
int _read_r (struct _reent *r, int file, char * ptr, int len)
{
r = r;
@@ -103,6 +104,7 @@ int _close_r (struct _reent *r, int file)
{
return 0;
}
+#endif
/***************************************************************************/
@@ -143,6 +145,7 @@ caddr_t _sbrk_r (struct _reent *r, int incr)
/***************************************************************************/
+#ifndef DO_PROFILING
int _fstat_r (struct _reent *r, int file, struct stat * st)
{
r = r;
@@ -181,6 +184,7 @@ int _kill (int a, int b)
return 0;
}
+#endif
/***************************************************************************/
@@ -193,6 +197,7 @@ int _getpid(int a)
/***************************************************************************/
+#ifndef DO_PROFILING
int _open(int a, int b)
{
a = a;
@@ -200,5 +205,6 @@ int _open(int a, int b)
return 0;
}
+#endif
/*** EOF ***/
diff --git a/task.c b/task.c
index e156940..b0028e7 100644
--- a/task.c
+++ b/task.c
@@ -81,7 +81,7 @@ static tcb_t *cur_task = NULL;
#define STACK_GUARD_WORD 0x55AA5A5A
-#ifdef TASK_METRICS
+#ifdef DO_TASK_METRICS
static uint32_t tick_start = 0;
static uint32_t tick_prev = 0;
static uint32_t tick_idle = 0;
@@ -188,7 +188,7 @@ void task_yield(void)
if (tail == NULL)
return;
-#ifdef TASK_METRICS
+#ifdef DO_TASK_METRICS
uint32_t tick0 = HAL_GetTick();
#endif
@@ -209,7 +209,7 @@ void task_yield(void)
* } while (next == NULL);
*/
-#ifdef TASK_METRICS
+#ifdef DO_TASK_METRICS
uint32_t tick = HAL_GetTick();
tick_idle += (tick - tick0);
if (tick_start == 0)
@@ -381,7 +381,7 @@ void task_mutex_unlock(task_mutex_t *mutex)
mutex->locked = 0;
}
-#ifdef TASK_METRICS
+#ifdef DO_TASK_METRICS
void task_get_metrics(struct task_metrics *tm)
{
if (tm != NULL) {
diff --git a/task.h b/task.h
index 24f87ce..de3e275 100644
--- a/task.h
+++ b/task.h
@@ -73,7 +73,7 @@ extern void task_delay(uint32_t delay);
extern void task_mutex_lock(task_mutex_t *mutex);
extern void task_mutex_unlock(task_mutex_t *mutex);
-#ifdef TASK_METRICS
+#ifdef DO_TASK_METRICS
#include <sys/time.h>
struct task_metrics {