Semihosted file handles for targets without DEVICE_SEMIHOST or DEVICE_LOCALFILESYSTEM

Dependents:   SemihostingTest

Files at this revision

API Documentation at this revision

Comitter:
devanlai
Date:
Wed Oct 11 23:14:14 2017 +0000
Commit message:
Initial Semihosting file I/O shim for devices without DEVICE_SEMIHOST and DEVICE_LOCALFILESYSTEM

Changed in this revision

SemihostedFileSystem.cpp Show annotated file Show diff for this revision Revisions of this file
SemihostedFileSystem.h Show annotated file Show diff for this revision Revisions of this file
mbed_semihost_api_shim.c Show annotated file Show diff for this revision Revisions of this file
mbed_semihost_api_shim.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r d5e731da01f0 SemihostedFileSystem.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SemihostedFileSystem.cpp	Wed Oct 11 23:14:14 2017 +0000
@@ -0,0 +1,179 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "SemihostedFileSystem.h"
+#include "mbed_semihost_api_shim.h"
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <cstdarg>
+
+#define STRING_STACK_LIMIT    120
+
+#define OPEN_R          0
+#define OPEN_B          1
+#define OPEN_PLUS       2
+#define OPEN_W          4
+#define OPEN_A          8
+#define OPEN_INVALID   -1
+
+static int posix_to_semihost_open_flags(int flags) {
+    /* POSIX flags -> semihosting open mode */
+    int openmode;
+    if (flags & O_RDWR) {
+        /* a plus mode */
+        openmode = OPEN_PLUS;
+        if (flags & O_APPEND) {
+            openmode |= OPEN_A;
+        } else if (flags & O_TRUNC) {
+            openmode |= OPEN_W;
+        } else {
+            openmode |= OPEN_R;
+        }
+    } else if (flags & O_WRONLY) {
+        /* write or append */
+        if (flags & O_APPEND) {
+            openmode = OPEN_A;
+        } else {
+            openmode = OPEN_W;
+        }
+    } else if (flags == O_RDONLY) {
+        /* read mode */
+        openmode = OPEN_R;
+    } else {
+        /* invalid flags */
+        openmode = OPEN_INVALID;
+    }
+
+    return openmode;
+}
+
+FILEHANDLE semihosted_file_open(const char* name, int flags) {
+    int openmode = posix_to_semihost_open_flags(flags);
+    if (openmode == OPEN_INVALID) {
+        return (FILEHANDLE)NULL;
+    }
+
+    FILEHANDLE fh = semihost_open(name, openmode);
+    if (fh == -1) {
+        return (FILEHANDLE)NULL;
+    }
+
+    return fh;
+}
+
+SemihostedFileHandle::SemihostedFileHandle(FILEHANDLE fh) : _fh(fh), pos(0) {
+    // No lock needed in constructor
+}
+
+SemihostedFileHandle::SemihostedFileHandle(const char* name, int flags)
+    : _fh(semihosted_file_open(name, flags)), pos(0) {
+    // No lock needed in constructor
+}
+
+int SemihostedFileHandle::close() {
+    int retval = semihost_close(_fh);
+    delete this;
+    return retval;
+}
+
+ssize_t SemihostedFileHandle::write(const void *buffer, size_t length) {
+    lock();
+    ssize_t n = semihost_write(_fh, (const unsigned char*)buffer, length, 0); // number of characters not written
+    n = length - n; // number of characters written
+    pos += n;
+    unlock();
+    return n;
+}
+
+ssize_t SemihostedFileHandle::read(void *buffer, size_t length) {
+    lock();
+    ssize_t n = semihost_read(_fh, (unsigned char*)buffer, length, 0); // number of characters not read
+    n = length - n; // number of characters read
+    pos += n;
+    unlock();
+    return n;
+}
+
+int SemihostedFileHandle::isatty() {
+    lock();
+    int ret = semihost_istty(_fh);
+    unlock();
+    return ret;
+}
+
+off_t SemihostedFileHandle::seek(off_t position, int whence) {
+    lock();
+    if (whence == SEEK_CUR) {
+        position += pos;
+    } else if (whence == SEEK_END) {
+        position += semihost_flen(_fh);
+    } /* otherwise SEEK_SET, so position is fine */
+
+    /* Always seems to return -1, so just ignore for now. */
+    semihost_seek(_fh, position);
+    pos = position;
+    unlock();
+    return position;
+}
+
+int SemihostedFileHandle::sync() {
+    lock();
+    int ret = semihost_ensure(_fh);
+    unlock();
+    return ret;
+}
+
+off_t SemihostedFileHandle::size() {
+    lock();
+    off_t off = semihost_flen(_fh);
+    unlock();
+    return off;
+}
+
+void SemihostedFileHandle::lock() {
+    _mutex.lock();
+}
+
+void SemihostedFileHandle::unlock() {
+    _mutex.unlock();
+}
+
+// Experimental support for printf in RawSerial. No Stream inheritance
+// means we can't call printf() directly, so we use sprintf() instead.
+// We only call malloc() for the sprintf() buffer if the buffer
+// length is above a certain threshold, otherwise we use just the stack.
+int SemihostedFileHandle::printf(const char *format, ...) {
+    lock();
+    std::va_list arg;
+    va_start(arg, format);
+    // ARMCC microlib does not properly handle a size of 0.
+    // As a workaround supply a dummy buffer with a size of 1.
+    char dummy_buf[1];
+    int len = vsnprintf(dummy_buf, sizeof(dummy_buf), format, arg);
+    if (len < STRING_STACK_LIMIT) {
+        char temp[STRING_STACK_LIMIT];
+        vsprintf(temp, format, arg);
+        write(temp, len);
+    } else {
+        char *temp = new char[len + 1];
+        vsprintf(temp, format, arg);
+        write(temp, len);
+        delete[] temp;
+    }
+    va_end(arg);
+    unlock();
+    return len;
+}
\ No newline at end of file
diff -r 000000000000 -r d5e731da01f0 SemihostedFileSystem.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SemihostedFileSystem.h	Wed Oct 11 23:14:14 2017 +0000
@@ -0,0 +1,65 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef SEMIHOSTEDFILESYSTEM_H
+#define SEMIHOSTEDFILESYSTEM_H
+
+#include "platform/platform.h"
+
+#include "platform/FileSystemLike.h"
+#include "platform/PlatformMutex.h"
+#include "platform/NonCopyable.h"
+
+/** \addtogroup platform */
+/** @{*/
+
+FILEHANDLE semihosted_file_open(const char* name, int flags);
+/** @}*/
+
+/**
+ * @class SemihostedFileHandle
+ * @ingroup platform
+ */
+class SemihostedFileHandle : public mbed::FileHandle, private mbed::NonCopyable<SemihostedFileHandle> {
+
+public:
+    SemihostedFileHandle(FILEHANDLE fh);
+    SemihostedFileHandle(const char* name, int flags);
+
+    virtual int close();
+
+    virtual ssize_t write(const void *buffer, size_t length);
+
+    virtual ssize_t read(void *buffer, size_t length);
+
+    virtual int isatty();
+
+    virtual off_t seek(off_t position, int whence);
+
+    virtual int sync();
+
+    virtual off_t size();
+    
+    int printf(const char *format, ...);
+
+protected:
+    virtual void lock();
+    virtual void unlock();
+    FILEHANDLE _fh;
+    int pos;
+    PlatformMutex _mutex;
+};
+
+#endif
diff -r 000000000000 -r d5e731da01f0 mbed_semihost_api_shim.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed_semihost_api_shim.c	Wed Oct 11 23:14:14 2017 +0000
@@ -0,0 +1,101 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "cmsis.h"
+#include "mbed_semihost_api_shim.h"
+
+#include <stdint.h>
+#include <string.h>
+
+// ARM Semihosting Commands
+#define SYS_OPEN   (0x1)
+#define SYS_CLOSE  (0x2)
+#define SYS_WRITE  (0x5)
+#define SYS_READ   (0x6)
+#define SYS_ISTTY  (0x9)
+#define SYS_SEEK   (0xa)
+#define SYS_ENSURE (0xb)
+#define SYS_FLEN   (0xc)
+#define SYS_REMOVE (0xe)
+#define SYS_RENAME (0xf)
+#define SYS_EXIT   (0x18)
+
+#if !DEVICE_LOCALFILESYSTEM
+FILEHANDLE semihost_open(const char* name, int openmode) {
+    uint32_t args[3];
+    args[0] = (uint32_t)name;
+    args[1] = (uint32_t)openmode;
+    args[2] = (uint32_t)strlen(name);
+    return __semihost(SYS_OPEN, args);
+}
+
+int semihost_close(FILEHANDLE fh) {
+    return __semihost(SYS_CLOSE, &fh);
+}
+
+int semihost_write(FILEHANDLE fh, const unsigned char* buffer, unsigned int length, int mode) {
+    if (length == 0) return 0;
+
+    uint32_t args[3];
+    args[0] = (uint32_t)fh;
+    args[1] = (uint32_t)buffer;
+    args[2] = (uint32_t)length;
+    return __semihost(SYS_WRITE, args);
+}
+
+int semihost_read(FILEHANDLE fh, unsigned char* buffer, unsigned int length, int mode) {
+    uint32_t args[3];
+    args[0] = (uint32_t)fh;
+    args[1] = (uint32_t)buffer;
+    args[2] = (uint32_t)length;
+    return __semihost(SYS_READ, args);
+}
+
+int semihost_istty(FILEHANDLE fh) {
+    return __semihost(SYS_ISTTY, &fh);
+}
+
+int semihost_seek(FILEHANDLE fh, long position) {
+    uint32_t args[2];
+    args[0] = (uint32_t)fh;
+    args[1] = (uint32_t)position;
+    return __semihost(SYS_SEEK, args);
+}
+
+int semihost_ensure(FILEHANDLE fh) {
+    return __semihost(SYS_ENSURE, &fh);
+}
+
+long semihost_flen(FILEHANDLE fh) {
+    return __semihost(SYS_FLEN, &fh);
+}
+
+int semihost_remove(const char *name) {
+    uint32_t args[2];
+    args[0] = (uint32_t)name;
+    args[1] = (uint32_t)strlen(name);
+    return __semihost(SYS_REMOVE, args);
+}
+
+int semihost_rename(const char *old_name, const char *new_name) {
+    uint32_t args[4];
+    args[0] = (uint32_t)old_name;
+    args[1] = (uint32_t)strlen(old_name);
+    args[0] = (uint32_t)new_name;
+    args[1] = (uint32_t)strlen(new_name);
+    return __semihost(SYS_RENAME, args);
+}
+
+#endif
diff -r 000000000000 -r d5e731da01f0 mbed_semihost_api_shim.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed_semihost_api_shim.h	Wed Oct 11 23:14:14 2017 +0000
@@ -0,0 +1,51 @@
+
+/** \addtogroup platform */
+/** @{*/
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef MBED_SEMIHOST_SHIM_H
+#define MBED_SEMIHOST_SHIM_H
+
+#include "device.h"
+#include "platform/mbed_toolchain.h"
+
+#include "platform/mbed_semihost_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !DEVICE_LOCALFILESYSTEM
+FILEHANDLE semihost_open(const char* name, int openmode);
+int semihost_close (FILEHANDLE fh);
+int semihost_read  (FILEHANDLE fh, unsigned char* buffer, unsigned int length, int mode);
+int semihost_write (FILEHANDLE fh, const unsigned char* buffer, unsigned int length, int mode);
+int semihost_ensure(FILEHANDLE fh);
+long semihost_flen (FILEHANDLE fh);
+int semihost_seek  (FILEHANDLE fh, long position);
+int semihost_istty (FILEHANDLE fh);
+
+int semihost_remove(const char *name);
+int semihost_rename(const char *old_name, const char *new_name);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/** @}*/
\ No newline at end of file