[Cbe-oss-dev] [PATCH 2/2] libspe2: Add emulated isolated mode support
Jeremy Kerr
jk at ozlabs.org
Wed May 30 21:01:16 EST 2007
Using a userspace loader, we can add an 'emulated' isolated mode, which
provides a facility to run contexts with an isolated-mode environment,
but without restricted access to SPE hardware. Contexts can be created
in emulated isolated mode by providing the SPE_ISOLATE_EMULATE flag to
spe_context_create.
This functionality depends on an emulated loader - a SPE program to
load the "emulated isolated" SPE application, using the same ABI as the
real isolated mode loader. We check for this in the file:
$libdir/spe/emulated-loader.bin
- if this isn't present (or isn't a valid SPE binary) then we refuse to
create emulated-isolated contexts.
Signed-off-by: Jeremy Kerr <jk at ozlabs.org>
libspe2-types.h | 1
spebase/Makefile | 3 +
spebase/create.c | 7 ++++
spebase/lib_builtin.c | 6 +++
spebase/load.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++--
spebase/run.c | 30 ++++++++++++++----
spebase/spebase.h | 16 +++++++++
7 files changed, 135 insertions(+), 9 deletions(-)
Index: libspe2/spebase/Makefile
===================================================================
--- libspe2.orig/spebase/Makefile
+++ libspe2/spebase/Makefile
@@ -23,6 +23,7 @@ include $(TOP)/make.defines
MAJOR_VERSION := 2
MINOR_VERSION := 0.0
+EMULATED_LOADER := $(libdir)/spe/emulated-loader.bin
libspebase_A := libspebase.a
libspebase_SO := libspebase.so.${MAJOR_VERSION}.${MINOR_VERSION}
@@ -35,6 +36,8 @@ libspebase_OBJS := create.o elf_loader.
CFLAGS += -I..
CFLAGS += -D_ATFILE_SOURCE
+load.o: CPPFLAGS+='-DSPE_EMULATED_LOADER_FILE="$(EMULATED_LOADER)"'
+
all: $(libspebase_SO) $(libspebase_A)
install-so: $(libspebase_SO) $(libspebase_A)
Index: libspe2/libspe2-types.h
===================================================================
--- libspe2.orig/libspe2-types.h
+++ libspe2/libspe2-types.h
@@ -176,6 +176,7 @@ enum ps_area { SPE_MSSYNC_AREA, SPE_MFC_
#define SPE_CFG_SIGNOTIFY2_OR 0x00000020
#define SPE_MAP_PS 0x00000040
#define SPE_ISOLATE 0x00000080
+#define SPE_ISOLATE_EMULATE 0x00000100
#define SPE_EVENTS_ENABLE 0x00001000
#define SPE_AFFINITY_MEMORY 0x00002000
Index: libspe2/spebase/load.c
===================================================================
--- libspe2.orig/spebase/load.c
+++ libspe2/spebase/load.c
@@ -26,6 +26,10 @@
#include "elf_loader.h"
#include "spebase.h"
+#ifndef SPE_EMULATED_LOADER_FILE
+#define SPE_EMULATED_LOADER_FILE "/usr/lib/spe/emulated-loader.bin"
+#endif
+
/**
* Send data to a SPU in mbox when space is available.
*
@@ -86,6 +90,74 @@ static int spe_start_isolated_app(struct
return 0;
}
+/**
+ * Load the emulated isolation loader program from the filesystem
+ *
+ * @return The loader program, or NULL if it can't be loaded. The loader binary
+ * is cached between calls.
+ */
+static spe_program_handle_t *emulated_loader_program(void)
+{
+ static spe_program_handle_t *loader = NULL;
+
+ if (!loader)
+ loader = _base_spe_image_open(SPE_EMULATED_LOADER_FILE);
+
+ if (!loader)
+ DEBUG_PRINTF("Can't load emulated loader '%s': %s\n",
+ SPE_EMULATED_LOADER_FILE, strerror(errno));
+
+ return loader;
+}
+
+/**
+ * Check if the emulated loader is present in the filesystem
+ * @return Non-zero if the loader is available, otherwise zero.
+ */
+int _base_spe_emulated_loader_present(void)
+{
+ spe_program_handle_t *loader = emulated_loader_program();
+
+ if (!loader)
+ return 0;
+
+ return !verify_spe_elf_image(loader);
+}
+
+/**
+ * Initiate transfer of an emulated isolated SPE app by the loader kernel.
+ *
+ * Helper function for internal libspe use.
+ *
+ * @param thread The SPE thread to load the app to
+ * @param handle The handle to the (isolated) spe program
+ * @param ld_info[out] Loader information about the entry point of the SPE.
+ * This will reference the loader, not the SPE program, as
+ * we will be running the loader first.
+ * @return zero on success, non-zero on failure;
+ */
+static int spe_start_emulated_isolated_app(struct spe_context *spe,
+ spe_program_handle_t *handle, struct spe_ld_info *ld_info)
+
+{
+ int rc;
+ spe_program_handle_t *loader;
+
+ /* load emulated loader from the filesystem */
+ loader = emulated_loader_program();
+
+ if (!loader)
+ return -1;
+
+ rc = load_spe_elf(loader, spe->base_private->mem_mmap_base, ld_info);
+ if (rc != 0) {
+ DEBUG_PRINTF("%s: No loader available\n", __FUNCTION__);
+ return rc;
+ }
+
+ return spe_start_isolated_app(spe, handle);
+}
+
int _base_spe_program_load(spe_context_ptr_t spe, spe_program_handle_t *program)
{
int rc = 0, objfd;
@@ -93,6 +165,10 @@ int _base_spe_program_load(spe_context_p
if (spe->base_private->flags & SPE_ISOLATE) {
rc = spe_start_isolated_app(spe, program);
+
+ } else if (spe->base_private->flags & SPE_ISOLATE_EMULATE) {
+ rc = spe_start_emulated_isolated_app(spe, program, &ld_info);
+
} else {
rc = load_spe_elf(program, spe->base_private->mem_mmap_base,
&ld_info);
@@ -114,7 +190,8 @@ int _base_spe_program_load(spe_context_p
__spe_context_update_event();
- spe->base_private->entry=ld_info.entry;
-
+ spe->base_private->entry = ld_info.entry;
+ spe->base_private->emulated_entry = ld_info.entry;
+
return 0;
}
Index: libspe2/spebase/create.c
===================================================================
--- libspe2.orig/spebase/create.c
+++ libspe2/spebase/create.c
@@ -189,6 +189,13 @@ spe_context_ptr_t _base_spe_context_crea
struct spe_context *spe = NULL;
struct spe_context_base_priv *priv;
+ /* We need a loader present to run in emulated isolated mode */
+ if (flags & SPE_ISOLATE_EMULATE
+ && !_base_spe_emulated_loader_present()) {
+ errno = EINVAL;
+ return NULL;
+ }
+
/* Put some sane defaults into the SPE context */
spe = malloc(sizeof(*spe));
if (!spe) {
Index: libspe2/spebase/spebase.h
===================================================================
--- libspe2.orig/spebase/spebase.h
+++ libspe2/spebase/spebase.h
@@ -91,6 +91,10 @@ struct spe_context_base_priv {
/* SPE program entry point generated by elf_load() */
int entry;
+
+ /* We need to keep the entry point for emulated isolated contexts,
+ * and ignore the value provided to spe_context_run */
+ int emulated_entry;
};
@@ -110,6 +114,12 @@ struct spe_context_base_priv {
#define SIGNAL1_OFFSET 0x14000
#define SIGNAL2_OFFSET 0x1c000
+/**
+ * Starting address (ie, offset from the local store base) of the "open area" -
+ * a small region of memory accessible when a SPE is in isolated mode.
+ */
+#define SPE_ISOLATE_LS_OPEN_AREA 0x3e000
+
/*
*/
#define SPE_PROGRAM_NORMAL_END 0x2000
@@ -168,6 +178,12 @@ extern spe_gang_context_ptr_t _base_spe_
extern int _base_spe_program_load(spe_context_ptr_t spectx, spe_program_handle_t *program);
/**
+ * Check if the emulated loader is present in the filesystem
+ * @return Non-zero if the loader is available, otherwise zero.
+ */
+int _base_spe_emulated_loader_present(void);
+
+/**
* _base_spe_context_destroy cleans up what is left when an SPE executable has exited.
* Closes open file handles and unmaps memory areas.
*
Index: libspe2/spebase/run.c
===================================================================
--- libspe2.orig/spebase/run.c
+++ libspe2/spebase/run.c
@@ -77,7 +77,7 @@ int _base_spe_context_run(spe_context_pt
spe_stop_info_t *stopinfo)
{
int retval = 0, run_rc;
- unsigned int run_status;
+ unsigned int run_status, tmp_entry;
spe_stop_info_t stopinfo_buf;
/* If the caller hasn't set a stopinfo buffer, provide a buffer on the
@@ -85,13 +85,20 @@ int _base_spe_context_run(spe_context_pt
if (!stopinfo)
stopinfo = &stopinfo_buf;
- if (*entry == SPE_DEFAULT_ENTRY)
- *entry = spe->base_private->entry;
+
+ /* In emulated isolated mode, the npc will always return as zero.
+ * use our private entry point instead */
+ if (spe->base_private->flags & SPE_ISOLATE_EMULATE)
+ tmp_entry = spe->base_private->emulated_entry;
+
+ else if (*entry == SPE_DEFAULT_ENTRY)
+ tmp_entry = spe->base_private->entry;
/* If we're starting the SPE binary from its original entry point,
* setup the arguments to main() */
- if (*entry == spe->base_private->entry &&
- !(spe->base_private->flags & SPE_ISOLATE)) {
+ if (tmp_entry == spe->base_private->entry &&
+ !(spe->base_private->flags &
+ (SPE_ISOLATE | SPE_ISOLATE_EMULATE))) {
addr64 argp64, envp64, tid64;
unsigned int regs[128][4];
@@ -127,16 +134,25 @@ int _base_spe_context_run(spe_context_pt
do_run:
/* run SPE context */
- run_rc = spu_run(spe->base_private->fd_spe_dir, entry, &run_status);
+ run_rc = spu_run(spe->base_private->fd_spe_dir,
+ &tmp_entry, &run_status);
DEBUG_PRINTF("spu_run returned run_rc=0x%08x, entry=0x%04x, "
- "ext_status=0x%04x.\n", run_rc, *entry, run_status);
+ "ext_status=0x%04x.\n", run_rc, tmp_entry, run_status);
/* set up return values and stopinfo according to spu_run exit
* conditions. This is overwritten on error.
*/
stopinfo->spu_status = run_rc;
+ if (spe->base_private->flags & SPE_ISOLATE_EMULATE) {
+ /* save the entry point, and pretend that the npc is zero */
+ spe->base_private->emulated_entry = tmp_entry;
+ *entry = 0;
+ } else {
+ *entry = tmp_entry;
+ }
+
/* Return with stopinfo set on syscall error paths */
if (run_rc == -1) {
DEBUG_PRINTF("spu_run returned error %d, errno=%d\n",
Index: libspe2/spebase/lib_builtin.c
===================================================================
--- libspe2.orig/spebase/lib_builtin.c
+++ libspe2/spebase/lib_builtin.c
@@ -150,6 +150,12 @@ int handle_library_callback(struct spe_c
handler=handlers[callnum];
+ /* In isolated mode, accesses to the local store are wrapped to the
+ * "open area". Emulate that behaviour by moving the npc (which
+ * should be 0) up to the open area range */
+ if (spe->base_private->flags & SPE_ISOLATE_EMULATE)
+ npc |= SPE_ISOLATE_LS_OPEN_AREA;
+
rc = handler(spe->base_private->mem_mmap_base, npc);
if (rc) {
DEBUG_PRINTF ("SPE library call unsupported.\n");
More information about the cbe-oss-dev
mailing list