You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by an...@apache.org on 2017/12/18 13:55:10 UTC

[mynewt-nimble] branch freertos-port updated (4417a34 -> c1b8508)

This is an automated email from the ASF dual-hosted git repository.

andk pushed a change to branch freertos-port
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git.


 discard 4417a34  porting: Add FreeRTOS port (based on nRF5 SDK)
     new c1b8508  porting: Add FreeRTOS port (based on nRF5 SDK)

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (4417a34)
            \
             N -- N -- N   refs/heads/freertos-port (c1b8508)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 porting/freertos_nrf5_sdk/Makefile                 |  514 ++++-----
 .../freertos_nrf5_sdk/nimble_FreeRTOS_gcc_nrf52.ld |   70 +-
 porting/freertos_nrf5_sdk/src/ble_task.c           |   19 +
 porting/freertos_nrf5_sdk/src/hci_transport.c      | 1150 --------------------
 porting/freertos_nrf5_sdk/src/main.c               |   69 +-
 5 files changed, 330 insertions(+), 1492 deletions(-)
 delete mode 100755 porting/freertos_nrf5_sdk/src/hci_transport.c

-- 
To stop receiving notification emails like this one, please contact
['"commits@mynewt.apache.org" <co...@mynewt.apache.org>'].

[mynewt-nimble] 01/01: porting: Add FreeRTOS port (based on nRF5 SDK)

Posted by an...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

andk pushed a commit to branch freertos-port
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git

commit c1b85089e0c11a32cb26a115433f286aa13697f7
Author: Andrzej Kaczmarek <an...@codecoup.pl>
AuthorDate: Wed Dec 6 10:36:40 2017 +0100

    porting: Add FreeRTOS port (based on nRF5 SDK)
    
    This patch adds port of Nimble stack to FreeRTOS based on nRF5 SDK.
    It's split into 'common' part which can be used a base for porting to
    any other platform and 'freertos_nrf5_sdk' which has FreeRTOS-specific
    files and makefile.
    
    Building and flashing is similar to other demo apps from nRF5 SDK:
    $ make -C porting/freertos_nrf5_sdk
    
    The resulting image can be flashed on nRF52 DK:
    $ make -C porting/freertos_nrf5_sdk flash
    
    Location of nRF5 SDK is set by NRF5_SDK_ROOT variable. By default it is
    set to 'nrf5_sdk' subdirectory so a symlink would work just fine:
    $ ln -s <x>/nRF5_SDK_12.3.0_d7731ad porting/freertos_nrf5_sdk/nrf5_sdk
---
 .gitignore                                         |    3 +
 porting/common/include/bsp/bsp.h                   |   14 +
 porting/common/include/console/console.h           |  116 ++
 porting/common/include/hal/hal_timer.h             |  105 ++
 porting/common/include/log/ignore.h                |   64 +
 porting/common/include/log/log.h                   |   89 ++
 porting/common/include/mem/mem.h                   |   66 +
 porting/common/include/nimble_port.h               |   35 +
 porting/common/include/os/endian.h                 |  225 ++++
 porting/common/include/os/os.h                     |   99 ++
 porting/common/include/os/os_arch.h                |   26 +
 porting/common/include/os/os_callout.h             |   62 +
 porting/common/include/os/os_cfg.h                 |   33 +
 porting/common/include/os/os_cputime.h             |  242 ++++
 porting/common/include/os/os_dev.h                 |  123 ++
 porting/common/include/os/os_error.h               |   52 +
 porting/common/include/os/os_eventq.h              |   68 +
 porting/common/include/os/os_fault.h               |   34 +
 porting/common/include/os/os_heap.h                |   38 +
 porting/common/include/os/os_malloc.h              |   42 +
 porting/common/include/os/os_mbuf.h                |  305 +++++
 porting/common/include/os/os_mempool.h             |  108 ++
 porting/common/include/os/os_mutex.h               |   67 +
 porting/common/include/os/os_sanity.h              |   64 +
 porting/common/include/os/os_sched.h               |   54 +
 porting/common/include/os/os_sem.h                 |   66 +
 porting/common/include/os/os_task.h                |  128 ++
 porting/common/include/os/os_test.h                |   33 +
 porting/common/include/os/os_time.h                |  120 ++
 porting/common/include/os/os_trace_api.h           |   84 ++
 porting/common/include/os/queue.h                  |  522 ++++++++
 porting/common/include/stats/stats.h               |   83 ++
 porting/common/include/sysinit/sysinit.h           |  128 ++
 porting/common/src/mem/mem.c                       |  245 ++++
 porting/common/src/nimble_port.c                   |   65 +
 porting/common/src/os/endian.c                     |  218 ++++
 porting/common/src/os/os.c                         |  240 ++++
 porting/common/src/os/os_callout.c                 |  230 ++++
 porting/common/src/os/os_cputime.c                 |  215 +++
 porting/common/src/os/os_cputime_1mhz.c            |   52 +
 porting/common/src/os/os_cputime_high.c            |   84 ++
 porting/common/src/os/os_cputime_pwr2.c            |   90 ++
 porting/common/src/os/os_dev.c                     |  346 +++++
 porting/common/src/os/os_eventq.c                  |  354 +++++
 porting/common/src/os/os_heap.c                    |  124 ++
 porting/common/src/os/os_mbuf.c                    | 1368 ++++++++++++++++++++
 porting/common/src/os/os_mempool.c                 |  321 +++++
 porting/common/src/os/os_msys_init.c               |   88 ++
 porting/common/src/os/os_mutex.c                   |  262 ++++
 porting/common/src/os/os_priv.h                    |   41 +
 porting/common/src/os/os_sanity.c                  |  250 ++++
 porting/common/src/os/os_sched.c                   |  377 ++++++
 porting/common/src/os/os_sem.c                     |  225 ++++
 porting/common/src/os/os_task.c                    |  284 ++++
 porting/common/src/os/os_time.c                    |  268 ++++
 porting/common/src/sysinit/sysinit.c               |   64 +
 porting/freertos_nrf5_sdk/Makefile                 |  257 ++++
 porting/freertos_nrf5_sdk/config/FreeRTOSConfig.h  |  229 ++++
 porting/freertos_nrf5_sdk/config/sdk_config.h      |  699 ++++++++++
 porting/freertos_nrf5_sdk/include/bsp/cmsis_nvic.h |   29 +
 porting/freertos_nrf5_sdk/include/mcu/nrf52_hal.h  |   70 +
 porting/freertos_nrf5_sdk/include/os/os_arch.h     |   25 +
 porting/freertos_nrf5_sdk/include/os/os_callout.h  |   52 +
 porting/freertos_nrf5_sdk/include/os/os_eventq.h   |   67 +
 porting/freertos_nrf5_sdk/include/os/os_mutex.h    |   46 +
 porting/freertos_nrf5_sdk/include/os/os_sem.h      |   27 +
 porting/freertos_nrf5_sdk/include/syscfg/syscfg.h  |  967 ++++++++++++++
 .../freertos_nrf5_sdk/nimble_FreeRTOS_gcc_nrf52.ld |   35 +
 porting/freertos_nrf5_sdk/src/ble_task.c           |  175 +++
 porting/freertos_nrf5_sdk/src/cmsis_nvic.c         |   73 ++
 porting/freertos_nrf5_sdk/src/hal_timer.c          |  932 +++++++++++++
 porting/freertos_nrf5_sdk/src/main.c               |   60 +
 porting/freertos_nrf5_sdk/src/os_port.c            |  348 +++++
 73 files changed, 13200 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..dfb676a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+# note: no / at the end since it could be either symlink or directory
+/porting/freertos_nrf5_sdk/nrf5_sdk
+/porting/freertos_nrf5_sdk/_build/
diff --git a/porting/common/include/bsp/bsp.h b/porting/common/include/bsp/bsp.h
new file mode 100644
index 0000000..60f8a3c
--- /dev/null
+++ b/porting/common/include/bsp/bsp.h
@@ -0,0 +1,14 @@
+#ifndef H_BSP_H
+#define H_BSP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define bssnz_t
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* H_BSP_H */
diff --git a/porting/common/include/console/console.h b/porting/common/include/console/console.h
new file mode 100644
index 0000000..7f9f0ed
--- /dev/null
+++ b/porting/common/include/console/console.h
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 __CONSOLE_H__
+#define __CONSOLE_H__
+
+#include <inttypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct os_eventq;
+
+struct console_input {
+    char line[0];
+};
+
+typedef void (*console_rx_cb)(void);
+typedef int (*console_append_char_cb)(char *line, uint8_t byte);
+typedef void (*completion_cb)(char *str, console_append_char_cb cb);
+
+static int inline
+console_is_init(void)
+{
+    return 0;
+}
+
+static int inline
+console_init(console_rx_cb rx_cb)
+{
+    return 0;
+}
+
+static void inline
+console_write(const char *str, int cnt)
+{
+}
+
+static int inline
+console_read(char *str, int cnt, int *newline)
+{
+    *newline = 0;
+    return 0;
+}
+
+static void inline
+console_blocking_mode(void)
+{
+}
+
+static void inline
+console_non_blocking_mode(void)
+{
+}
+
+static void inline
+console_echo(int on)
+{
+}
+
+static int inline console_printf(const char *fmt, ...)
+    __attribute__ ((format (printf, 1, 2)));
+
+static int inline
+console_printf(const char *fmt, ...)
+{
+    return 0;
+}
+
+static void inline
+console_set_queues(struct os_eventq *avail_queue,
+                   struct os_eventq *cmd_queue)
+{
+}
+
+static void inline
+console_set_completion_cb(void (*completion)(char *str, console_append_char_cb cb))
+{
+}
+
+static int inline
+console_handle_char(uint8_t byte)
+{
+    return 0;
+}
+
+static int inline
+console_out(int character)
+{
+    return 0;
+}
+
+#define console_is_midline  (0)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CONSOLE__ */
+
diff --git a/porting/common/include/hal/hal_timer.h b/porting/common/include/hal/hal_timer.h
new file mode 100644
index 0000000..1937130
--- /dev/null
+++ b/porting/common/include/hal/hal_timer.h
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 H_HAL_TIMER_
+#define H_HAL_TIMER_
+
+#include <inttypes.h>
+#include "os/queue.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <inttypes.h>
+
+#include "os/queue.h"
+
+/* HAL timer struct */
+typedef void (*hal_timer_cb)(void *arg);
+
+/**
+ * The HAL timer structure. The user can declare as many of these structures
+ * as desired. They are enqueued on a particular HW timer queue when the user
+ * calls the hal_timer_start or hal_timer_start_at API. The user must have
+ * called hal_timer_set_cb before starting a timer.
+ *
+ * NOTE: the user should not have to modify/examine the contents of this
+ * structure; the hal timer API should be used.
+ */
+struct hal_timer
+{
+    void                *bsp_timer; /* Internal platform specific pointer */
+    hal_timer_cb        cb_func;    /* Callback function */
+    void                *cb_arg;    /* Callback argument */
+    uint32_t            expiry;     /* Tick at which timer should expire */
+    TAILQ_ENTRY(hal_timer) link;    /* Queue linked list structure */
+};
+
+/* Initialize a HW timer. */
+int hal_timer_init(int timer_num, void *cfg);
+
+/* Un-initialize a HW timer. */
+int hal_timer_deinit(int timer_num);
+
+/*
+ * Config a HW timer at the given frequency and start it. If the exact
+ * frequency is not obtainable the closest obtainable frequency is set.
+ */
+int hal_timer_config(int timer_num, uint32_t freq_hz);
+
+/*
+ * Returns the resolution of the HW timer. NOTE: the frequency may not be
+ * obtainable so the caller can use this to determine the resolution.
+ * Returns resolution in nanoseconds. A return value of 0 indicates an invalid
+ * timer was used.
+ */
+uint32_t hal_timer_get_resolution(int timer_num);
+
+/* Returns the HW timer current tick value */
+uint32_t hal_timer_read(int timer_num);
+
+/* Perform a blocking delay for a number of ticks. */
+int hal_timer_delay(int timer_num, uint32_t ticks);
+
+/*
+ * Set the timer structure prior to use. Should not be called if the timer
+ * is running. Must be called at least once prior to using timer.
+ */
+int hal_timer_set_cb(int timer_num, struct hal_timer *tmr, hal_timer_cb cb_func,
+                     void *arg);
+
+/* Start a timer that will expire in 'ticks' ticks. Ticks cannot be 0 */
+int hal_timer_start(struct hal_timer *, uint32_t ticks);
+
+/*
+ * Start a timer that will expire when the timer reaches 'tick'. If tick
+ * has already passed the timer callback will be called "immediately" (at
+ * interrupt context).
+ */
+int hal_timer_start_at(struct hal_timer *, uint32_t tick);
+
+/* Stop a currently running timer; associated callback will NOT be called */
+int hal_timer_stop(struct hal_timer *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* H_HAL_TIMER_ */
diff --git a/porting/common/include/log/ignore.h b/porting/common/include/log/ignore.h
new file mode 100644
index 0000000..46282a0
--- /dev/null
+++ b/porting/common/include/log/ignore.h
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 H_IGNORE_
+#define H_IGNORE_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * These macros prevent the "set but not used" warnings for log writes below
+ * the log level.
+ */
+
+#define IGN_1(X) ((void)(X))
+#define IGN_2(X, ...) ((void)(X));IGN_1(__VA_ARGS__)
+#define IGN_3(X, ...) ((void)(X));IGN_2(__VA_ARGS__)
+#define IGN_4(X, ...) ((void)(X));IGN_3(__VA_ARGS__)
+#define IGN_5(X, ...) ((void)(X));IGN_4(__VA_ARGS__)
+#define IGN_6(X, ...) ((void)(X));IGN_5(__VA_ARGS__)
+#define IGN_7(X, ...) ((void)(X));IGN_6(__VA_ARGS__)
+#define IGN_8(X, ...) ((void)(X));IGN_7(__VA_ARGS__)
+#define IGN_9(X, ...) ((void)(X));IGN_8(__VA_ARGS__)
+#define IGN_10(X, ...) ((void)(X));IGN_9(__VA_ARGS__)
+#define IGN_11(X, ...) ((void)(X));IGN_10(__VA_ARGS__)
+#define IGN_12(X, ...) ((void)(X));IGN_11(__VA_ARGS__)
+#define IGN_13(X, ...) ((void)(X));IGN_12(__VA_ARGS__)
+#define IGN_14(X, ...) ((void)(X));IGN_13(__VA_ARGS__)
+#define IGN_15(X, ...) ((void)(X));IGN_14(__VA_ARGS__)
+#define IGN_16(X, ...) ((void)(X));IGN_15(__VA_ARGS__)
+#define IGN_17(X, ...) ((void)(X));IGN_16(__VA_ARGS__)
+#define IGN_18(X, ...) ((void)(X));IGN_17(__VA_ARGS__)
+#define IGN_19(X, ...) ((void)(X));IGN_18(__VA_ARGS__)
+#define IGN_20(X, ...) ((void)(X));IGN_19(__VA_ARGS__)
+
+#define GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, \
+                  _13, _14, _15, _16, _17, _18, _19, _20, NAME, ...) NAME
+#define IGNORE(...) \
+    GET_MACRO(__VA_ARGS__, IGN_20, IGN_19, IGN_18, IGN_17, IGN_16, IGN_15, \
+              IGN_14, IGN_13, IGN_12, IGN_11, IGN_10, IGN_9, IGN_8, IGN_7, \
+              IGN_6, IGN_5, IGN_4, IGN_3, IGN_2, IGN_1)(__VA_ARGS__)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/porting/common/include/log/log.h b/porting/common/include/log/log.h
new file mode 100644
index 0000000..ac4d7e7
--- /dev/null
+++ b/porting/common/include/log/log.h
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 __SYS_LOG_STUB_H__
+#define __SYS_LOG_STUB_H__
+
+#include <inttypes.h>
+#include "syscfg/syscfg.h"
+#include "log/ignore.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LOG_DEBUG(__l, __mod, ...) IGNORE(__VA_ARGS__)
+#define LOG_INFO(__l, __mod, ...) IGNORE(__VA_ARGS__)
+#define LOG_WARN(__l, __mod, ...) IGNORE(__VA_ARGS__)
+#define LOG_ERROR(__l, __mod, ...) IGNORE(__VA_ARGS__)
+#define LOG_CRITICAL(__l, __mod, ...) IGNORE(__VA_ARGS__)
+
+#define LOG_LEVEL_DEBUG         0
+#define LOG_LEVEL_INFO          1
+#define LOG_LEVEL_WARN          2
+#define LOG_LEVEL_ERROR         3
+#define LOG_LEVEL_CRITICAL      4
+/* Up to 7 custom log levels. */
+#define LOG_LEVEL_MAX           UINT8_MAX
+#define LOG_SYSLEVEL            UINT8_MAX
+
+/* Logging medium */
+#define LOG_STORE_CONSOLE    1
+#define LOG_STORE_CBMEM      2
+#define LOG_STORE_FCB        3
+
+/* Global log info */
+struct log_info {
+    uint32_t li_next_index;
+    uint8_t li_version;
+};
+
+struct log_info g_log_info;
+
+struct log {
+};
+
+struct log_handler {
+};
+
+static inline int
+log_register(char *name, struct log *log, const struct log_handler *h,
+             void *arg, uint8_t level)
+{
+    return 0;
+}
+
+static inline void
+log_init(void)
+{
+}
+
+#define log_printf(...)
+
+/*
+ * Dummy handler exports.
+ */
+const struct log_handler log_console_handler;
+const struct log_handler log_cbmem_handler;
+const struct log_handler log_fcb_handler;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SYS_LOG_STUB_H__ */
diff --git a/porting/common/include/mem/mem.h b/porting/common/include/mem/mem.h
new file mode 100644
index 0000000..18461b6
--- /dev/null
+++ b/porting/common/include/mem/mem.h
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 H_UTIL_MEM_
+#define H_UTIL_MEM_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct os_mempool;
+struct os_mbuf_pool;
+
+int mem_malloc_mempool(struct os_mempool *mempool, int num_blocks,
+                       int block_size, char *name, void **out_buf);
+
+int mem_malloc_mbuf_pool(struct os_mempool *mempool,
+                         struct os_mbuf_pool *mbuf_pool, int num_blocks,
+                         int block_size, char *name,
+                         void **out_buf);
+int mem_malloc_mbufpkt_pool(struct os_mempool *mempool,
+                            struct os_mbuf_pool *mbuf_pool, int num_blocks,
+                            int block_size, char *name,
+                            void **out_buf);
+int mem_init_mbuf_pool(void *mem, struct os_mempool *mempool,
+                       struct os_mbuf_pool *mbuf_pool, int num_blocks,
+                       int block_size, char *name);
+
+/**
+ * Specifies a function used as a callback.  Functions of this type allocate an
+ * mbuf chain meant to hold a packet fragment.  The resulting mbuf must contain
+ * a pkthdr.
+ *
+ * @param frag_size             The number of data bytes that the mbuf will
+ *                                  eventually contain.
+ * @param arg                   A generic parameter.
+ *
+ * @return                      An allocated mbuf chain on success;
+ *                              NULL on failure.
+ */
+typedef struct os_mbuf *mem_frag_alloc_fn(uint16_t frag_size, void *arg);
+
+struct os_mbuf *mem_split_frag(struct os_mbuf **om, uint16_t max_frag_sz,
+                               mem_frag_alloc_fn *alloc_cb, void *cb_arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/porting/common/include/nimble_port.h b/porting/common/include/nimble_port.h
new file mode 100755
index 0000000..6d5e214
--- /dev/null
+++ b/porting/common/include/nimble_port.h
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 __NIMBLE_PORT_H__
+#define __NIMBLE_PORT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void nimble_init(void);
+
+void nimble_run(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __NIMBLE_PORT_H__ */
diff --git a/porting/common/include/os/endian.h b/porting/common/include/os/endian.h
new file mode 100644
index 0000000..ca8698d
--- /dev/null
+++ b/porting/common/include/os/endian.h
@@ -0,0 +1,225 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 H_ENDIAN_
+#define H_ENDIAN_
+
+#include <inttypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Internal helpers */
+#ifndef os_bswap_64
+#define os_bswap_64(x)   ((uint64_t)                \
+     ((((x) & 0xff00000000000000ull) >> 56) |       \
+      (((x) & 0x00ff000000000000ull) >> 40) |       \
+      (((x) & 0x0000ff0000000000ull) >> 24) |       \
+      (((x) & 0x000000ff00000000ull) >>  8) |       \
+      (((x) & 0x00000000ff000000ull) <<  8) |       \
+      (((x) & 0x0000000000ff0000ull) << 24) |       \
+      (((x) & 0x000000000000ff00ull) << 40) |       \
+      (((x) & 0x00000000000000ffull) << 56)))
+#endif
+
+#ifndef os_bswap_32
+#define os_bswap_32(x)    ((uint32_t)               \
+    ((((x) & 0xff000000) >> 24) |                   \
+     (((x) & 0x00ff0000) >>  8) |                   \
+     (((x) & 0x0000ff00) <<  8) |                   \
+     (((x) & 0x000000ff) << 24)))
+#endif
+
+#ifndef os_bswap_16
+#define os_bswap_16(x)   ((uint16_t)                \
+    ((((x) & 0xff00) >> 8) |                        \
+     (((x) & 0x00ff) << 8)))
+#endif
+
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+
+#ifndef ntohll
+#define ntohll(x)  ((uint64_t)(x))
+#endif
+
+#ifndef htonll
+#define htonll(x)  ((uint64_t)(x))
+#endif
+
+#ifndef ntohl
+#define ntohl(x)   ((uint32_t)(x))
+#endif
+
+#ifndef htonl
+#define htonl(x)   ((uint32_t)(x))
+#endif
+
+#ifndef ntohs
+#define ntohs(x)   ((uint16_t)(x))
+#endif
+
+#ifndef htons
+#define htons(x)   ((uint16_t)(x))
+#endif
+
+#ifndef htobe16
+#define htobe16(x) ((uint16_t)(x))
+#endif
+
+#ifndef htole16
+#define htole16(x) os_bswap_16 (x)
+#endif
+
+#ifndef be16toh
+#define be16toh(x) ((uint16_t)(x))
+#endif
+
+#ifndef le16toh
+#define le16toh(x) os_bswap_16 (x)
+#endif
+
+#ifndef htobe32
+#define htobe32(x) ((uint32_t)(x))
+#endif
+
+#ifndef htole32
+#define htole32(x) os_bswap_32 (x)
+#endif
+
+#ifndef be32toh
+#define be32toh(x) ((uint32_t)(x))
+#endif
+
+#ifndef le32toh
+#define le32toh(x) os_bswap_32 (x)
+#endif
+
+#ifndef htobe64
+#define htobe64(x) ((uint64_t)(x))
+#endif
+
+#ifndef htole64
+#define htole64(x) os_bswap_64 (x)
+#endif
+
+#ifndef be64toh
+#define be64toh(x) ((uint64_t)(x))
+#endif
+
+#ifndef le64toh
+#define le64toh(x) os_bswap_64 (x)
+#endif
+
+#else
+
+#ifndef ntohll
+#define ntohll(x)   os_bswap_64(x)
+#endif
+
+#ifndef htonll
+#define htonll      ntohll
+#endif
+
+#ifndef ntohl
+#define ntohl(x)    os_bswap_32(x)
+#endif
+
+#ifndef htonl
+#define htonl       ntohl
+#endif
+
+#ifndef htons
+#define htons(x)    os_bswap_16(x)
+#endif
+
+#ifndef ntohs
+#define ntohs       htons
+#endif
+
+#ifndef htobe16
+#define htobe16(x) os_bswap_16(x)
+#endif
+
+#ifndef htole16
+#define htole16(x) ((uint16_t)(x))
+#endif
+
+#ifndef be16toh
+#define be16toh(x) os_bswap_16(x)
+#endif
+
+#ifndef le16toh
+#define le16toh(x) ((uint16_t)(x))
+#endif
+
+#ifndef htobe32
+#define htobe32(x) os_bswap_32(x)
+#endif
+
+#ifndef htole32
+#define htole32(x) ((uint32_t)(x))
+#endif
+
+#ifndef be32toh
+#define be32toh(x) os_bswap_32(x)
+#endif
+
+#ifndef le32toh
+#define le32toh(x) ((uint32_t)(x))
+#endif
+
+#ifndef htobe64
+#define htobe64(x) os_bswap64(x)
+#endif
+
+#ifndef htole64
+#define htole64(x) ((uint64_t)(x))
+#endif
+
+#ifndef be64toh
+#define be64toh(x) os_bswap64(x)
+#endif
+
+#ifndef le64toh
+#define le64toh(x) ((uint64_t)(x))
+#endif
+
+#endif
+
+void put_le16(void *buf, uint16_t x);
+void put_le32(void *buf, uint32_t x);
+void put_le64(void *buf, uint64_t x);
+uint16_t get_le16(const void *buf);
+uint32_t get_le32(const void *buf);
+uint64_t get_le64(const void *buf);
+void put_be16(void *buf, uint16_t x);
+void put_be32(void *buf, uint32_t x);
+void put_be64(void *buf, uint64_t x);
+uint16_t get_be16(const void *buf);
+uint32_t get_be32(const void *buf);
+uint64_t get_be64(const void *buf);
+void swap_in_place(void *buf, int len);
+void swap_buf(uint8_t *dst, const uint8_t *src, int len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/porting/common/include/os/os.h b/porting/common/include/os/os.h
new file mode 100644
index 0000000..9ff6ed5
--- /dev/null
+++ b/porting/common/include/os/os.h
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 _OS_H
+#define _OS_H
+
+#include <stdlib.h>
+#include <inttypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef min
+#define min(a, b) ((a)<(b)?(a):(b))
+#endif
+
+#ifndef max
+#define max(a, b) ((a)>(b)?(a):(b))
+#endif
+
+#define os_get_return_addr() (__builtin_return_address(0))
+
+#define OS_ALIGN(__n, __a) (                             \
+        (((__n) & ((__a) - 1)) == 0)                   ? \
+            (__n)                                      : \
+            ((__n) + ((__a) - ((__n) & ((__a) - 1))))    \
+        )
+
+
+#define CTASSERT(x) typedef int __ctasssert ## __LINE__[(x) ? 1 : -1]
+
+
+/**
+ * Whether or not the operating system has been started.  Set to
+ * 1 right before first task is run.
+ */
+extern int g_os_started;
+
+int os_info_init(void);
+
+/**
+ * Returns 1 if the OS has been started, 0 if it has not yet been
+ * been started.
+ */
+int os_started(void);
+
+#define OS_WAIT_FOREVER (-1)
+
+#define OS_IDLE_PRIO (0xff)
+#define OS_MAIN_TASK_PRIO       MYNEWT_VAL(OS_MAIN_TASK_PRIO)
+#define OS_MAIN_STACK_SIZE      MYNEWT_VAL(OS_MAIN_STACK_SIZE)
+
+void os_init(int (*fn)(int argc, char **argv));
+void os_start(void);
+
+/* XXX: Not sure if this should go here; I want to differentiate API that
+ * should be called by application developers as those that should not. */
+void os_init_idle_task(void);
+
+#include "os/endian.h"
+#include "os/os_arch.h"
+#include "os/os_callout.h"
+#include "os/os_cputime.h"
+#include "os/os_dev.h"
+#include "os/os_error.h"
+#include "os/os_eventq.h"
+#include "os/os_heap.h"
+#include "os/os_fault.h"
+#include "os/os_mbuf.h"
+#include "os/os_mempool.h"
+#include "os/os_mutex.h"
+#include "os/os_sanity.h"
+#include "os/os_sched.h"
+#include "os/os_sem.h"
+#include "os/os_task.h"
+#include "os/os_time.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OS_H */
diff --git a/porting/common/include/os/os_arch.h b/porting/common/include/os/os_arch.h
new file mode 100755
index 0000000..22d47f7
--- /dev/null
+++ b/porting/common/include/os/os_arch.h
@@ -0,0 +1,26 @@
+#ifndef _OS_ARCH_H
+#define _OS_ARCH_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int os_sr_t;
+typedef int os_stack_t;
+
+#define OS_ALIGNMENT (4)
+#define OS_TICKS_PER_SEC (1000)
+
+extern void vPortEnterCritical(void);
+extern void vPortExitCritical(void);
+
+#define OS_ENTER_CRITICAL(unused) do { (void)unused; vPortEnterCritical(); } while (0)
+#define OS_EXIT_CRITICAL(unused) do { (void)unused; vPortExitCritical(); } while (0)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OS_ARCH_H */
diff --git a/porting/common/include/os/os_callout.h b/porting/common/include/os/os_callout.h
new file mode 100644
index 0000000..254d7a4
--- /dev/null
+++ b/porting/common/include/os/os_callout.h
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 _OS_CALLOUT_H
+#define _OS_CALLOUT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define OS_CALLOUT_F_QUEUED (0x01)
+
+#include "os/os_eventq.h"
+
+struct os_callout {
+    struct os_event c_ev;
+    struct os_eventq *c_evq;
+    uint32_t c_ticks;
+    TAILQ_ENTRY(os_callout) c_next;
+};
+
+TAILQ_HEAD(os_callout_list, os_callout);
+
+void os_callout_init(struct os_callout *cf, struct os_eventq *evq,
+                     os_event_fn *ev_cb, void *ev_arg);
+void os_callout_stop(struct os_callout *);
+int os_callout_reset(struct os_callout *, int32_t);
+void os_callout_tick(void);
+os_time_t os_callout_wakeup_ticks(os_time_t now);
+os_time_t os_callout_remaining_ticks(struct os_callout *c, os_time_t now);
+
+static inline int
+os_callout_queued(struct os_callout *c)
+{
+    return c->c_next.tqe_prev != NULL;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OS_CALLOUT_H */
+
+
+
diff --git a/porting/common/include/os/os_cfg.h b/porting/common/include/os/os_cfg.h
new file mode 100644
index 0000000..15f43d5
--- /dev/null
+++ b/porting/common/include/os/os_cfg.h
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 _OS_CFG_H_
+#define _OS_CFG_H_ 
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OS_CFG_H_ */
diff --git a/porting/common/include/os/os_cputime.h b/porting/common/include/os/os_cputime.h
new file mode 100644
index 0000000..fc3b881
--- /dev/null
+++ b/porting/common/include/os/os_cputime.h
@@ -0,0 +1,242 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 H_OS_CPUTIME_
+#define H_OS_CPUTIME_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "syscfg/syscfg.h"
+#include "os/queue.h"
+#include "hal/hal_timer.h"
+
+/*
+ * NOTE: these definitions allow one to override the cputime frequency used.
+ * The reason these definitions exist is to make the code more
+ * efficient/smaller when CPUTIME counts at 1 MHz.
+ *
+ * For those who want a different cputime frequency, you can set the config
+ * definition for OS_CPUTIME_FREQ to the desired frequency in your project,
+ * target or bsp.
+ */
+#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 1000000)
+
+#define OS_CPUTIME_FREQ_1MHZ
+
+#elif MYNEWT_VAL(OS_CPUTIME_FREQ) == 256        ||  \
+      MYNEWT_VAL(OS_CPUTIME_FREQ) == 512        ||  \
+      MYNEWT_VAL(OS_CPUTIME_FREQ) == 1024       ||  \
+      MYNEWT_VAL(OS_CPUTIME_FREQ) == 2048       ||  \
+      MYNEWT_VAL(OS_CPUTIME_FREQ) == 4096       ||  \
+      MYNEWT_VAL(OS_CPUTIME_FREQ) == 8192       ||  \
+      MYNEWT_VAL(OS_CPUTIME_FREQ) == 16384      ||  \
+      MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768      ||  \
+      MYNEWT_VAL(OS_CPUTIME_FREQ) == 65536      ||  \
+      MYNEWT_VAL(OS_CPUTIME_FREQ) == 131072     ||  \
+      MYNEWT_VAL(OS_CPUTIME_FREQ) == 262144     ||  \
+      MYNEWT_VAL(OS_CPUTIME_FREQ) == 524288
+
+#define OS_CPUTIME_FREQ_PWR2
+
+#elif MYNEWT_VAL(OS_CPUTIME_FREQ) > 1000000
+
+#define OS_CPUTIME_FREQ_HIGH
+
+#else
+
+#error "Invalid OS_CPUTIME_FREQ value.  Value must be one of a) a power of 2" \
+       ">= 256Hz, or b) any value >= 1MHz"
+
+#endif
+
+#if defined(OS_CPUTIME_FREQ_HIGH)
+/* CPUTIME data. */
+struct os_cputime_data
+{
+    uint32_t ticks_per_usec;    /* number of ticks per usec */
+};
+extern struct os_cputime_data g_os_cputime;
+#endif
+
+/* Helpful macros to compare cputimes */
+#define CPUTIME_LT(__t1, __t2) ((int32_t)   ((__t1) - (__t2)) < 0)
+#define CPUTIME_GT(__t1, __t2) ((int32_t)   ((__t1) - (__t2)) > 0)
+#define CPUTIME_GEQ(__t1, __t2) ((int32_t)  ((__t1) - (__t2)) >= 0)
+#define CPUTIME_LEQ(__t1, __t2) ((int32_t)  ((__t1) - (__t2)) <= 0)
+
+/**
+ * os cputime init
+ *
+ * Initialize the cputime module. This must be called after os_init is called
+ * and before any other timer API are used. This should be called only once
+ * and should be called before the hardware timer is used.
+ *
+ * @param clock_freq The desired cputime frequency, in hertz (Hz).
+ *
+ * @return int 0 on success; -1 on error.
+ */
+int os_cputime_init(uint32_t clock_freq);
+
+/**
+ * os cputime get32
+ *
+ * Returns the low 32 bits of cputime.
+ *
+ * @return uint32_t The lower 32 bits of cputime
+ */
+uint32_t os_cputime_get32(void);
+
+#if !defined(OS_CPUTIME_FREQ_PWR2)
+/**
+ * os cputime nsecs to ticks
+ *
+ * Converts the given number of nanoseconds into cputime ticks.
+ *
+ * @param usecs The number of nanoseconds to convert to ticks
+ *
+ * @return uint32_t The number of ticks corresponding to 'nsecs'
+ */
+uint32_t os_cputime_nsecs_to_ticks(uint32_t nsecs);
+
+/**
+ * os cputime ticks to nsecs
+ *
+ * Convert the given number of ticks into nanoseconds.
+ *
+ * @param ticks The number of ticks to convert to nanoseconds.
+ *
+ * @return uint32_t The number of nanoseconds corresponding to 'ticks'
+ */
+uint32_t os_cputime_ticks_to_nsecs(uint32_t ticks);
+
+/**
+ * os cputime delay nsecs
+ *
+ * Wait until 'nsecs' nanoseconds has elapsed. This is a blocking delay.
+ *
+ * @param nsecs The number of nanoseconds to wait.
+ */
+void os_cputime_delay_nsecs(uint32_t nsecs);
+#endif
+
+#if defined(OS_CPUTIME_FREQ_1MHZ)
+#define os_cputime_usecs_to_ticks(x)    (x)
+#define os_cputime_ticks_to_usecs(x)    (x)
+#else
+/**
+ * os cputime usecs to ticks
+ *
+ * Converts the given number of microseconds into cputime ticks.
+ *
+ * @param usecs The number of microseconds to convert to ticks
+ *
+ * @return uint32_t The number of ticks corresponding to 'usecs'
+ */
+uint32_t os_cputime_usecs_to_ticks(uint32_t usecs);
+
+/**
+ * os cputime ticks to usecs
+ *
+ * Convert the given number of ticks into microseconds.
+ *
+ * @param ticks The number of ticks to convert to microseconds.
+ *
+ * @return uint32_t The number of microseconds corresponding to 'ticks'
+ */
+uint32_t os_cputime_ticks_to_usecs(uint32_t ticks);
+#endif
+
+/**
+ * os cputime delay ticks
+ *
+ * Wait until the number of ticks has elapsed. This is a blocking delay.
+ *
+ * @param ticks The number of ticks to wait.
+ */
+void os_cputime_delay_ticks(uint32_t ticks);
+
+/**
+ * os cputime delay usecs
+ *
+ * Wait until 'usecs' microseconds has elapsed. This is a blocking delay.
+ *
+ * @param usecs The number of usecs to wait.
+ */
+void os_cputime_delay_usecs(uint32_t usecs);
+
+/**
+ * os cputime timer init
+ *
+ * @param timer The timer to initialize. Cannot be NULL.
+ * @param fp    The timer callback function. Cannot be NULL.
+ * @param arg   Pointer to data object to pass to timer.
+ */
+void os_cputime_timer_init(struct hal_timer *timer, hal_timer_cb fp, void *arg);
+
+/**
+ * os cputime timer start
+ *
+ * Start a cputimer that will expire at 'cputime'. If cputime has already
+ * passed, the timer callback will still be called (at interrupt context).
+ *
+ * NOTE: This must be called when the timer is stopped.
+ *
+ * @param timer     Pointer to timer to start. Cannot be NULL.
+ * @param cputime   The cputime at which the timer should expire.
+ *
+ * @return int 0 on success; EINVAL if timer already started or timer struct
+ *         invalid
+ *
+ */
+int os_cputime_timer_start(struct hal_timer *timer, uint32_t cputime);
+
+/**
+ * os cputimer timer relative
+ *
+ * Sets a cpu timer that will expire 'usecs' microseconds from the current
+ * cputime.
+ *
+ * NOTE: This must be called when the timer is stopped.
+ *
+ * @param timer Pointer to timer. Cannot be NULL.
+ * @param usecs The number of usecs from now at which the timer will expire.
+ *
+ * @return int 0 on success; EINVAL if timer already started or timer struct
+ *         invalid
+ */
+int os_cputime_timer_relative(struct hal_timer *timer, uint32_t usecs);
+
+/**
+ * os cputime timer stop
+ *
+ * Stops a cputimer from running. The timer is removed from the timer queue
+ * and interrupts are disabled if no timers are left on the queue. Can be
+ * called even if timer is not running.
+ *
+ * @param timer Pointer to cputimer to stop. Cannot be NULL.
+ */
+void os_cputime_timer_stop(struct hal_timer *timer);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* H_OS_CPUTIME_ */
diff --git a/porting/common/include/os/os_dev.h b/porting/common/include/os/os_dev.h
new file mode 100644
index 0000000..ed65a08
--- /dev/null
+++ b/porting/common/include/os/os_dev.h
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 _OS_DEV_H
+#define _OS_DEV_H
+
+#include <os/os.h>
+
+#include "os/queue.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct os_dev;
+
+/*
+ * Initialization order, defines when a device should be initialized
+ * by the Mynewt kernel.
+ *
+ */
+#define OS_DEV_INIT_PRIMARY   (1)
+#define OS_DEV_INIT_SECONDARY (2)
+#define OS_DEV_INIT_KERNEL    (3)
+
+#define OS_DEV_INIT_F_CRITICAL (1 << 0)
+
+
+#define OS_DEV_INIT_PRIO_DEFAULT (0xff)
+
+/**
+ * Device status, so functions can ensure device is called in a
+ * consistent state.
+ */
+#define OS_DEV_F_STATUS_READY     (1 << 0)
+#define OS_DEV_F_STATUS_OPEN      (1 << 1)
+#define OS_DEV_F_STATUS_SUSPENDED (1 << 2)
+#define OS_DEV_F_INIT_CRITICAL    (1 << 3)
+
+typedef int (*os_dev_init_func_t)(struct os_dev *, void *);
+typedef int (*os_dev_open_func_t)(struct os_dev *, uint32_t,
+        void *);
+typedef int (*os_dev_suspend_func_t)(struct os_dev *, os_time_t, int);
+typedef int (*os_dev_resume_func_t)(struct os_dev *);
+typedef int (*os_dev_close_func_t)(struct os_dev *);
+
+struct os_dev_handlers {
+    os_dev_open_func_t od_open;
+    os_dev_suspend_func_t od_suspend;
+    os_dev_resume_func_t od_resume;
+    os_dev_close_func_t od_close;
+};
+
+/*
+ * Device structure.
+ */
+struct os_dev {
+    struct os_dev_handlers od_handlers;
+    os_dev_init_func_t od_init;
+    void *od_init_arg;
+    uint8_t od_stage;
+    uint8_t od_priority;
+    uint8_t od_open_ref;
+    uint8_t od_flags;
+    char *od_name;
+    STAILQ_ENTRY(os_dev) od_next;
+};
+
+#define OS_DEV_SETHANDLERS(__dev, __open, __close)          \
+    (__dev)->od_handlers.od_open = (__open);                \
+    (__dev)->od_handlers.od_close = (__close);
+
+static inline int
+os_dev_suspend(struct os_dev *dev, os_time_t suspend_t, uint8_t force)
+{
+    if (dev->od_handlers.od_suspend == NULL) {
+        return (0);
+    } else {
+        return (dev->od_handlers.od_suspend(dev, suspend_t, force));
+    }
+}
+
+static inline int
+os_dev_resume(struct os_dev *dev)
+{
+    if (dev->od_handlers.od_resume == NULL) {
+        return (0);
+    } else {
+        return (dev->od_handlers.od_resume(dev));
+    }
+}
+
+int os_dev_create(struct os_dev *dev, char *name, uint8_t stage,
+        uint8_t priority, os_dev_init_func_t od_init, void *arg);
+struct os_dev *os_dev_lookup(char *name);
+int os_dev_initialize_all(uint8_t stage);
+int os_dev_suspend_all(os_time_t, uint8_t);
+int os_dev_resume_all(void);
+struct os_dev *os_dev_open(char *devname, uint32_t timo, void *arg);
+int os_dev_close(struct os_dev *dev);
+void os_dev_reset(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OS_DEV_H */
diff --git a/porting/common/include/os/os_error.h b/porting/common/include/os/os_error.h
new file mode 100644
index 0000000..01df389
--- /dev/null
+++ b/porting/common/include/os/os_error.h
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 H_OS_ERROR_
+#define H_OS_ERROR_
+
+#include "syscfg/syscfg.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* OS error enumerations */
+enum os_error {
+    OS_OK = 0,
+    OS_ENOMEM = 1,
+    OS_EINVAL = 2,
+    OS_INVALID_PARM = 3,
+    OS_MEM_NOT_ALIGNED = 4,
+    OS_BAD_MUTEX = 5,
+    OS_TIMEOUT = 6,
+    OS_ERR_IN_ISR = 7,      /* Function cannot be called from ISR */
+    OS_ERR_PRIV = 8,        /* Privileged access error */
+    OS_NOT_STARTED = 9,     /* OS must be started to call this function, but isn't */
+    OS_ENOENT = 10,         /* No such thing */
+    OS_EBUSY = 11,          /* Resource busy */
+    OS_ERROR = 12,          /* Generic Error */
+};
+
+typedef enum os_error os_error_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/porting/common/include/os/os_eventq.h b/porting/common/include/os/os_eventq.h
new file mode 100644
index 0000000..b0c3abd
--- /dev/null
+++ b/porting/common/include/os/os_eventq.h
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 _OS_EVENTQ_H
+#define _OS_EVENTQ_H
+
+#include <inttypes.h>
+#include "os/os_time.h"
+#include "os/queue.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct os_event;
+typedef void os_event_fn(struct os_event *ev);
+
+struct os_event {
+    uint8_t ev_queued;
+    os_event_fn *ev_cb;
+    void *ev_arg;
+    STAILQ_ENTRY(os_event) ev_next;
+};
+
+#define OS_EVENT_QUEUED(__ev) ((__ev)->ev_queued)
+
+struct os_eventq {
+    struct os_task *evq_owner;  /* owner task */
+    struct os_task *evq_task;   /* sleeper; must be either NULL, or the owner */
+    STAILQ_HEAD(, os_event) evq_list;
+};
+
+void os_eventq_init(struct os_eventq *);
+int os_eventq_inited(const struct os_eventq *evq);
+void os_eventq_put(struct os_eventq *, struct os_event *);
+struct os_event *os_eventq_get_no_wait(struct os_eventq *evq);
+struct os_event *os_eventq_get(struct os_eventq *);
+void os_eventq_run(struct os_eventq *evq);
+struct os_event *os_eventq_poll(struct os_eventq **, int, os_time_t);
+void os_eventq_remove(struct os_eventq *, struct os_event *);
+struct os_eventq *os_eventq_dflt_get(void);
+
+/* [DEPRECATED] */
+void os_eventq_designate(struct os_eventq **dst, struct os_eventq *val,
+                         struct os_event *start_ev);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OS_EVENTQ_H */
+
diff --git a/porting/common/include/os/os_fault.h b/porting/common/include/os/os_fault.h
new file mode 100644
index 0000000..4ce34c2
--- /dev/null
+++ b/porting/common/include/os/os_fault.h
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 _OS_FAULT_H
+#define _OS_FAULT_H
+
+#ifdef __cplusplus
+extern "c" {
+#endif
+
+void __assert_func(const char *, int, const char *, const char *)
+    __attribute((noreturn));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OS_FAULT_H */
diff --git a/porting/common/include/os/os_heap.h b/porting/common/include/os/os_heap.h
new file mode 100644
index 0000000..4413568
--- /dev/null
+++ b/porting/common/include/os/os_heap.h
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 H_OS_HEAP_
+#define H_OS_HEAP_
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void *os_malloc(size_t size);
+void os_free(void *mem);
+void *os_realloc(void *ptr, size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/porting/common/include/os/os_malloc.h b/porting/common/include/os/os_malloc.h
new file mode 100644
index 0000000..32b72c2
--- /dev/null
+++ b/porting/common/include/os/os_malloc.h
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 H_OS_MALLOC_
+#define H_OS_MALLOC_
+
+#include "os/os_heap.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#undef  malloc
+#define malloc  os_malloc
+
+#undef  free
+#define free    os_free
+
+#undef  realloc
+#define realloc  os_realloc
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/porting/common/include/os/os_mbuf.h b/porting/common/include/os/os_mbuf.h
new file mode 100644
index 0000000..314a2eb
--- /dev/null
+++ b/porting/common/include/os/os_mbuf.h
@@ -0,0 +1,305 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 _OS_MBUF_H
+#define _OS_MBUF_H
+
+#include "os/queue.h"
+#include "os/os_eventq.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * A mbuf pool from which to allocate mbufs. This contains a pointer to the os
+ * mempool to allocate mbufs out of, the total number of elements in the pool,
+ * and the amount of "user" data in a non-packet header mbuf. The total pool
+ * size, in bytes, should be:
+ *  os_mbuf_count * (omp_databuf_len + sizeof(struct os_mbuf))
+ */
+struct os_mbuf_pool {
+    /**
+     * Total length of the databuf in each mbuf.  This is the size of the
+     * mempool block, minus the mbuf header
+     */
+    uint16_t omp_databuf_len;
+    /**
+     * Total number of memblock's allocated in this mempool.
+     */
+    uint16_t omp_mbuf_count;
+    /**
+     * The memory pool which to allocate mbufs out of
+     */
+    struct os_mempool *omp_pool;
+
+    /**
+     * Link to the next mbuf pool for system memory pools.
+     */
+    STAILQ_ENTRY(os_mbuf_pool) omp_next;
+};
+
+
+/**
+ * A packet header structure that preceeds the mbuf packet headers.
+ */
+struct os_mbuf_pkthdr {
+    /**
+     * Overall length of the packet.
+     */
+    uint16_t omp_len;
+    /**
+     * Flags
+     */
+    uint16_t omp_flags;
+    /**
+     * Next packet in the mbuf chain.
+     */
+    STAILQ_ENTRY(os_mbuf_pkthdr) omp_next;
+};
+
+/**
+ * Chained memory buffer.
+ */
+struct os_mbuf {
+    /**
+     * Current pointer to data in the structure
+     */
+    uint8_t *om_data;
+    /**
+     * Flags associated with this buffer, see OS_MBUF_F_* defintions
+     */
+    uint8_t om_flags;
+    /**
+     * Length of packet header
+     */
+    uint8_t om_pkthdr_len;
+    /**
+     * Length of data in this buffer
+     */
+    uint16_t om_len;
+
+    /**
+     * The mbuf pool this mbuf was allocated out of
+     */
+    struct os_mbuf_pool *om_omp;
+
+    /**
+     * Pointer to next entry in the chained memory buffer
+     */
+    SLIST_ENTRY(os_mbuf) om_next;
+
+    /**
+     * Pointer to the beginning of the data, after this buffer
+     */
+    uint8_t om_databuf[0];
+};
+
+struct os_mqueue {
+    STAILQ_HEAD(, os_mbuf_pkthdr) mq_head;
+    struct os_event mq_ev;
+};
+
+/*
+ * Given a flag number, provide the mask for it
+ *
+ * @param __n The number of the flag in the mask
+ */
+#define OS_MBUF_F_MASK(__n) (1 << (__n))
+
+/*
+ * Checks whether a given mbuf is a packet header mbuf
+ *
+ * @param __om The mbuf to check
+ */
+#define OS_MBUF_IS_PKTHDR(__om) \
+    ((__om)->om_pkthdr_len >= sizeof (struct os_mbuf_pkthdr))
+
+/* Get a packet header pointer given an mbuf pointer */
+#define OS_MBUF_PKTHDR(__om) ((struct os_mbuf_pkthdr *)     \
+    ((uint8_t *)&(__om)->om_data + sizeof(struct os_mbuf)))
+
+/* Given a mbuf packet header pointer, return a pointer to the mbuf */
+#define OS_MBUF_PKTHDR_TO_MBUF(__hdr)   \
+     (struct os_mbuf *)((uint8_t *)(__hdr) - sizeof(struct os_mbuf))
+
+/**
+ * Gets the length of an entire mbuf chain.  The specified mbuf must have a
+ * packet header.
+ */
+#define OS_MBUF_PKTLEN(__om) (OS_MBUF_PKTHDR(__om)->omp_len)
+
+/*
+ * Access the data of a mbuf, and cast it to type
+ *
+ * @param __om The mbuf to access, and cast
+ * @param __type The type to cast it to
+ */
+#define OS_MBUF_DATA(__om, __type) \
+     (__type) ((__om)->om_data)
+
+/**
+ * Access the "user header" in the head of an mbuf chain.
+ *
+ * @param om                    Pointer to the head of an mbuf chain.
+ */
+#define OS_MBUF_USRHDR(om)                              \
+    (void *)((uint8_t *)om + sizeof (struct os_mbuf) +  \
+             sizeof (struct os_mbuf_pkthdr))
+
+/**
+ * Retrieves the length of the user header in an mbuf.
+ *
+ * @param om                    Pointer to the mbuf to query.
+ */
+#define OS_MBUF_USRHDR_LEN(om) \
+    ((om)->om_pkthdr_len - sizeof (struct os_mbuf_pkthdr))
+
+/*
+ * Called by OS_MBUF_LEADINGSPACE() macro
+ */
+static inline uint16_t
+_os_mbuf_leadingspace(struct os_mbuf *om)
+{
+    uint16_t startoff;
+    uint16_t leadingspace;
+
+    startoff = 0;
+    if (OS_MBUF_IS_PKTHDR(om)) {
+        startoff = om->om_pkthdr_len;
+    }
+
+    leadingspace = (uint16_t) (OS_MBUF_DATA(om, uint8_t *) -
+        ((uint8_t *) &om->om_databuf[0] + startoff));
+
+    return (leadingspace);
+}
+
+/**
+ * Returns the leading space (space at the beginning) of the mbuf.
+ * Works on both packet header, and regular mbufs, as it accounts
+ * for the additional space allocated to the packet header.
+ *
+ * @param __omp Is the mbuf pool (which contains packet header length.)
+ * @param __om  Is the mbuf in that pool to get the leadingspace for
+ *
+ * @return Amount of leading space available in the mbuf
+ */
+#define OS_MBUF_LEADINGSPACE(__om) _os_mbuf_leadingspace(__om)
+
+/* Called by OS_MBUF_TRAILINGSPACE() macro. */
+static inline uint16_t
+_os_mbuf_trailingspace(struct os_mbuf *om)
+{
+    struct os_mbuf_pool *omp;
+
+    omp = om->om_omp;
+
+    return (&om->om_databuf[0] + omp->omp_databuf_len) -
+      (om->om_data + om->om_len);
+}
+
+/**
+ * Returns the trailing space (space at the end) of the mbuf.
+ * Works on both packet header and regular mbufs.
+ *
+ * @param __omp The mbuf pool for this mbuf
+ * @param __om  Is the mbuf in that pool to get trailing space for
+ *
+ * @return The amount of trailing space available in the mbuf
+ */
+#define OS_MBUF_TRAILINGSPACE(__om) _os_mbuf_trailingspace(__om)
+
+/* Mbuf queue functions */
+
+/* Initialize a mbuf queue */
+int os_mqueue_init(struct os_mqueue *mq, os_event_fn *ev_cb, void *arg);
+
+/* Get an element from a mbuf queue */
+struct os_mbuf *os_mqueue_get(struct os_mqueue *);
+
+/* Put an element in a mbuf queue */
+int os_mqueue_put(struct os_mqueue *, struct os_eventq *, struct os_mbuf *);
+
+/* Register an mbuf pool with the system pool registry */
+int os_msys_register(struct os_mbuf_pool *);
+
+/* Return a mbuf from the system pool, given an indicative mbuf size */
+struct os_mbuf *os_msys_get(uint16_t dsize, uint16_t leadingspace);
+
+/* De-registers all mbuf pools from msys. */
+void os_msys_reset(void);
+
+/* Return a packet header mbuf from the system pool */
+struct os_mbuf *os_msys_get_pkthdr(uint16_t dsize, uint16_t user_hdr_len);
+
+int os_msys_count(void);
+int os_msys_num_free(void);
+
+/* Initialize a mbuf pool */
+int os_mbuf_pool_init(struct os_mbuf_pool *, struct os_mempool *mp,
+        uint16_t, uint16_t);
+
+/* Allocate a new mbuf out of the os_mbuf_pool */
+struct os_mbuf *os_mbuf_get(struct os_mbuf_pool *omp, uint16_t);
+
+/* Allocate a new packet header mbuf out of the os_mbuf_pool */
+struct os_mbuf *os_mbuf_get_pkthdr(struct os_mbuf_pool *omp,
+        uint8_t pkthdr_len);
+
+/* Duplicate a mbuf from the pool */
+struct os_mbuf *os_mbuf_dup(struct os_mbuf *m);
+
+struct os_mbuf *os_mbuf_off(const struct os_mbuf *om, int off,
+                            uint16_t *out_off);
+
+/* Copy data from an mbuf to a flat buffer. */
+int os_mbuf_copydata(const struct os_mbuf *m, int off, int len, void *dst);
+
+/* Append data onto a mbuf */
+int os_mbuf_append(struct os_mbuf *m, const void *, uint16_t);
+
+int os_mbuf_appendfrom(struct os_mbuf *dst, const struct os_mbuf *src,
+                       uint16_t src_off, uint16_t len);
+
+/* Free a mbuf */
+int os_mbuf_free(struct os_mbuf *mb);
+
+/* Free a mbuf chain */
+int os_mbuf_free_chain(struct os_mbuf *om);
+
+void os_mbuf_adj(struct os_mbuf *mp, int req_len);
+int os_mbuf_cmpf(const struct os_mbuf *om, int off, const void *data, int len);
+int os_mbuf_cmpm(const struct os_mbuf *om1, uint16_t offset1,
+                 const struct os_mbuf *om2, uint16_t offset2,
+                 uint16_t len);
+
+struct os_mbuf *os_mbuf_prepend(struct os_mbuf *om, int len);
+struct os_mbuf *os_mbuf_prepend_pullup(struct os_mbuf *om, uint16_t len);
+int os_mbuf_copyinto(struct os_mbuf *om, int off, const void *src, int len);
+void os_mbuf_concat(struct os_mbuf *first, struct os_mbuf *second);
+void *os_mbuf_extend(struct os_mbuf *om, uint16_t len);
+struct os_mbuf *os_mbuf_pullup(struct os_mbuf *om, uint16_t len);
+struct os_mbuf *os_mbuf_trim_front(struct os_mbuf *om);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OS_MBUF_H */ 
diff --git a/porting/common/include/os/os_mempool.h b/porting/common/include/os/os_mempool.h
new file mode 100644
index 0000000..0f5cca9
--- /dev/null
+++ b/porting/common/include/os/os_mempool.h
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 _OS_MEMPOOL_H_
+#define _OS_MEMPOOL_H_
+
+#include <stdbool.h>
+#include "os/os.h"
+#include "os/queue.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * A memory block structure. This simply contains a pointer to the free list
+ * chain and is only used when the block is on the free list. When the block
+ * has been removed from the free list the entire memory block is usable by the
+ * caller.
+ */
+struct os_memblock {
+    SLIST_ENTRY(os_memblock) mb_next;
+};
+
+/* XXX: Change this structure so that we keep the first address in the pool? */
+/* XXX: add memory debug structure and associated code */
+/* XXX: Change how I coded the SLIST_HEAD here. It should be named:
+   SLIST_HEAD(,os_memblock) mp_head; */
+
+/* Memory pool */
+struct os_mempool {
+    int mp_block_size;          /* Size of the memory blocks, in bytes. */
+    int mp_num_blocks;          /* The number of memory blocks. */
+    int mp_num_free;            /* The number of free blocks left */
+    int mp_min_free;            /* The lowest number of free blocks seen */
+    uint32_t mp_membuf_addr;    /* Address of memory buffer used by pool */
+    STAILQ_ENTRY(os_mempool) mp_list;
+    SLIST_HEAD(,os_memblock);   /* Pointer to list of free blocks */
+    char *name;                 /* Name for memory block */
+};
+
+#define OS_MEMPOOL_INFO_NAME_LEN (32)
+
+struct os_mempool_info {
+    int omi_block_size;
+    int omi_num_blocks;
+    int omi_num_free;
+    int omi_min_free;
+    char omi_name[OS_MEMPOOL_INFO_NAME_LEN];
+};
+
+struct os_mempool *os_mempool_info_get_next(struct os_mempool *,
+        struct os_mempool_info *);
+
+/*
+ * To calculate size of the memory buffer needed for the pool. NOTE: This size
+ * is NOT in bytes! The size is the number of os_membuf_t elements required for
+ * the memory pool.
+ */
+#if (OS_CFG_ALIGNMENT == OS_CFG_ALIGN_4)
+#define OS_MEMPOOL_SIZE(n,blksize)      ((((blksize) + 3) / 4) * (n))
+typedef uint32_t os_membuf_t;
+#else
+#define OS_MEMPOOL_SIZE(n,blksize)      ((((blksize) + 7) / 8) * (n))
+typedef uint64_t os_membuf_t;
+#endif
+
+/** Calculates the number of bytes required to initialize a memory pool. */
+#define OS_MEMPOOL_BYTES(n,blksize)     \
+    (sizeof (os_membuf_t) * OS_MEMPOOL_SIZE((n), (blksize)))
+
+/* Initialize a memory pool */
+os_error_t os_mempool_init(struct os_mempool *mp, int blocks, int block_size,
+                           void *membuf, char *name);
+
+/* Performs an integrity check of the specified mempool. */
+bool os_mempool_is_sane(const struct os_mempool *mp);
+
+/* Checks if a memory block was allocated from the specified mempool. */
+int os_memblock_from(const struct os_mempool *mp, const void *block_addr);
+
+/* Get a memory block from the pool */
+void *os_memblock_get(struct os_mempool *mp);
+
+/* Put the memory block back into the pool */
+os_error_t os_memblock_put(struct os_mempool *mp, void *block_addr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* _OS_MEMPOOL_H_ */
diff --git a/porting/common/include/os/os_mutex.h b/porting/common/include/os/os_mutex.h
new file mode 100644
index 0000000..2964edb
--- /dev/null
+++ b/porting/common/include/os/os_mutex.h
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 _OS_MUTEX_H_
+#define _OS_MUTEX_H_
+
+#include "os/os.h"
+#include "os/queue.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct os_mutex
+{
+    SLIST_HEAD(, os_task) mu_head;  /* chain of waiting tasks */
+    uint8_t     _pad;
+    uint8_t     mu_prio;            /* owner's default priority*/
+    uint16_t    mu_level;           /* call nesting level */
+    struct os_task *mu_owner;       /* owners task */
+};
+
+/* 
+  XXX: NOTES
+    -> Should we add a magic number or flag to the mutex structure so
+    that we know that this is a mutex? We can use it for double checking
+    that a proper mutex was passed in to the API.
+    -> What debug information should we add to this structure? Who last
+    acquired the mutex? File/line where it was released?
+    -> Should we add a name to the mutex?
+    -> Should we add a "os_mutex_inspect() api?
+*/
+
+/* XXX: api to create
+os_mutex_inspect(); 
+*/ 
+
+/* Initialize a mutex */
+os_error_t os_mutex_init(struct os_mutex *mu);
+
+/* Release a mutex */
+os_error_t os_mutex_release(struct os_mutex *mu);
+
+/* Pend (wait) for a mutex */
+os_error_t os_mutex_pend(struct os_mutex *mu, uint32_t timeout);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* _OS_MUTEX_H_ */
diff --git a/porting/common/include/os/os_sanity.h b/porting/common/include/os/os_sanity.h
new file mode 100644
index 0000000..e74f2f9
--- /dev/null
+++ b/porting/common/include/os/os_sanity.h
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 _OS_SANITY_H
+#define _OS_SANITY_H
+
+#include <stdint.h>
+
+#include "os/os_time.h"
+#include "os/queue.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct os_sanity_check;
+typedef int (*os_sanity_check_func_t)(struct os_sanity_check *, void *);
+
+struct os_sanity_check {
+    os_time_t sc_checkin_last;
+    os_time_t sc_checkin_itvl;
+    os_sanity_check_func_t sc_func;
+    void *sc_arg;
+
+    SLIST_ENTRY(os_sanity_check) sc_next;
+
+};
+
+#define OS_SANITY_CHECK_SETFUNC(__sc, __f, __arg, __itvl)  \
+    (__sc)->sc_func = (__f);                               \
+    (__sc)->sc_arg = (__arg);                              \
+    (__sc)->sc_checkin_itvl = (__itvl) * OS_TICKS_PER_SEC;
+
+int os_sanity_init(void);
+void os_sanity_run(void);
+
+struct os_task;
+int os_sanity_task_checkin(struct os_task *);
+
+int os_sanity_check_init(struct os_sanity_check *);
+int os_sanity_check_register(struct os_sanity_check *);
+int os_sanity_check_reset(struct os_sanity_check *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OS_SANITY_H */
diff --git a/porting/common/include/os/os_sched.h b/porting/common/include/os/os_sched.h
new file mode 100644
index 0000000..be6b7fd
--- /dev/null
+++ b/porting/common/include/os/os_sched.h
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 _OS_SCHED_H
+#define _OS_SCHED_H
+
+#include "os/os_task.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct os_task;
+
+TAILQ_HEAD(os_task_list, os_task);
+
+extern struct os_task *g_current_task;
+extern struct os_task_list g_os_run_list;
+extern struct os_task_list g_os_sleep_list;
+
+void os_sched_ctx_sw_hook(struct os_task *);
+struct os_task *os_sched_get_current_task(void);
+void os_sched_set_current_task(struct os_task *);
+struct os_task *os_sched_next_task(void);
+void os_sched(struct os_task *);
+void os_sched_os_timer_exp(void);
+os_error_t os_sched_insert(struct os_task *);
+int os_sched_sleep(struct os_task *, os_time_t nticks);
+int os_sched_wakeup(struct os_task *);
+int os_sched_remove(struct os_task *);
+void os_sched_resort(struct os_task *);
+os_time_t os_sched_wakeup_ticks(os_time_t now);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OS_SCHED_H */
diff --git a/porting/common/include/os/os_sem.h b/porting/common/include/os/os_sem.h
new file mode 100644
index 0000000..d5451ab
--- /dev/null
+++ b/porting/common/include/os/os_sem.h
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 _OS_SEM_H_
+#define _OS_SEM_H_
+
+#include "os/queue.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct os_sem
+{
+    SLIST_HEAD(, os_task) sem_head;     /* chain of waiting tasks */
+    uint16_t    _pad;
+    uint16_t    sem_tokens;             /* # of tokens */
+};
+
+/* 
+  XXX: NOTES
+    -> Should we add a magic number or flag to the semaphore structure so
+    that we know that this is a semaphore? We can use it for double checking
+    that a proper semaphore was passed in to the API.
+    -> What debug information should we add to this structure? Who last
+    acquired the semaphore? File/line where it was released?
+    -> Should we add a name to the semaphore?
+    -> Should we add a "os_sem_inspect() api, like ucos?
+*/ 
+
+/* Create a semaphore */
+os_error_t os_sem_init(struct os_sem *sem, uint16_t tokens);
+
+/* Release a semaphore */
+os_error_t os_sem_release(struct os_sem *sem);
+
+/* Pend (wait) for a semaphore */
+os_error_t os_sem_pend(struct os_sem *sem, uint32_t timeout);
+
+/* Get current semaphore's count */
+static inline uint16_t os_sem_get_count(struct os_sem *sem)
+{
+    return sem->sem_tokens;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* _OS_SEM_H_ */
diff --git a/porting/common/include/os/os_task.h b/porting/common/include/os/os_task.h
new file mode 100644
index 0000000..a9e420f
--- /dev/null
+++ b/porting/common/include/os/os_task.h
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 _OS_TASK_H
+#define _OS_TASK_H
+
+#include "os/os.h"
+#include "os/os_sanity.h"
+#include "os/queue.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The highest and lowest task priorities */
+#define OS_TASK_PRI_HIGHEST (0)
+#define OS_TASK_PRI_LOWEST  (0xff)
+
+/*
+ * Generic "object" structure. All objects that a task can wait on must
+ * have a SLIST_HEAD(, os_task) head_name as the first element in the object
+ * structure. The element 'head_name' can be any name. See os_mutex.h or
+ * os_sem.h for an example.
+ */
+struct os_task_obj {
+    SLIST_HEAD(, os_task) obj_head;     /* chain of waiting tasks */
+};
+
+/* Task states */
+typedef enum os_task_state {
+    OS_TASK_READY = 1,
+    OS_TASK_SLEEP = 2,
+} os_task_state_t;
+
+/* Task flags */
+#define OS_TASK_FLAG_NO_TIMEOUT     (0x01U)
+#define OS_TASK_FLAG_SEM_WAIT       (0x02U)
+#define OS_TASK_FLAG_MUTEX_WAIT     (0x04U)
+#define OS_TASK_FLAG_EVQ_WAIT       (0x08U)
+
+typedef void (*os_task_func_t)(void *);
+
+#define OS_TASK_MAX_NAME_LEN (32)
+
+struct os_task {
+    os_stack_t *t_stackptr;
+    os_stack_t *t_stacktop;
+
+    uint16_t t_stacksize;
+    uint8_t t_taskid;
+    uint8_t t_prio;
+
+    uint8_t t_state;
+    uint8_t t_flags;
+    uint8_t t_lockcnt;
+    uint8_t t_pad;
+
+    const char *t_name;
+    os_task_func_t t_func;
+    void *t_arg;
+
+    void *t_obj;
+
+    struct os_sanity_check t_sanity_check;
+
+    os_time_t t_next_wakeup;
+    os_time_t t_run_time;
+    uint32_t t_ctx_sw_cnt;
+
+    /* Global list of all tasks, irrespective of run or sleep lists */
+    STAILQ_ENTRY(os_task) t_os_task_list;
+
+    /* Used to chain task to either the run or sleep list */
+    TAILQ_ENTRY(os_task) t_os_list;
+
+    /* Used to chain task to an object such as a semaphore or mutex */
+    SLIST_ENTRY(os_task) t_obj_list;
+};
+
+STAILQ_HEAD(os_task_stailq, os_task);
+
+extern struct os_task_stailq g_os_task_list;
+
+int os_task_init(struct os_task *, const char *, os_task_func_t, void *,
+        uint8_t, os_time_t, os_stack_t *, uint16_t);
+
+int os_task_remove(struct os_task *t);
+
+uint8_t os_task_count(void);
+
+struct os_task_info {
+    uint8_t oti_prio;
+    uint8_t oti_taskid;
+    uint8_t oti_state;
+    uint16_t oti_stkusage;
+    uint16_t oti_stksize;
+    uint32_t oti_cswcnt;
+    uint32_t oti_runtime;
+    os_time_t oti_last_checkin;
+    os_time_t oti_next_checkin;
+
+    char oti_name[OS_TASK_MAX_NAME_LEN];
+};
+
+struct os_task *os_task_info_get_next(const struct os_task *,
+        struct os_task_info *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OS_TASK_H */
diff --git a/porting/common/include/os/os_test.h b/porting/common/include/os/os_test.h
new file mode 100644
index 0000000..b71d608
--- /dev/null
+++ b/porting/common/include/os/os_test.h
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 H_OS_TEST_
+#define H_OS_TEST_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int os_test_all(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/porting/common/include/os/os_time.h b/porting/common/include/os/os_time.h
new file mode 100644
index 0000000..2fa07e9
--- /dev/null
+++ b/porting/common/include/os/os_time.h
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+/*-
+ * Copyright (c) 1982, 1986, 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.
+ *
+ *      @(#)time.h      8.5 (Berkeley) 5/4/95
+ * $FreeBSD$
+ */
+
+#ifndef _OS_TIME_H
+#define _OS_TIME_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef UINT32_MAX
+#define UINT32_MAX  0xFFFFFFFFU
+#endif
+
+typedef uint32_t os_time_t;
+typedef int32_t os_stime_t;
+#define OS_TIME_MAX UINT32_MAX
+ 
+/* Used to wait forever for events and mutexs */
+#define OS_TIMEOUT_NEVER    (UINT32_MAX)
+
+os_time_t os_time_get(void);
+void os_time_advance(int ticks);
+void os_time_delay(int32_t osticks);
+
+#define OS_TIME_TICK_LT(__t1, __t2) ((os_stime_t) ((__t1) - (__t2)) < 0)
+#define OS_TIME_TICK_GT(__t1, __t2) ((os_stime_t) ((__t1) - (__t2)) > 0)
+#define OS_TIME_TICK_GEQ(__t1, __t2) ((os_stime_t) ((__t1) - (__t2)) >= 0)
+
+struct os_timeval {
+    int64_t tv_sec;         /* seconds since Jan 1 1970 */
+    int32_t tv_usec;        /* microseconds within the second */
+};
+
+struct os_timezone {
+    int16_t tz_minuteswest;     /* with respect to GMT */
+    int16_t tz_dsttime;         /* daylight savings time correction (if any) */
+};
+
+#define os_timeradd(tvp, uvp, vvp)                                      \
+        do {                                                            \
+                (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec;          \
+                (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec;       \
+                if ((vvp)->tv_usec >= 1000000) {                        \
+                        (vvp)->tv_sec++;                                \
+                        (vvp)->tv_usec -= 1000000;                      \
+                }                                                       \
+        } while (0)
+
+#define os_timersub(tvp, uvp, vvp)                                      \
+        do {                                                            \
+                (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec;          \
+                (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec;       \
+                if ((vvp)->tv_usec < 0) {                               \
+                        (vvp)->tv_sec--;                                \
+                        (vvp)->tv_usec += 1000000;                      \
+                }                                                       \
+        } while (0)
+
+int os_settimeofday(struct os_timeval *utctime, struct os_timezone *tz);
+int os_gettimeofday(struct os_timeval *utctime, struct os_timezone *tz);
+int64_t os_get_uptime_usec(void);
+int os_time_ms_to_ticks(uint32_t ms, uint32_t *out_ticks);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OS_TIME_H */
diff --git a/porting/common/include/os/os_trace_api.h b/porting/common/include/os/os_trace_api.h
new file mode 100644
index 0000000..e01ff20
--- /dev/null
+++ b/porting/common/include/os/os_trace_api.h
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 OS_TRACE_API_H
+#define OS_TRACE_API_H
+
+#include <stdint.h>
+
+#include "syscfg/syscfg.h"
+#include "os/os.h"
+
+#define OS_TRACE_ID_OFFSET                    (32u)
+
+#define OS_TRACE_ID_EVQ_PUT                   (1u + OS_TRACE_ID_OFFSET)
+#define OS_TRACE_ID_EVQ_GET                   (2u + OS_TRACE_ID_OFFSET)
+#define OS_TRACE_ID_MUTEX_INIT                (3u + OS_TRACE_ID_OFFSET)
+#define OS_TRACE_ID_MUTEX_RELEASE             (4u + OS_TRACE_ID_OFFSET)
+#define OS_TRACE_ID_MUTEX_PEND                (5u + OS_TRACE_ID_OFFSET)
+
+#if MYNEWT_VAL(OS_SYSVIEW)
+void os_trace_enter_isr(void);
+void os_trace_exit_isr(void);
+void os_trace_exit_isr_to_scheduler(void);
+void os_trace_task_info(const struct os_task *p_task);
+void os_trace_task_create(uint32_t task_id);
+void os_trace_task_start_exec(uint32_t task_id);
+void os_trace_task_stop_exec(void);
+void os_trace_task_start_ready(uint32_t task_id);
+void os_trace_task_stop_ready(uint32_t task_id, unsigned reason);
+void os_trace_idle(void);
+
+void os_trace_void(unsigned id);
+void os_trace_u32(unsigned id, uint32_t para0);
+void os_trace_u32x2(unsigned id, uint32_t para0, uint32_t para1);
+void os_trace_u32x3(unsigned id, uint32_t para0, uint32_t para1, uint32_t para2);
+void os_trace_u32x4(unsigned id, uint32_t para0, uint32_t para1, uint32_t para2, uint32_t para3);
+void os_trace_u32x5(unsigned id, uint32_t para0, uint32_t para1, uint32_t para2, uint32_t para3, uint32_t para4);
+void os_trace_enter_timer(uint32_t timer_id);
+void os_trace_exit_timer(void);
+
+void os_trace_end_call(unsigned id);
+void os_trace_end_call_return_value(unsigned id, uint32_t return_value);
+
+#else
+
+static inline void os_trace_enter_isr(void){}
+static inline void os_trace_exit_isr(void){}
+static inline void os_trace_exit_isr_to_scheduler(void){}
+static inline void os_trace_task_info(const struct os_task *p_task){}
+static inline void os_trace_task_create(uint32_t task_id){}
+static inline void os_trace_task_start_exec(uint32_t task_id){}
+static inline void os_trace_task_stop_exec(void){}
+static inline void os_trace_task_start_ready(uint32_t task_id){}
+static inline void os_trace_task_stop_ready(uint32_t task_id, unsigned reason){}
+static inline void os_trace_idle(void){}
+static inline void os_trace_void(unsigned id){}
+static inline void os_trace_u32(unsigned id, uint32_t para0){}
+static inline void os_trace_u32x2(unsigned id, uint32_t para0, uint32_t para1){}
+static inline void os_trace_u32x3(unsigned id, uint32_t para0, uint32_t para1, uint32_t para2){}
+static inline void os_trace_u32x4(unsigned id, uint32_t para0, uint32_t para1, uint32_t para2, uint32_t para3){}
+static inline void os_trace_u32x5(unsigned id, uint32_t para0, uint32_t para1, uint32_t para2, uint32_t para3, uint32_t para4){}
+static inline void os_trace_enter_timer(uint32_t timer_id){}
+static inline void os_trace_exit_timer(void){}
+static inline void os_trace_end_call(unsigned id){}
+static inline void os_trace_end_call_return_value(unsigned id, uint32_t return_value){}
+#endif
+
+#endif
diff --git a/porting/common/include/os/queue.h b/porting/common/include/os/queue.h
new file mode 100755
index 0000000..faffd85
--- /dev/null
+++ b/porting/common/include/os/queue.h
@@ -0,0 +1,522 @@
+/*
+ * Copyright (c) 1991, 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.
+ *
+ *	@(#)queue.h	8.5 (Berkeley) 8/20/94
+ * $FreeBSD: src/sys/sys/queue.h,v 1.32.2.7 2002/04/17 14:21:02 des Exp $
+ */
+
+#ifndef _QUEUE_H_
+#define	_QUEUE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This file defines five types of data structures: singly-linked lists,
+ * singly-linked tail queues, lists, tail queues, and circular queues.
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction.  Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A singly-linked tail queue is headed by a pair of pointers, one to the
+ * head of the list and the other to the tail of the list. The elements are
+ * singly linked for minimum space and pointer manipulation overhead at the
+ * expense of O(n) removal for arbitrary elements. New elements can be added
+ * to the list after an existing element, at the head of the list, or at the
+ * end of the list. Elements being removed from the head of the tail queue
+ * should use the explicit macro for this purpose for optimum efficiency.
+ * A singly-linked tail queue may only be traversed in the forward direction.
+ * Singly-linked tail queues are ideal for applications with large datasets
+ * and few or no removals or for implementing a FIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ *
+ *
+ *                      SLIST   LIST    STAILQ  TAILQ   CIRCLEQ
+ * _HEAD                +       +       +       +       +
+ * _HEAD_INITIALIZER    +       +       +       +       +
+ * _ENTRY               +       +       +       +       +
+ * _INIT                +       +       +       +       +
+ * _EMPTY               +       +       +       +       +
+ * _FIRST               +       +       +       +       +
+ * _NEXT                +       +       +       +       +
+ * _PREV                -       -       -       +       +
+ * _LAST                -       -       +       +       +
+ * _FOREACH             +       +       +       +       +
+ * _FOREACH_REVERSE     -       -       -       +       +
+ * _INSERT_HEAD         +       +       +       +       +
+ * _INSERT_BEFORE       -       +       -       +       +
+ * _INSERT_AFTER        +       +       +       +       +
+ * _INSERT_TAIL         -       -       +       +       +
+ * _REMOVE_HEAD         +       -       +       -       -
+ * _REMOVE              +       +       +       +       +
+ *
+ */
+
+/*
+ * Singly-linked List declarations.
+ */
+#define	SLIST_HEAD(name, type)                          \
+struct name {                                           \
+    struct type *slh_first;	/* first element */         \
+}
+
+#define	SLIST_HEAD_INITIALIZER(head)                    \
+    { NULL }
+ 
+#define	SLIST_ENTRY(type)                               \
+struct {                                                \
+    struct type *sle_next;  /* next element */          \
+}
+ 
+/*
+ * Singly-linked List functions.
+ */
+#define SLIST_EMPTY(head)   ((head)->slh_first == NULL)
+
+#define SLIST_FIRST(head)   ((head)->slh_first)
+
+#define SLIST_FOREACH(var, head, field)                 \
+    for ((var) = SLIST_FIRST((head));                   \
+        (var);                                          \
+        (var) = SLIST_NEXT((var), field))
+
+#define SLIST_INIT(head) do {                           \
+        SLIST_FIRST((head)) = NULL;                     \
+} while (0)
+
+#define SLIST_INSERT_AFTER(slistelm, elm, field) do {           \
+    SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field);   \
+    SLIST_NEXT((slistelm), field) = (elm);                      \
+} while (0)
+
+#define SLIST_INSERT_HEAD(head, elm, field) do {            \
+    SLIST_NEXT((elm), field) = SLIST_FIRST((head));         \
+    SLIST_FIRST((head)) = (elm);                            \
+} while (0)
+
+#define SLIST_NEXT(elm, field)	((elm)->field.sle_next)
+
+#define SLIST_REMOVE(head, elm, type, field) do {           \
+    if (SLIST_FIRST((head)) == (elm)) {                     \
+        SLIST_REMOVE_HEAD((head), field);                   \
+    }                                                       \
+    else {                                                  \
+        struct type *curelm = SLIST_FIRST((head));          \
+        while (SLIST_NEXT(curelm, field) != (elm))          \
+            curelm = SLIST_NEXT(curelm, field);             \
+        SLIST_NEXT(curelm, field) =                         \
+            SLIST_NEXT(SLIST_NEXT(curelm, field), field);   \
+    }                                                       \
+} while (0)
+
+#define SLIST_REMOVE_HEAD(head, field) do {                         \
+    SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field);   \
+} while (0)
+
+/*
+ * Singly-linked Tail queue declarations.
+ */
+#define	STAILQ_HEAD(name, type)						\
+struct name {								\
+	struct type *stqh_first;/* first element */			\
+	struct type **stqh_last;/* addr of last next element */		\
+}
+
+#define	STAILQ_HEAD_INITIALIZER(head)					\
+	{ NULL, &(head).stqh_first }
+
+#define	STAILQ_ENTRY(type)						\
+struct {								\
+	struct type *stqe_next;	/* next element */			\
+}
+
+/*
+ * Singly-linked Tail queue functions.
+ */
+#define	STAILQ_EMPTY(head)	((head)->stqh_first == NULL)
+
+#define	STAILQ_FIRST(head)	((head)->stqh_first)
+
+#define	STAILQ_FOREACH(var, head, field)				\
+	for((var) = STAILQ_FIRST((head));				\
+	   (var);							\
+	   (var) = STAILQ_NEXT((var), field))
+
+#define	STAILQ_INIT(head) do {						\
+	STAILQ_FIRST((head)) = NULL;					\
+	(head)->stqh_last = &STAILQ_FIRST((head));			\
+} while (0)
+
+#define	STAILQ_INSERT_AFTER(head, tqelm, elm, field) do {		\
+	if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\
+		(head)->stqh_last = &STAILQ_NEXT((elm), field);		\
+	STAILQ_NEXT((tqelm), field) = (elm);				\
+} while (0)
+
+#define	STAILQ_INSERT_HEAD(head, elm, field) do {			\
+	if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL)	\
+		(head)->stqh_last = &STAILQ_NEXT((elm), field);		\
+	STAILQ_FIRST((head)) = (elm);					\
+} while (0)
+
+#define	STAILQ_INSERT_TAIL(head, elm, field) do {			\
+	STAILQ_NEXT((elm), field) = NULL;				\
+	*(head)->stqh_last = (elm);					\
+	(head)->stqh_last = &STAILQ_NEXT((elm), field);			\
+} while (0)
+
+#define	STAILQ_LAST(head, type, field)					\
+	(STAILQ_EMPTY(head) ?						\
+		NULL :							\
+	        ((struct type *)					\
+		((char *)((head)->stqh_last) - offsetof(struct type, field))))
+
+#define	STAILQ_NEXT(elm, field)	((elm)->field.stqe_next)
+
+#define	STAILQ_REMOVE(head, elm, type, field) do {			\
+	if (STAILQ_FIRST((head)) == (elm)) {				\
+		STAILQ_REMOVE_HEAD(head, field);			\
+	}								\
+	else {								\
+		struct type *curelm = STAILQ_FIRST((head));		\
+		while (STAILQ_NEXT(curelm, field) != (elm))		\
+			curelm = STAILQ_NEXT(curelm, field);		\
+		if ((STAILQ_NEXT(curelm, field) =			\
+		     STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\
+			(head)->stqh_last = &STAILQ_NEXT((curelm), field);\
+	}								\
+} while (0)
+
+#define	STAILQ_REMOVE_HEAD(head, field) do {				\
+	if ((STAILQ_FIRST((head)) =					\
+	     STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL)		\
+		(head)->stqh_last = &STAILQ_FIRST((head));		\
+} while (0)
+
+#define	STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do {			\
+	if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL)	\
+		(head)->stqh_last = &STAILQ_FIRST((head));		\
+} while (0)
+
+#define STAILQ_REMOVE_AFTER(head, elm, field) do {			\
+	if ((STAILQ_NEXT(elm, field) =					\
+	     STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL)	\
+		(head)->stqh_last = &STAILQ_NEXT((elm), field);		\
+} while (0)
+
+/*
+ * List declarations.
+ */
+#define	LIST_HEAD(name, type)						\
+struct name {								\
+	struct type *lh_first;	/* first element */			\
+}
+
+#define	LIST_HEAD_INITIALIZER(head)					\
+	{ NULL }
+
+#define	LIST_ENTRY(type)						\
+struct {								\
+	struct type *le_next;	/* next element */			\
+	struct type **le_prev;	/* address of previous next element */	\
+}
+
+/*
+ * List functions.
+ */
+
+#define	LIST_EMPTY(head)	((head)->lh_first == NULL)
+
+#define	LIST_FIRST(head)	((head)->lh_first)
+
+#define	LIST_FOREACH(var, head, field)					\
+	for ((var) = LIST_FIRST((head));				\
+	    (var);							\
+	    (var) = LIST_NEXT((var), field))
+
+#define	LIST_INIT(head) do {						\
+	LIST_FIRST((head)) = NULL;					\
+} while (0)
+
+#define	LIST_INSERT_AFTER(listelm, elm, field) do {			\
+	if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\
+		LIST_NEXT((listelm), field)->field.le_prev =		\
+		    &LIST_NEXT((elm), field);				\
+	LIST_NEXT((listelm), field) = (elm);				\
+	(elm)->field.le_prev = &LIST_NEXT((listelm), field);		\
+} while (0)
+
+#define	LIST_INSERT_BEFORE(listelm, elm, field) do {			\
+	(elm)->field.le_prev = (listelm)->field.le_prev;		\
+	LIST_NEXT((elm), field) = (listelm);				\
+	*(listelm)->field.le_prev = (elm);				\
+	(listelm)->field.le_prev = &LIST_NEXT((elm), field);		\
+} while (0)
+
+#define	LIST_INSERT_HEAD(head, elm, field) do {				\
+	if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL)	\
+		LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
+	LIST_FIRST((head)) = (elm);					\
+	(elm)->field.le_prev = &LIST_FIRST((head));			\
+} while (0)
+
+#define	LIST_NEXT(elm, field)	((elm)->field.le_next)
+
+#define	LIST_REMOVE(elm, field) do {					\
+	if (LIST_NEXT((elm), field) != NULL)				\
+		LIST_NEXT((elm), field)->field.le_prev = 		\
+		    (elm)->field.le_prev;				\
+	*(elm)->field.le_prev = LIST_NEXT((elm), field);		\
+} while (0)
+
+/*
+ * Tail queue declarations.
+ */
+#define	TAILQ_HEAD(name, type)						\
+struct name {								\
+	struct type *tqh_first;	/* first element */			\
+	struct type **tqh_last;	/* addr of last next element */		\
+}
+
+#define	TAILQ_HEAD_INITIALIZER(head)					\
+	{ NULL, &(head).tqh_first }
+
+#define	TAILQ_ENTRY(type)						\
+struct {								\
+	struct type *tqe_next;	/* next element */			\
+	struct type **tqe_prev;	/* address of previous next element */	\
+}
+
+/*
+ * Tail queue functions.
+ */
+#define	TAILQ_EMPTY(head)	((head)->tqh_first == NULL)
+
+#define	TAILQ_FIRST(head)	((head)->tqh_first)
+
+#define	TAILQ_FOREACH(var, head, field)					\
+	for ((var) = TAILQ_FIRST((head));				\
+	    (var);							\
+	    (var) = TAILQ_NEXT((var), field))
+
+#define	TAILQ_FOREACH_REVERSE(var, head, headname, field)		\
+	for ((var) = TAILQ_LAST((head), headname);			\
+	    (var);							\
+	    (var) = TAILQ_PREV((var), headname, field))
+
+#define	TAILQ_INIT(head) do {						\
+	TAILQ_FIRST((head)) = NULL;					\
+	(head)->tqh_last = &TAILQ_FIRST((head));			\
+} while (0)
+
+#define	TAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\
+		TAILQ_NEXT((elm), field)->field.tqe_prev = 		\
+		    &TAILQ_NEXT((elm), field);				\
+	else								\
+		(head)->tqh_last = &TAILQ_NEXT((elm), field);		\
+	TAILQ_NEXT((listelm), field) = (elm);				\
+	(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field);		\
+} while (0)
+
+#define	TAILQ_INSERT_BEFORE(listelm, elm, field) do {			\
+	(elm)->field.tqe_prev = (listelm)->field.tqe_prev;		\
+	TAILQ_NEXT((elm), field) = (listelm);				\
+	*(listelm)->field.tqe_prev = (elm);				\
+	(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field);		\
+} while (0)
+
+#define	TAILQ_INSERT_HEAD(head, elm, field) do {			\
+	if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL)	\
+		TAILQ_FIRST((head))->field.tqe_prev =			\
+		    &TAILQ_NEXT((elm), field);				\
+	else								\
+		(head)->tqh_last = &TAILQ_NEXT((elm), field);		\
+	TAILQ_FIRST((head)) = (elm);					\
+	(elm)->field.tqe_prev = &TAILQ_FIRST((head));			\
+} while (0)
+
+#define	TAILQ_INSERT_TAIL(head, elm, field) do {			\
+	TAILQ_NEXT((elm), field) = NULL;				\
+	(elm)->field.tqe_prev = (head)->tqh_last;			\
+	*(head)->tqh_last = (elm);					\
+	(head)->tqh_last = &TAILQ_NEXT((elm), field);			\
+} while (0)
+
+#define	TAILQ_LAST(head, headname)					\
+	(*(((struct headname *)((head)->tqh_last))->tqh_last))
+
+#define	TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+
+#define	TAILQ_PREV(elm, headname, field)				\
+	(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+
+#define	TAILQ_REMOVE(head, elm, field) do {				\
+	if ((TAILQ_NEXT((elm), field)) != NULL)				\
+		TAILQ_NEXT((elm), field)->field.tqe_prev = 		\
+		    (elm)->field.tqe_prev;				\
+	else								\
+		(head)->tqh_last = (elm)->field.tqe_prev;		\
+	*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field);		\
+} while (0)
+
+/*
+ * Circular queue declarations.
+ */
+#define	CIRCLEQ_HEAD(name, type)					\
+struct name {								\
+	struct type *cqh_first;		/* first element */		\
+	struct type *cqh_last;		/* last element */		\
+}
+
+#define	CIRCLEQ_HEAD_INITIALIZER(head)					\
+	{ (void *)&(head), (void *)&(head) }
+
+#define	CIRCLEQ_ENTRY(type)						\
+struct {								\
+	struct type *cqe_next;		/* next element */		\
+	struct type *cqe_prev;		/* previous element */		\
+}
+
+/*
+ * Circular queue functions.
+ */
+#define	CIRCLEQ_EMPTY(head)	((head)->cqh_first == (void *)(head))
+
+#define	CIRCLEQ_FIRST(head)	((head)->cqh_first)
+
+#define	CIRCLEQ_FOREACH(var, head, field)				\
+	for ((var) = CIRCLEQ_FIRST((head));				\
+	    (var) != (void *)(head) || ((var) = NULL);			\
+	    (var) = CIRCLEQ_NEXT((var), field))
+
+#define	CIRCLEQ_FOREACH_REVERSE(var, head, field)			\
+	for ((var) = CIRCLEQ_LAST((head));				\
+	    (var) != (void *)(head) || ((var) = NULL);			\
+	    (var) = CIRCLEQ_PREV((var), field))
+
+#define	CIRCLEQ_INIT(head) do {						\
+	CIRCLEQ_FIRST((head)) = (void *)(head);				\
+	CIRCLEQ_LAST((head)) = (void *)(head);				\
+} while (0)
+
+#define	CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	CIRCLEQ_NEXT((elm), field) = CIRCLEQ_NEXT((listelm), field);	\
+	CIRCLEQ_PREV((elm), field) = (listelm);				\
+	if (CIRCLEQ_NEXT((listelm), field) == (void *)(head))		\
+		CIRCLEQ_LAST((head)) = (elm);				\
+	else								\
+		CIRCLEQ_PREV(CIRCLEQ_NEXT((listelm), field), field) = (elm);\
+	CIRCLEQ_NEXT((listelm), field) = (elm);				\
+} while (0)
+
+#define	CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do {		\
+	CIRCLEQ_NEXT((elm), field) = (listelm);				\
+	CIRCLEQ_PREV((elm), field) = CIRCLEQ_PREV((listelm), field);	\
+	if (CIRCLEQ_PREV((listelm), field) == (void *)(head))		\
+		CIRCLEQ_FIRST((head)) = (elm);				\
+	else								\
+		CIRCLEQ_NEXT(CIRCLEQ_PREV((listelm), field), field) = (elm);\
+	CIRCLEQ_PREV((listelm), field) = (elm);				\
+} while (0)
+
+#define	CIRCLEQ_INSERT_HEAD(head, elm, field) do {			\
+	CIRCLEQ_NEXT((elm), field) = CIRCLEQ_FIRST((head));		\
+	CIRCLEQ_PREV((elm), field) = (void *)(head);			\
+	if (CIRCLEQ_LAST((head)) == (void *)(head))			\
+		CIRCLEQ_LAST((head)) = (elm);				\
+	else								\
+		CIRCLEQ_PREV(CIRCLEQ_FIRST((head)), field) = (elm);	\
+	CIRCLEQ_FIRST((head)) = (elm);					\
+} while (0)
+
+#define	CIRCLEQ_INSERT_TAIL(head, elm, field) do {			\
+	CIRCLEQ_NEXT((elm), field) = (void *)(head);			\
+	CIRCLEQ_PREV((elm), field) = CIRCLEQ_LAST((head));		\
+	if (CIRCLEQ_FIRST((head)) == (void *)(head))			\
+		CIRCLEQ_FIRST((head)) = (elm);				\
+	else								\
+		CIRCLEQ_NEXT(CIRCLEQ_LAST((head)), field) = (elm);	\
+	CIRCLEQ_LAST((head)) = (elm);					\
+} while (0)
+
+#define	CIRCLEQ_LAST(head)	((head)->cqh_last)
+
+#define	CIRCLEQ_NEXT(elm,field)	((elm)->field.cqe_next)
+
+#define	CIRCLEQ_PREV(elm,field)	((elm)->field.cqe_prev)
+
+#define	CIRCLEQ_REMOVE(head, elm, field) do {				\
+	if (CIRCLEQ_NEXT((elm), field) == (void *)(head))		\
+		CIRCLEQ_LAST((head)) = CIRCLEQ_PREV((elm), field);	\
+	else								\
+		CIRCLEQ_PREV(CIRCLEQ_NEXT((elm), field), field) =	\
+		    CIRCLEQ_PREV((elm), field);				\
+	if (CIRCLEQ_PREV((elm), field) == (void *)(head))		\
+		CIRCLEQ_FIRST((head)) = CIRCLEQ_NEXT((elm), field);	\
+	else								\
+		CIRCLEQ_NEXT(CIRCLEQ_PREV((elm), field), field) =	\
+		    CIRCLEQ_NEXT((elm), field);				\
+} while (0)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_QUEUE_H_ */
diff --git a/porting/common/include/stats/stats.h b/porting/common/include/stats/stats.h
new file mode 100644
index 0000000..ac2a182
--- /dev/null
+++ b/porting/common/include/stats/stats.h
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 __UTIL_STATS_H__
+#define __UTIL_STATS_H__
+
+#include <stdint.h>
+#include "syscfg/syscfg.h"
+#include "os/queue.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct stats_name_map {
+    uint16_t snm_off;
+    char *snm_name;
+} __attribute__((packed));
+
+struct stats_hdr {
+    char *s_name;
+    uint8_t s_size;
+    uint8_t s_cnt;
+    uint16_t s_pad1;
+#if MYNEWT_VAL(STATS_NAMES)
+    const struct stats_name_map *s_map;
+    int s_map_cnt;
+#endif
+    STAILQ_ENTRY(stats_hdr) s_next;
+};
+
+#define STATS_SECT_DECL(__name)                                         \
+    struct stats_ ## __name
+#define STATS_SECT_END };
+
+#define STATS_SECT_START(__name)                                        \
+    STATS_SECT_DECL(__name) {
+#define STATS_SECT_VAR(__var)
+
+#define STATS_HDR(__sectname)
+
+#define STATS_SECT_ENTRY(__var)
+#define STATS_SECT_ENTRY16(__var)
+#define STATS_SECT_ENTRY32(__var)
+#define STATS_SECT_ENTRY64(__var)
+#define STATS_RESET(__var)
+
+#define STATS_SIZE_INIT_PARMS(__sectvarname, __size) 0, 0
+
+#define STATS_INC(__sectvarname, __var)
+#define STATS_INCN(__sectvarname, __var, __n)
+#define STATS_CLEAR(__sectvarname, __var)
+
+#define STATS_NAME_START(__name)
+#define STATS_NAME(__name, __entry)
+#define STATS_NAME_END(__name)
+#define STATS_NAME_INIT_PARMS(__name) NULL, 0
+
+#define stats_init(...) 0
+#define stats_register(name, shdr) 0
+#define stats_init_and_reg(...) 0
+#define stats_reset(shdr)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __UTIL_STATS_H__ */
diff --git a/porting/common/include/sysinit/sysinit.h b/porting/common/include/sysinit/sysinit.h
new file mode 100644
index 0000000..7694c42
--- /dev/null
+++ b/porting/common/include/sysinit/sysinit.h
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 H_SYSINIT_
+#define H_SYSINIT_
+
+#include <inttypes.h>
+#include <assert.h>
+#include "syscfg/syscfg.h"
+
+#if MYNEWT_VAL(SPLIT_APPLICATION)
+#include "split/split.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern uint8_t sysinit_active;
+
+void sysinit_start(void);
+void sysinit_end(void);
+
+typedef void sysinit_panic_fn(const char *file, int line, const char *func,
+                              const char *expr, const char *msg);
+
+extern sysinit_panic_fn *sysinit_panic_cb;
+
+void sysinit_panic_set(sysinit_panic_fn *panic_fn);
+
+#if MYNEWT_VAL(SYSINIT_PANIC_MESSAGE)
+
+#if MYNEWT_VAL(SYSINIT_PANIC_FILE_LINE)
+#define SYSINIT_PANIC_MSG(msg) sysinit_panic_cb(__FILE__, __LINE__, 0, 0, msg)
+#else
+#define SYSINIT_PANIC_MSG(msg) sysinit_panic_cb(0, 0, 0, 0, msg)
+#endif
+
+#else
+
+#if MYNEWT_VAL(SYSINIT_PANIC_FILE_LINE)
+#define SYSINIT_PANIC_MSG(msg) sysinit_panic_cb(__FILE__, __LINE__, 0, 0, 0)
+#else
+#define SYSINIT_PANIC_MSG(msg) sysinit_panic_cb(0, 0, 0, 0, 0)
+#endif
+
+#endif
+
+#define SYSINIT_PANIC() SYSINIT_PANIC_MSG(NULL)
+
+#define SYSINIT_PANIC_ASSERT_MSG(rc, msg) do \
+{                                            \
+    if (!(rc)) {                             \
+        SYSINIT_PANIC_MSG(msg);              \
+    }                                        \
+} while (0)
+
+#define SYSINIT_PANIC_ASSERT(rc) SYSINIT_PANIC_ASSERT_MSG(rc, NULL)
+
+/**
+ * Asserts that system initialization is in progress.  This macro is used to
+ * ensure packages don't get initialized a second time after system
+ * initialization has completed.
+ */
+#if MYNEWT_VAL(SYSINIT_CONSTRAIN_INIT)
+#define SYSINIT_ASSERT_ACTIVE() assert(sysinit_active)
+#else
+#define SYSINIT_ASSERT_ACTIVE()
+#endif
+
+#if MYNEWT_VAL(SPLIT_LOADER)
+
+/*** System initialization for loader (first stage of split image). */
+void sysinit_loader(void);
+#define sysinit() do                                                        \
+{                                                                           \
+    sysinit_start();                                                        \
+    sysinit_loader();                                                       \
+    sysinit_end();                                                          \
+} while (0)
+
+#elif MYNEWT_VAL(SPLIT_APPLICATION)
+
+/*** System initialization for split-app (second stage of split image). */
+void sysinit_app(void);
+#define sysinit() do                                                        \
+{                                                                           \
+    /* Record that a split app is running; imgmgt needs to know this. */    \
+    split_app_active_set(1);                                                \
+    sysinit_start();                                                        \
+    sysinit_app();                                                          \
+    sysinit_end();                                                          \
+} while (0)
+
+#else
+
+/*** System initialization for a unified image (no split). */
+void sysinit_app(void);
+#define sysinit() do                                                        \
+{                                                                           \
+    sysinit_start();                                                        \
+    sysinit_app();                                                          \
+    sysinit_end();                                                          \
+} while (0)
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/porting/common/src/mem/mem.c b/porting/common/src/mem/mem.c
new file mode 100644
index 0000000..340e60e
--- /dev/null
+++ b/porting/common/src/mem/mem.c
@@ -0,0 +1,245 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 "os/os.h"
+#include "mem/mem.h"
+
+/**
+ * Mallocs a block of memory and initializes a mempool to use it.
+ *
+ * @param mempool               The mempool to initialize.
+ * @param num_blocks            The total number of memory blocks in the
+ *                                  mempool.
+ * @param block_size            The size of each mempool entry.
+ * @param name                  The name to give the mempool.
+ * @param out_buf               On success, this points to the malloced memory.
+ *                                  Pass NULL if you don't need this
+ *                                  information.
+ *
+ * @return                      0 on success;
+ *                              OS_ENOMEM on malloc failure;
+ *                              Other OS code on unexpected error.
+ */
+int
+mem_malloc_mempool(struct os_mempool *mempool, int num_blocks, int block_size,
+                   char *name, void **out_buf)
+{
+    void *buf;
+    int rc;
+
+    block_size = OS_ALIGN(block_size, OS_ALIGNMENT);
+
+    if (num_blocks > 0) {
+        buf = malloc(OS_MEMPOOL_BYTES(num_blocks, block_size));
+        if (buf == NULL) {
+            return OS_ENOMEM;
+        }
+    } else {
+        buf = NULL;
+    }
+
+    rc = os_mempool_init(mempool, num_blocks, block_size, buf, name);
+    if (rc != 0) {
+        free(buf);
+        return rc;
+    }
+
+    if (out_buf != NULL) {
+        *out_buf = buf;
+    }
+
+    return 0;
+}
+
+/**
+ * Mallocs a block of memory and initializes an mbuf pool to use it.  The
+ * specified block_size indicates the size of an mbuf acquired from the pool if
+ * it does not contain a pkthdr.
+ *
+ * @param mempool               The mempool to initialize.
+ * @param mbuf_pool             The mbuf pool to initialize.
+ * @param num_blocks            The total number of mbufs in the pool.
+ * @param block_size            The size of each mbuf.
+ * @param name                  The name to give the mempool.
+ * @param out_buf               On success, this points to the malloced memory.
+ *                                  Pass NULL if you don't need this
+ *                                  information.
+ *
+ * @return                      0 on success;
+ *                              OS_ENOMEM on malloc failure;
+ *                              Other OS code on unexpected error.
+ */
+int
+mem_malloc_mbuf_pool(struct os_mempool *mempool,
+                     struct os_mbuf_pool *mbuf_pool, int num_blocks,
+                     int block_size, char *name,
+                     void **out_buf)
+{
+    void *buf;
+    int rc;
+
+    block_size = OS_ALIGN(block_size + sizeof (struct os_mbuf), OS_ALIGNMENT);
+
+    rc = mem_malloc_mempool(mempool, num_blocks, block_size, name, &buf);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = os_mbuf_pool_init(mbuf_pool, mempool, block_size, num_blocks);
+    if (rc != 0) {
+        free(buf);
+        return rc;
+    }
+
+    if (out_buf != NULL) {
+        *out_buf = buf;
+    }
+
+    return 0;
+}
+
+/**
+ * Mallocs a block of memory and initializes an mbuf pool to use it.  The
+ * specified block_size indicates the size of an mbuf acquired from the pool if
+ * it contains a pkthdr.
+ *
+ * @param mempool               The mempool to initialize.
+ * @param mbuf_pool             The mbuf pool to initialize.
+ * @param num_blocks            The total number of mbufs in the pool.
+ * @param block_size            The size of each mbuf.
+ * @param name                  The name to give the mempool.
+ * @param out_buf               On success, this points to the malloced memory.
+ *                                  Pass NULL if you don't need this
+ *                                  information.
+ *
+ * @return                      0 on success;
+ *                              OS_ENOMEM on malloc failure;
+ *                              Other OS code on unexpected error.
+ */
+int
+mem_malloc_mbufpkt_pool(struct os_mempool *mempool,
+                        struct os_mbuf_pool *mbuf_pool, int num_blocks,
+                        int block_size, char *name,
+                        void **out_buf)
+{
+    int rc;
+
+    rc = mem_malloc_mbuf_pool(mempool, mbuf_pool, num_blocks,
+                              block_size + sizeof (struct os_mbuf_pkthdr),
+                              name, out_buf);
+    return rc;
+}
+
+int
+mem_init_mbuf_pool(void *mem, struct os_mempool *mempool,
+                   struct os_mbuf_pool *mbuf_pool, int num_blocks,
+                   int block_size, char *name)
+{
+    int rc;
+
+    rc = os_mempool_init(mempool, num_blocks, block_size, mem, name);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = os_mbuf_pool_init(mbuf_pool, mempool, block_size, num_blocks);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+/*
+ * Splits an appropriately-sized fragment from the front of an mbuf chain, as
+ * neeeded.  If the length of the mbuf chain greater than specified maximum
+ * fragment size, a new mbuf is allocated, and data is moved from the source
+ * mbuf to the new mbuf.  If the mbuf chain is small enough to fit in a single
+ * fragment, the source mbuf itself is returned unmodified, and the suplied
+ * pointer is set to NULL.
+ *
+ * This function is expected to be called in a loop until the entire mbuf chain
+ * has been consumed.  For example:
+ *
+ *     struct os_mbuf *frag;
+ *     struct os_mbuf *rsp;
+ *     // [...]
+ *     while (rsp != NULL) {
+ *         frag = mem_split_frag(&rsp, get_mtu(), frag_alloc, NULL);
+ *         if (frag == NULL) {
+ *             os_mbuf_free_chain(rsp);
+ *             return SYS_ENOMEM;
+ *         }
+ *         send_packet(frag)
+ *     }
+ *
+ * @param om                    The packet to fragment.  Upon fragmentation,
+ *                                  this mbuf is adjusted such that the
+ *                                  fragment data is removed.  If the packet
+ *                                  constitutes a single fragment, this gets
+ *                                  set to NULL on success.
+ * @param max_frag_sz           The maximum payload size of a fragment.
+ *                                  Typically this is the MTU of the
+ *                                  connection.
+ * @param alloc_cb              Points to a function that allocates an mbuf to
+ *                                  hold a fragment.  This function gets called
+ *                                  before the source mbuf chain is modified,
+ *                                  so it can safely inspect it.
+ * @param cb_arg                Generic parameter that gets passed to the
+ *                                  callback function.
+ *
+ * @return                      The next fragment to send on success;
+ *                              NULL on failure.
+ */
+struct os_mbuf *
+mem_split_frag(struct os_mbuf **om, uint16_t max_frag_sz,
+               mem_frag_alloc_fn *alloc_cb, void *cb_arg)
+{
+    struct os_mbuf *frag;
+    int rc;
+
+    if (OS_MBUF_PKTLEN(*om) <= max_frag_sz) {
+        /* Final fragment. */
+        frag = *om;
+        *om = NULL;
+        return frag;
+    }
+
+    /* Packet needs to be split.  Allocate a new buffer for the fragment. */
+    frag = alloc_cb(max_frag_sz, cb_arg);
+    if (frag == NULL) {
+        goto err;
+    }
+
+    /* Move data from the front of the packet into the fragment mbuf. */
+    rc = os_mbuf_appendfrom(frag, *om, 0, max_frag_sz);
+    if (rc != 0) {
+        goto err;
+    }
+    os_mbuf_adj(*om, max_frag_sz);
+
+    /* Free unused portion of of source mbuf chain, if possible. */
+    *om = os_mbuf_trim_front(*om);
+
+    return frag;
+
+err:
+    os_mbuf_free_chain(frag);
+    return NULL;
+}
diff --git a/porting/common/src/nimble_port.c b/porting/common/src/nimble_port.c
new file mode 100644
index 0000000..8f8daa9
--- /dev/null
+++ b/porting/common/src/nimble_port.c
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 <stddef.h>
+#include "os/os.h"
+#include "sysinit/sysinit.h"
+#include "host/ble_hs.h"
+#include "services/gap/ble_svc_gap.h"
+#include "services/gatt/ble_svc_gatt.h"
+#include "services/ans/ble_svc_ans.h"
+#include "services/ias/ble_svc_ias.h"
+#include "services/lls/ble_svc_lls.h"
+#include "services/tps/ble_svc_tps.h"
+#include "controller/ble_ll.h"
+
+void
+nimble_init(void)
+{
+    void os_msys_init(void);
+    void ble_hci_ram_pkg_init(void);
+    void ble_store_ram_init(void);
+
+    sysinit_start();
+    os_msys_init();
+    ble_hci_ram_pkg_init();
+    ble_hs_init();
+    ble_ll_init();
+    ble_svc_gap_init();
+    ble_svc_gatt_init();
+    ble_svc_ans_init();
+    ble_svc_ias_init();
+    ble_svc_lls_init();
+    ble_svc_tps_init();
+    ble_store_ram_init();
+    sysinit_end();
+}
+
+void
+nimble_run(void)
+{
+    while (1) {
+        struct os_event *ev;
+
+        ev = os_eventq_get(os_eventq_dflt_get());
+        assert(ev->ev_cb != NULL);
+
+        ev->ev_cb(ev);
+    }
+}
diff --git a/porting/common/src/os/endian.c b/porting/common/src/os/endian.c
new file mode 100644
index 0000000..1311f43
--- /dev/null
+++ b/porting/common/src/os/endian.c
@@ -0,0 +1,218 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 "os/endian.h"
+
+void
+put_le16(void *buf, uint16_t x)
+{
+    uint8_t *u8ptr;
+
+    u8ptr = buf;
+    u8ptr[0] = (uint8_t)x;
+    u8ptr[1] = (uint8_t)(x >> 8);
+}
+
+void
+put_le32(void *buf, uint32_t x)
+{
+    uint8_t *u8ptr;
+
+    u8ptr = buf;
+    u8ptr[0] = (uint8_t)x;
+    u8ptr[1] = (uint8_t)(x >> 8);
+    u8ptr[2] = (uint8_t)(x >> 16);
+    u8ptr[3] = (uint8_t)(x >> 24);
+}
+
+void
+put_le64(void *buf, uint64_t x)
+{
+    uint8_t *u8ptr;
+
+    u8ptr = buf;
+    u8ptr[0] = (uint8_t)x;
+    u8ptr[1] = (uint8_t)(x >> 8);
+    u8ptr[2] = (uint8_t)(x >> 16);
+    u8ptr[3] = (uint8_t)(x >> 24);
+    u8ptr[4] = (uint8_t)(x >> 32);
+    u8ptr[5] = (uint8_t)(x >> 40);
+    u8ptr[6] = (uint8_t)(x >> 48);
+    u8ptr[7] = (uint8_t)(x >> 56);
+}
+
+uint16_t
+get_le16(const void *buf)
+{
+    const uint8_t *u8ptr;
+    uint16_t x;
+
+    u8ptr = buf;
+    x = u8ptr[0];
+    x |= (uint16_t)u8ptr[1] << 8;
+
+    return x;
+}
+
+uint32_t
+get_le32(const void *buf)
+{
+    const uint8_t *u8ptr;
+    uint32_t x;
+
+    u8ptr = buf;
+    x = u8ptr[0];
+    x |= (uint32_t)u8ptr[1] << 8;
+    x |= (uint32_t)u8ptr[2] << 16;
+    x |= (uint32_t)u8ptr[3] << 24;
+
+    return x;
+}
+
+uint64_t
+get_le64(const void *buf)
+{
+    const uint8_t *u8ptr;
+    uint64_t x;
+
+    u8ptr = buf;
+    x = u8ptr[0];
+    x |= (uint64_t)u8ptr[1] << 8;
+    x |= (uint64_t)u8ptr[2] << 16;
+    x |= (uint64_t)u8ptr[3] << 24;
+    x |= (uint64_t)u8ptr[4] << 32;
+    x |= (uint64_t)u8ptr[5] << 40;
+    x |= (uint64_t)u8ptr[6] << 48;
+    x |= (uint64_t)u8ptr[7] << 56;
+
+    return x;
+}
+
+void
+put_be16(void *buf, uint16_t x)
+{
+    uint8_t *u8ptr;
+
+    u8ptr = buf;
+    u8ptr[0] = (uint8_t)(x >> 8);
+    u8ptr[1] = (uint8_t)x;
+}
+
+void
+put_be32(void *buf, uint32_t x)
+{
+    uint8_t *u8ptr;
+
+    u8ptr = buf;
+    u8ptr[0] = (uint8_t)(x >> 24);
+    u8ptr[1] = (uint8_t)(x >> 16);
+    u8ptr[2] = (uint8_t)(x >> 8);
+    u8ptr[3] = (uint8_t)x;
+}
+
+void
+put_be64(void *buf, uint64_t x)
+{
+    uint8_t *u8ptr;
+
+    u8ptr = buf;
+    u8ptr[0] = (uint8_t)(x >> 56);
+    u8ptr[1] = (uint8_t)(x >> 48);
+    u8ptr[2] = (uint8_t)(x >> 40);
+    u8ptr[3] = (uint8_t)(x >> 32);
+    u8ptr[4] = (uint8_t)(x >> 24);
+    u8ptr[5] = (uint8_t)(x >> 16);
+    u8ptr[6] = (uint8_t)(x >> 8);
+    u8ptr[7] = (uint8_t)x;
+}
+
+uint16_t
+get_be16(const void *buf)
+{
+    const uint8_t *u8ptr;
+    uint16_t x;
+
+    u8ptr = buf;
+    x = (uint16_t)u8ptr[0] << 8;
+    x |= u8ptr[1];
+
+    return x;
+}
+
+uint32_t
+get_be32(const void *buf)
+{
+    const uint8_t *u8ptr;
+    uint32_t x;
+
+    u8ptr = buf;
+    x = (uint32_t)u8ptr[0] << 24;
+    x |= (uint32_t)u8ptr[1] << 16;
+    x |= (uint32_t)u8ptr[2] << 8;
+    x |= u8ptr[3];
+
+    return x;
+}
+
+uint64_t
+get_be64(const void *buf)
+{
+    const uint8_t *u8ptr;
+    uint64_t x;
+
+    u8ptr = buf;
+    x = (uint64_t)u8ptr[0] << 56;
+    x |= (uint64_t)u8ptr[1] << 48;
+    x |= (uint64_t)u8ptr[2] << 40;
+    x |= (uint64_t)u8ptr[3] << 32;
+    x |= (uint64_t)u8ptr[4] << 24;
+    x |= (uint64_t)u8ptr[5] << 16;
+    x |= (uint64_t)u8ptr[6] << 8;
+    x |= u8ptr[7];
+
+    return x;
+}
+void
+swap_in_place(void *buf, int len)
+{
+    uint8_t *u8ptr;
+    uint8_t tmp;
+    int i;
+    int j;
+
+    u8ptr = buf;
+
+    for (i = 0, j = len - 1; i < j; i++, j--) {
+        tmp = u8ptr[i];
+
+        u8ptr[i] = u8ptr[j];
+        u8ptr[j] = tmp;
+    }
+}
+
+/* swap octets */
+void
+swap_buf(uint8_t *dst, const uint8_t *src, int len)
+{
+    int i;
+
+    for (i = 0; i < len; i++) {
+        dst[len - 1 - i] = src[i];
+    }
+}
diff --git a/porting/common/src/os/os.c b/porting/common/src/os/os.c
new file mode 100644
index 0000000..b8ec3ff
--- /dev/null
+++ b/porting/common/src/os/os.c
@@ -0,0 +1,240 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 "sysinit/sysinit.h"
+#include "os/os.h"
+#include "os/queue.h"
+#include "os/os_dev.h"
+#include "os/os_trace_api.h"
+#include "hal/hal_os_tick.h"
+#include "hal/hal_bsp.h"
+#include "hal/hal_watchdog.h"
+
+#include <assert.h>
+#include "../os/os_priv.h"
+
+/**
+ * @defgroup OSKernel Operating System Kernel
+ * @brief This section contains documentation for the core operating system kernel
+ * of Apache Mynewt.
+ * @{
+ *   @addtogroup OSGeneral General Functions
+ *   @{
+ */
+
+struct os_task g_idle_task;
+os_stack_t g_idle_task_stack[OS_STACK_ALIGN(OS_IDLE_STACK_SIZE)];
+
+uint32_t g_os_idle_ctr;
+
+static struct os_task os_main_task;
+static os_stack_t os_main_stack[OS_STACK_ALIGN(OS_MAIN_STACK_SIZE)];
+
+/* Default zero.  Set by the architecture specific code when os is started.
+ */
+int g_os_started;
+
+#ifdef ARCH_sim
+#define MIN_IDLE_TICKS  1
+#else
+#define MIN_IDLE_TICKS  (100 * OS_TICKS_PER_SEC / 1000) /* 100 msec */
+#endif
+#define MAX_IDLE_TICKS  (600 * OS_TICKS_PER_SEC)        /* 10 minutes */
+
+
+/**
+ * Idle operating system task, runs when no other tasks are running.
+ * The idle task operates in tickless mode, which means it looks for
+ * the next time an event in the system needs to run, and then tells
+ * the architecture specific functions to sleep until that time.
+ *
+ * @param arg unused
+ */
+void
+os_idle_task(void *arg)
+{
+    os_sr_t sr;
+    os_time_t now;
+    os_time_t iticks, sticks, cticks;
+    os_time_t sanity_last;
+    os_time_t sanity_itvl_ticks;
+
+    sanity_itvl_ticks = (MYNEWT_VAL(SANITY_INTERVAL) * OS_TICKS_PER_SEC) / 1000;
+    sanity_last = 0;
+
+    hal_watchdog_tickle();
+
+    while (1) {
+        ++g_os_idle_ctr;
+
+        now = os_time_get();
+        if (OS_TIME_TICK_GT(now, sanity_last + sanity_itvl_ticks)) {
+            os_sanity_run();
+            /* Tickle the watchdog after successfully running sanity */
+            hal_watchdog_tickle();
+            sanity_last = now;
+        }
+
+        OS_ENTER_CRITICAL(sr);
+        now = os_time_get();
+        sticks = os_sched_wakeup_ticks(now);
+        cticks = os_callout_wakeup_ticks(now);
+        iticks = min(sticks, cticks);
+        /* Wakeup in time to run sanity as well from the idle context,
+         * as the idle task does not schedule itself.
+         */
+        iticks = min(iticks, ((sanity_last + sanity_itvl_ticks) - now));
+
+        if (iticks < MIN_IDLE_TICKS) {
+            iticks = 0;
+        } else if (iticks > MAX_IDLE_TICKS) {
+            iticks = MAX_IDLE_TICKS;
+        } else {
+            /* NOTHING */
+        }
+        /* Tell the architecture specific support to put the processor to sleep
+         * for 'n' ticks.
+         */
+
+        os_trace_idle();
+        os_tick_idle(iticks);
+        OS_EXIT_CRITICAL(sr);
+    }
+}
+
+/**
+ * Has the operating system started.
+ *
+ * @return 1 if the operating system has started, 0 if it hasn't
+ */
+int
+os_started(void)
+{
+    return (g_os_started);
+}
+
+static void
+os_main(void *arg)
+{
+    int (*fn)(int argc, char **argv) = arg;
+
+#if !MYNEWT_VAL(SELFTEST)
+    fn(0, NULL);
+#else
+    (void)fn;
+    while (1) {
+        os_eventq_run(os_eventq_dflt_get());
+    }
+#endif
+    assert(0);
+}
+
+void
+os_init_idle_task(void)
+{
+    int rc;
+
+    rc = os_task_init(&g_idle_task, "idle", os_idle_task, NULL,
+            OS_IDLE_PRIO, OS_WAIT_FOREVER, g_idle_task_stack,
+            OS_STACK_ALIGN(OS_IDLE_STACK_SIZE));
+    assert(rc == 0);
+
+    /* Initialize sanity */
+    rc = os_sanity_init();
+    assert(rc == 0);
+
+    assert(MYNEWT_VAL(WATCHDOG_INTERVAL) - 200 > MYNEWT_VAL(SANITY_INTERVAL));
+
+    rc = hal_watchdog_init(MYNEWT_VAL(WATCHDOG_INTERVAL));
+    assert(rc == 0);
+}
+
+/**
+ * Initialize the operating system, calls into the architecture specific
+ * support to initialize the operating system.
+ */
+void
+os_init(int (*main_fn)(int argc, char **arg))
+{
+    os_error_t err;
+
+    TAILQ_INIT(&g_callout_list);
+    STAILQ_INIT(&g_os_task_list);
+    os_eventq_init(os_eventq_dflt_get());
+
+    /* Initialize device list. */
+    os_dev_reset();
+
+    err = os_arch_os_init();
+    assert(err == OS_OK);
+
+    if (main_fn) {
+        err = os_task_init(&os_main_task, "main", os_main, main_fn,
+                           OS_MAIN_TASK_PRIO, OS_WAIT_FOREVER, os_main_stack,
+                           OS_STACK_ALIGN(OS_MAIN_STACK_SIZE));
+        assert(err == 0);
+    }
+    /* Call bsp related OS initializations */
+    hal_bsp_init();
+
+    err = (os_error_t) os_dev_initialize_all(OS_DEV_INIT_PRIMARY);
+    assert(err == OS_OK);
+
+    err = (os_error_t) os_dev_initialize_all(OS_DEV_INIT_SECONDARY);
+    assert(err == OS_OK);
+}
+
+/**
+ * Start the operating system, calls into the architecture specific support
+ * to start the operating system.
+ */
+void
+os_start(void)
+{
+#if MYNEWT_VAL(OS_SCHEDULING)
+    os_error_t err;
+
+    /* Enable the watchdog prior to starting the OS */
+    hal_watchdog_enable();
+
+    err = os_arch_os_start();
+    assert(err == OS_OK);
+#else
+    assert(0);
+#endif
+}
+
+void
+os_pkg_init(void)
+{
+    os_error_t err;
+
+    /* Ensure this function only gets called by sysinit. */
+    SYSINIT_ASSERT_ACTIVE();
+
+    err = os_dev_initialize_all(OS_DEV_INIT_KERNEL);
+    assert(err == OS_OK);
+
+    os_msys_init();
+}
+
+/**
+ *   }@ General OS functions
+ * }@ OS Kernel
+ */
diff --git a/porting/common/src/os/os_callout.c b/porting/common/src/os/os_callout.c
new file mode 100644
index 0000000..e8deeab
--- /dev/null
+++ b/porting/common/src/os/os_callout.c
@@ -0,0 +1,230 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 <assert.h>
+#include <string.h>
+
+#include "../os/os_priv.h"
+#include "os/os.h"
+
+/**
+ * @addtogroup OSKernel
+ * @{
+ *   @defgroup OSCallouts Event Timers (Callouts)
+ *   @{
+ */
+struct os_callout_list g_callout_list;
+
+/**
+ * Initialize a callout.
+ *
+ * Callouts are used to schedule events in the future onto a task's event
+ * queue.  Callout timers are scheduled using the os_callout_reset()
+ * function.  When the timer expires, an event is posted to the event
+ * queue specified in os_callout_init().  The event argument given here
+ * is posted in the ev_arg field of that event.
+ *
+ * @param c The callout to initialize
+ * @param evq The event queue to post an OS_EVENT_T_TIMER event to
+ * @param timo_func The function to call on this callout for the host task
+ *                  used to provide multiple timer events to a task
+ *                  (this can be NULL.)
+ * @param ev_arg The argument to provide to the event when posting the
+ *               timer.
+ */
+void os_callout_init(struct os_callout *c, struct os_eventq *evq,
+                     os_event_fn *ev_cb, void *ev_arg)
+{
+    memset(c, 0, sizeof(*c));
+    c->c_ev.ev_cb = ev_cb;
+    c->c_ev.ev_arg = ev_arg;
+    c->c_evq = evq;
+}
+
+/**
+ * Stop the callout from firing off, any pending events will be cleared.
+ *
+ * @param c The callout to stop
+ */
+void
+os_callout_stop(struct os_callout *c)
+{
+    os_sr_t sr;
+
+    OS_ENTER_CRITICAL(sr);
+
+    if (os_callout_queued(c)) {
+        TAILQ_REMOVE(&g_callout_list, c, c_next);
+        c->c_next.tqe_prev = NULL;
+    }
+
+    if (c->c_evq) {
+        os_eventq_remove(c->c_evq, &c->c_ev);
+    }
+
+    OS_EXIT_CRITICAL(sr);
+}
+
+/**
+ * Reset the callout to fire off in 'ticks' ticks.
+ *
+ * @param c The callout to reset
+ * @param ticks The number of ticks to wait before posting an event
+ *
+ * @return 0 on success, non-zero on failure
+ */
+int
+os_callout_reset(struct os_callout *c, int32_t ticks)
+{
+    struct os_callout *entry;
+    os_sr_t sr;
+    int rc;
+
+    if (ticks < 0) {
+        rc = OS_EINVAL;
+        goto err;
+    }
+
+    OS_ENTER_CRITICAL(sr);
+
+    os_callout_stop(c);
+
+    if (ticks == 0) {
+        ticks = 1;
+    }
+
+    c->c_ticks = os_time_get() + ticks;
+
+    entry = NULL;
+    TAILQ_FOREACH(entry, &g_callout_list, c_next) {
+        if (OS_TIME_TICK_LT(c->c_ticks, entry->c_ticks)) {
+            break;
+        }
+    }
+
+    if (entry) {
+        TAILQ_INSERT_BEFORE(entry, c, c_next);
+    } else {
+        TAILQ_INSERT_TAIL(&g_callout_list, c, c_next);
+    }
+
+    OS_EXIT_CRITICAL(sr);
+
+    return (0);
+err:
+    return (rc);
+}
+
+/**
+ * This function is called by the OS in the time tick.  It searches the list
+ * of callouts, and sees if any of them are ready to run.  If they are ready
+ * to run, it posts an event for each callout that's ready to run,
+ * to the event queue provided to os_callout_init().
+ */
+void
+os_callout_tick(void)
+{
+    os_sr_t sr;
+    struct os_callout *c;
+    uint32_t now;
+
+    now = os_time_get();
+
+    while (1) {
+        OS_ENTER_CRITICAL(sr);
+        c = TAILQ_FIRST(&g_callout_list);
+        if (c) {
+            if (OS_TIME_TICK_GEQ(now, c->c_ticks)) {
+                TAILQ_REMOVE(&g_callout_list, c, c_next);
+                c->c_next.tqe_prev = NULL;
+            } else {
+                c = NULL;
+            }
+        }
+        OS_EXIT_CRITICAL(sr);
+
+        if (c) {
+            if (c->c_evq) {
+                os_eventq_put(c->c_evq, &c->c_ev);
+            } else {
+                c->c_ev.ev_cb(&c->c_ev);
+            }
+        } else {
+            break;
+        }
+    }
+}
+
+/*
+ * Returns the number of ticks to the first pending callout. If there are no
+ * pending callouts then return OS_TIMEOUT_NEVER instead.
+ *
+ * @param now The time now
+ *
+ * @return Number of ticks to first pending callout
+ */
+os_time_t
+os_callout_wakeup_ticks(os_time_t now)
+{
+    os_time_t rt;
+    struct os_callout *c;
+
+    OS_ASSERT_CRITICAL();
+
+    c = TAILQ_FIRST(&g_callout_list);
+    if (c != NULL) {
+        if (OS_TIME_TICK_GEQ(c->c_ticks, now)) {
+            rt = c->c_ticks - now;
+        } else {
+            rt = 0;     /* callout time is in the past */
+        }
+    } else {
+        rt = OS_TIMEOUT_NEVER;
+    }
+
+    return (rt);
+}
+
+/*
+ * Returns the number of ticks which remains to callout..
+ *
+ * @param c callout
+ * @param now The time now
+ *
+ * @return Number of ticks to first pending callout
+ */
+os_time_t os_callout_remaining_ticks(struct os_callout *c, os_time_t now)
+{
+    os_time_t rt;
+
+    OS_ASSERT_CRITICAL();
+
+    if (OS_TIME_TICK_GEQ(c->c_ticks, now)) {
+        rt = c->c_ticks - now;
+    } else {
+        rt = 0;     /* callout time is in the past */
+    }
+
+    return rt;
+}
+
+/**
+ *   @} Callout Timers
+ * @} OS Kernel
+ */
diff --git a/porting/common/src/os/os_cputime.c b/porting/common/src/os/os_cputime.c
new file mode 100644
index 0000000..19b0b82
--- /dev/null
+++ b/porting/common/src/os/os_cputime.c
@@ -0,0 +1,215 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 <string.h>
+#include <stdint.h>
+#include <assert.h>
+#include "os/os.h"
+#include "os/os_cputime.h"
+
+/**
+ * @addtogroup OSKernel Operating System Kernel
+ * @{
+ *   @defgroup OSCPUTime High Resolution Timers
+ *   @{
+ */
+
+#if defined(OS_CPUTIME_FREQ_HIGH)
+struct os_cputime_data g_os_cputime;
+#endif
+
+/**
+ * os cputime init
+ *
+ * Initialize the cputime module. This must be called after os_init is called
+ * and before any other timer API are used. This should be called only once
+ * and should be called before the hardware timer is used.
+ *
+ * @param clock_freq The desired cputime frequency, in hertz (Hz).
+ *
+ * @return int 0 on success; -1 on error.
+ */
+int
+os_cputime_init(uint32_t clock_freq)
+{
+    int rc;
+
+    /* Set the ticks per microsecond. */
+#if defined(OS_CPUTIME_FREQ_HIGH)
+    g_os_cputime.ticks_per_usec = clock_freq / 1000000U;
+#endif
+    rc = hal_timer_config(MYNEWT_VAL(OS_CPUTIME_TIMER_NUM), clock_freq);
+    return rc;
+}
+
+/**
+ * os cputime delay ticks
+ *
+ * Wait until the number of ticks has elapsed. This is a blocking delay.
+ *
+ * @param ticks The number of ticks to wait.
+ */
+void
+os_cputime_delay_ticks(uint32_t ticks)
+{
+    uint32_t until;
+
+    until = os_cputime_get32() + ticks;
+    while ((int32_t)(os_cputime_get32() - until) < 0) {
+        /* Loop here till finished */
+    }
+}
+
+#if !defined(OS_CPUTIME_FREQ_PWR2)
+/**
+ * os cputime delay nsecs
+ *
+ * Wait until 'nsecs' nanoseconds has elapsed. This is a blocking delay.
+ *
+ * @param nsecs The number of nanoseconds to wait.
+ */
+void
+os_cputime_delay_nsecs(uint32_t nsecs)
+{
+    uint32_t ticks;
+
+    ticks = os_cputime_nsecs_to_ticks(nsecs);
+    os_cputime_delay_ticks(ticks);
+}
+#endif
+
+/**
+ * os cputime delay usecs
+ *
+ * Wait until 'usecs' microseconds has elapsed. This is a blocking delay.
+ *
+ * @param usecs The number of usecs to wait.
+ */
+void
+os_cputime_delay_usecs(uint32_t usecs)
+{
+    uint32_t ticks;
+
+    ticks = os_cputime_usecs_to_ticks(usecs);
+    os_cputime_delay_ticks(ticks);
+}
+
+/**
+ * os cputime timer init
+ *
+ * @param timer The timer to initialize. Cannot be NULL.
+ * @param fp    The timer callback function. Cannot be NULL.
+ * @param arg   Pointer to data object to pass to timer.
+ */
+void
+os_cputime_timer_init(struct hal_timer *timer, hal_timer_cb fp, void *arg)
+{
+    assert(timer != NULL);
+    assert(fp != NULL);
+
+    hal_timer_set_cb(MYNEWT_VAL(OS_CPUTIME_TIMER_NUM), timer, fp, arg);
+}
+
+/**
+ * os cputime timer start
+ *
+ * Start a cputimer that will expire at 'cputime'. If cputime has already
+ * passed, the timer callback will still be called (at interrupt context).
+ *
+ * NOTE: This must be called when the timer is stopped.
+ *
+ * @param timer     Pointer to timer to start. Cannot be NULL.
+ * @param cputime   The cputime at which the timer should expire.
+ *
+ * @return int 0 on success; EINVAL if timer already started or timer struct
+ *         invalid
+ *
+ */
+int
+os_cputime_timer_start(struct hal_timer *timer, uint32_t cputime)
+{
+    int rc;
+
+    rc = hal_timer_start_at(timer, cputime);
+    return rc;
+}
+
+/**
+ * os cputimer timer relative
+ *
+ * Sets a cpu timer that will expire 'usecs' microseconds from the current
+ * cputime.
+ *
+ * NOTE: This must be called when the timer is stopped.
+ *
+ * @param timer Pointer to timer. Cannot be NULL.
+ * @param usecs The number of usecs from now at which the timer will expire.
+ *
+ * @return int 0 on success; EINVAL if timer already started or timer struct
+ *         invalid
+ */
+int
+os_cputime_timer_relative(struct hal_timer *timer, uint32_t usecs)
+{
+    int rc;
+    uint32_t cputime;
+
+    assert(timer != NULL);
+
+    cputime = os_cputime_get32() + os_cputime_usecs_to_ticks(usecs);
+    rc = hal_timer_start_at(timer, cputime);
+
+    return rc;
+}
+
+/**
+ * os cputime timer stop
+ *
+ * Stops a cputimer from running. The timer is removed from the timer queue
+ * and interrupts are disabled if no timers are left on the queue. Can be
+ * called even if timer is not running.
+ *
+ * @param timer Pointer to cputimer to stop. Cannot be NULL.
+ */
+void
+os_cputime_timer_stop(struct hal_timer *timer)
+{
+    hal_timer_stop(timer);
+}
+
+/**
+ * os cputime get32
+ *
+ * Returns current value of cputime.
+ *
+ * @return uint32_t cputime
+ */
+uint32_t
+os_cputime_get32(void)
+{
+    uint32_t cpu_time;
+
+    cpu_time = hal_timer_read(MYNEWT_VAL(OS_CPUTIME_TIMER_NUM));
+    return cpu_time;
+}
+
+/**
+ *   @} OSCPUTime
+ * @} OSKernel
+ */
diff --git a/porting/common/src/os/os_cputime_1mhz.c b/porting/common/src/os/os_cputime_1mhz.c
new file mode 100644
index 0000000..4e76968
--- /dev/null
+++ b/porting/common/src/os/os_cputime_1mhz.c
@@ -0,0 +1,52 @@
+#include "os/os_cputime.h"
+
+/**
+ * This module implements cputime functionality for timers whose frequency is
+ * exactly 1 MHz.
+ */
+
+#if defined(OS_CPUTIME_FREQ_1MHZ)
+
+/**
+ * @addtogroup OSKernel Operating System Kernel
+ * @{
+ *   @defgroup OSCPUTime High Resolution Timers
+ *   @{
+ */
+
+/**
+ * os cputime nsecs to ticks
+ *
+ * Converts the given number of nanoseconds into cputime ticks.
+ *
+ * @param usecs The number of nanoseconds to convert to ticks
+ *
+ * @return uint32_t The number of ticks corresponding to 'nsecs'
+ */
+uint32_t
+os_cputime_nsecs_to_ticks(uint32_t nsecs)
+{
+    return (nsecs + 999) / 1000;
+}
+
+/**
+ * os cputime ticks to nsecs
+ *
+ * Convert the given number of ticks into nanoseconds.
+ *
+ * @param ticks The number of ticks to convert to nanoseconds.
+ *
+ * @return uint32_t The number of nanoseconds corresponding to 'ticks'
+ */
+uint32_t
+os_cputime_ticks_to_nsecs(uint32_t ticks)
+{
+    return ticks * 1000;
+}
+
+/**
+ *   @} OSCPUTime
+ * @} OSKernel
+ */
+
+#endif
diff --git a/porting/common/src/os/os_cputime_high.c b/porting/common/src/os/os_cputime_high.c
new file mode 100644
index 0000000..bb71662
--- /dev/null
+++ b/porting/common/src/os/os_cputime_high.c
@@ -0,0 +1,84 @@
+#include "os/os_cputime.h"
+
+/**
+ * This module implements cputime functionality for timers whose frequency is
+ * greater than 1 MHz.
+ */
+
+#if defined(OS_CPUTIME_FREQ_HIGH)
+
+/**
+ * @addtogroup OSKernel Operating System Kernel
+ * @{
+ *   @defgroup OSCPUTime High Resolution Timers
+ *   @{
+ */
+
+/**
+ * os cputime usecs to ticks
+ *
+ * Converts the given number of microseconds into cputime ticks.
+ *
+ * @param usecs The number of microseconds to convert to ticks
+ *
+ * @return uint32_t The number of ticks corresponding to 'usecs'
+ */
+uint32_t
+os_cputime_usecs_to_ticks(uint32_t usecs)
+{
+    return usecs * g_os_cputime.ticks_per_usec;
+}
+
+/**
+ * cputime ticks to usecs
+ *
+ * Convert the given number of ticks into microseconds.
+ *
+ * @param ticks The number of ticks to convert to microseconds.
+ *
+ * @return uint32_t The number of microseconds corresponding to 'ticks'
+ */
+uint32_t
+os_cputime_ticks_to_usecs(uint32_t ticks)
+{
+    return (ticks + g_os_cputime.ticks_per_usec - 1) /
+           g_os_cputime.ticks_per_usec;
+}
+
+/**
+ * os cputime nsecs to ticks
+ *
+ * Converts the given number of nanoseconds into cputime ticks.
+ *
+ * @param usecs The number of nanoseconds to convert to ticks
+ *
+ * @return uint32_t The number of ticks corresponding to 'nsecs'
+ */
+uint32_t
+os_cputime_nsecs_to_ticks(uint32_t nsecs)
+{
+    return (nsecs * g_os_cputime.ticks_per_usec + 999) / 1000;
+}
+
+/**
+ * os cputime ticks to nsecs
+ *
+ * Convert the given number of ticks into nanoseconds.
+ *
+ * @param ticks The number of ticks to convert to nanoseconds.
+ *
+ * @return uint32_t The number of nanoseconds corresponding to 'ticks'
+ */
+uint32_t
+os_cputime_ticks_to_nsecs(uint32_t ticks)
+{
+    return (ticks * 1000 + g_os_cputime.ticks_per_usec - 1) /
+           g_os_cputime.ticks_per_usec;
+}
+
+/**
+ *   @} OSCPUTime
+ * @} OSKernel
+ */
+
+#endif
diff --git a/porting/common/src/os/os_cputime_pwr2.c b/porting/common/src/os/os_cputime_pwr2.c
new file mode 100644
index 0000000..5a05b96
--- /dev/null
+++ b/porting/common/src/os/os_cputime_pwr2.c
@@ -0,0 +1,90 @@
+#include "os/os_cputime.h"
+
+/**
+ * This module implements cputime functionality for timers for which:
+ *     a. freq is a power of 2 Hz, and
+ *     b. 256 Hz <= freq < 1 MHz
+ */
+
+#if defined(OS_CPUTIME_FREQ_PWR2)
+
+/**
+ * @addtogroup OSKernel Operating System Kernel
+ * @{
+ *   @defgroup OSCPUTime High Resolution Timers
+ *   @{
+ */
+
+/**
+ * os cputime usecs to ticks
+ *
+ * Converts the given number of microseconds into cputime ticks.
+ *
+ * @param usecs The number of microseconds to convert to ticks
+ *
+ * @return uint32_t The number of ticks corresponding to 'usecs'
+ */
+uint32_t
+os_cputime_usecs_to_ticks(uint32_t usecs)
+{
+    uint64_t ticks;
+
+    /*
+     * Faster calculation but could be off 1 full tick since we do not
+     * add residual back. Adding back the residual is commented out below, but
+     * shown.
+     */
+    ticks = (1ULL << 32) * MYNEWT_VAL(OS_CPUTIME_FREQ) / 1000000 * usecs;
+
+    /* Residual for 32768 Hz. */
+    //ticks += ((uint64_t)usecs * (1526122139+1)) >> 32;
+
+    return ticks >> 32;
+}
+
+/**
+ * cputime ticks to usecs
+ *
+ * Convert the given number of ticks into microseconds.
+ *
+ * @param ticks The number of ticks to convert to microseconds.
+ *
+ * @return uint32_t The number of microseconds corresponding to 'ticks'
+ *
+ * NOTE: This calculation will overflow if the value for ticks is greater
+ * than 140737488. I am not going to check that here because that many ticks
+ * is about 4222 seconds, way more than what this routine should be used for.
+ */
+uint32_t
+os_cputime_ticks_to_usecs(uint32_t ticks)
+{
+    uint32_t usecs;
+    uint32_t shift;
+    uint32_t freq;
+
+    /* Given: `freq = 2^n`, calculate `n`. */
+    /* Note: this looks like a lot of work, but gcc can optimize it away since
+     * `freq` is known at compile time.
+     */
+    freq = MYNEWT_VAL(OS_CPUTIME_FREQ);
+    shift = 0;
+    while (freq != 0) {
+        freq >>= 1;
+        shift++;
+    }
+
+    if (shift <= 7) {
+        return 0;
+    }
+    shift -= 7;
+
+    usecs = ((ticks >> shift) * 15625) + (((ticks & 0x1ff) * 15625) >> shift);
+    return usecs;
+}
+
+/**
+ *   @} OSCPUTime
+ * @} OSKernel
+ */
+
+#endif
diff --git a/porting/common/src/os/os_dev.c b/porting/common/src/os/os_dev.c
new file mode 100644
index 0000000..07b1c54
--- /dev/null
+++ b/porting/common/src/os/os_dev.c
@@ -0,0 +1,346 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 "os/os.h"
+#include "os/queue.h"
+#include "os/os_dev.h"
+
+#include <string.h>
+
+/**
+ * @addtogroup OSKernel
+ * @{
+ *   @defgroup OSDevice Device Framework
+ *   @{
+ */
+
+static STAILQ_HEAD(, os_dev) g_os_dev_list;
+
+static int
+os_dev_init(struct os_dev *dev, char *name, uint8_t stage,
+        uint8_t priority, os_dev_init_func_t od_init, void *arg)
+{
+    dev->od_name = name;
+    dev->od_stage = stage;
+    dev->od_priority = priority;
+    /* assume these are set after the fact. */
+    dev->od_flags = 0;
+    dev->od_open_ref = 0;
+    dev->od_init = od_init;
+    dev->od_init_arg = arg;
+    memset(&dev->od_handlers, 0, sizeof(dev->od_handlers));
+
+    return (0);
+}
+
+/**
+ * Add the device to the device tree.  This is a private function.
+ *
+ * @param dev The device to add to the device tree.
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+static int
+os_dev_add(struct os_dev *dev)
+{
+    struct os_dev *cur_dev;
+
+    /* If no devices present, insert into head */
+    if (STAILQ_FIRST(&g_os_dev_list) == NULL) {
+        STAILQ_INSERT_HEAD(&g_os_dev_list, dev, od_next);
+        return (0);
+    }
+
+    /* Add devices to the list, sorted first by stage, then by
+     * priority.  Keep sorted in this order for initialization
+     * stage.
+     */
+    cur_dev = NULL;
+    STAILQ_FOREACH(cur_dev, &g_os_dev_list, od_next) {
+        if (cur_dev->od_stage > dev->od_stage) {
+            continue;
+        }
+
+        if (dev->od_priority >= cur_dev->od_priority) {
+            break;
+        }
+    }
+
+    if (cur_dev) {
+        STAILQ_INSERT_AFTER(&g_os_dev_list, cur_dev, dev, od_next);
+    } else {
+        STAILQ_INSERT_TAIL(&g_os_dev_list, dev, od_next);
+    }
+
+    return (0);
+}
+
+/**
+ * Call device initialize routine, and mark it ready. This is a private
+ * function.
+ *
+ * @param dev The device to initialize.
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+static int
+os_dev_initialize(struct os_dev *dev)
+{
+    int rc;
+
+    rc = dev->od_init(dev, dev->od_init_arg);
+    if (rc != 0) {
+        if (dev->od_flags & OS_DEV_F_INIT_CRITICAL) {
+            goto err;
+        }
+    } else {
+        dev->od_flags |= OS_DEV_F_STATUS_READY;
+    }
+    return 0;
+err:
+    return rc;
+}
+
+
+/**
+ * Create a new device in the kernel.
+ *
+ * @param dev The device to create.
+ * @param name The name of the device to create.
+ * @param stage The stage to initialize that device to.
+ * @param priority The priority of initializing that device
+ * @param od_init The initialization function to call for this
+ *                device.
+ * @param arg The argument to provide this device initialization
+ *            function.
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+int
+os_dev_create(struct os_dev *dev, char *name, uint8_t stage,
+        uint8_t priority, os_dev_init_func_t od_init, void *arg)
+{
+    int rc;
+
+    rc = os_dev_init(dev, name, stage, priority, od_init, arg);
+    if (rc != 0) {
+        goto err;
+    }
+
+    rc = os_dev_add(dev);
+    if (rc != 0) {
+        goto err;
+    }
+
+    if (g_os_started) {
+        rc = os_dev_initialize(dev);
+    }
+err:
+    return (rc);
+}
+
+/**
+ * Initialize all devices for a given state.
+ *
+ * @param stage The stage to initialize.
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+int
+os_dev_initialize_all(uint8_t stage)
+{
+    struct os_dev *dev;
+    int rc = 0;
+
+    STAILQ_FOREACH(dev, &g_os_dev_list, od_next) {
+        if (dev->od_stage == stage) {
+            rc = os_dev_initialize(dev);
+            if (rc) {
+                break;
+            }
+        }
+    }
+
+    return (rc);
+}
+
+/**
+ * Suspend all devices.
+ *
+ * @param dev The device to suspend
+ * @param suspend_t The number of ticks to suspend this device for
+ * @param force Whether or not to force suspending the device
+ *
+ * @return 0 on success, or a non-zero error code if one of the devices
+ *                       returned it.
+ */
+int
+os_dev_suspend_all(os_time_t suspend_t, uint8_t force)
+{
+    struct os_dev *dev;
+    int suspend_failure;
+    int rc;
+
+    suspend_failure = 0;
+    STAILQ_FOREACH(dev, &g_os_dev_list, od_next) {
+        rc = os_dev_suspend(dev, suspend_t, force);
+        if (rc != 0) {
+            suspend_failure = OS_ERROR;
+        }
+    }
+
+    return (suspend_failure);
+}
+
+/**
+ * Resume all the devices that were suspended.
+ *
+ * @return 0 on success, -1 if any of the devices have failed to resume.
+ */
+int
+os_dev_resume_all(void)
+{
+    struct os_dev *dev;
+    int rc;
+
+    STAILQ_FOREACH(dev, &g_os_dev_list, od_next) {
+        rc = os_dev_resume(dev);
+        if (rc != 0) {
+            goto err;
+        }
+    }
+
+    return (0);
+err:
+    return (rc);
+}
+
+/**
+ * Lookup a device by name.
+ *
+ * WARNING: This should be called before any locking on the device is done, or
+ * the device list itself is modified in any context.  There is no locking.
+ *
+ * @param name The name of the device to look up.
+ *
+ * @return A pointer to the device corresponding to name, or NULL if not found.
+ */
+struct os_dev *
+os_dev_lookup(char *name)
+{
+    struct os_dev *dev;
+
+    dev = NULL;
+    STAILQ_FOREACH(dev, &g_os_dev_list, od_next) {
+        if (!strcmp(dev->od_name, name)) {
+            break;
+        }
+    }
+    return (dev);
+}
+
+/**
+ * Open a device.
+ *
+ * @param dev The device to open
+ * @param timo The timeout to open the device, if not specified.
+ * @param arg The argument to the device open() call.
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+struct os_dev *
+os_dev_open(char *devname, uint32_t timo, void *arg)
+{
+    struct os_dev *dev;
+    os_sr_t sr;
+    int rc;
+
+    dev = os_dev_lookup(devname);
+    if (dev == NULL) {
+        return (NULL);
+    }
+
+    /* Device is not ready to be opened. */
+    if ((dev->od_flags & OS_DEV_F_STATUS_READY) == 0) {
+        return (NULL);
+    }
+
+    if (dev->od_handlers.od_open) {
+        rc = dev->od_handlers.od_open(dev, timo, arg);
+        if (rc != 0) {
+            goto err;
+        }
+    }
+
+    OS_ENTER_CRITICAL(sr);
+    ++dev->od_open_ref;
+    dev->od_flags |= OS_DEV_F_STATUS_OPEN;
+    OS_EXIT_CRITICAL(sr);
+
+    return (dev);
+err:
+    return (NULL);
+}
+
+/**
+ * Close a device.
+ *
+ * @param dev The device to close
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+int
+os_dev_close(struct os_dev *dev)
+{
+    int rc;
+    os_sr_t sr;
+
+    if (dev->od_handlers.od_close) {
+        rc = dev->od_handlers.od_close(dev);
+        if (rc != 0) {
+            goto err;
+        }
+    }
+
+    OS_ENTER_CRITICAL(sr);
+    if (--dev->od_open_ref == 0) {
+        dev->od_flags &= ~OS_DEV_F_STATUS_OPEN;
+    }
+    OS_EXIT_CRITICAL(sr);
+
+    return (0);
+err:
+    return (rc);
+}
+
+/**
+ * Clears the device list.  This function does not close any devices or free
+ * any resources; its purpose is to allow a full system reset between unit
+ * tests.
+ */
+void
+os_dev_reset(void)
+{
+    STAILQ_INIT(&g_os_dev_list);
+}
+
+/**
+ *   @} OSDevice
+ * @} OSKernel
+ */
diff --git a/porting/common/src/os/os_eventq.c b/porting/common/src/os/os_eventq.c
new file mode 100644
index 0000000..b09c81f
--- /dev/null
+++ b/porting/common/src/os/os_eventq.c
@@ -0,0 +1,354 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 <assert.h>
+#include <string.h>
+#include "os/os_trace_api.h"
+
+#include "os/os.h"
+
+/**
+ * @addtogroup OSKernel
+ * @{
+ *   @defgroup OSEvent Event Queues
+ *   @{
+ */
+
+static struct os_eventq os_eventq_main;
+
+/**
+ * Initialize the event queue
+ *
+ * @param evq The event queue to initialize
+ */
+void
+os_eventq_init(struct os_eventq *evq)
+{
+    memset(evq, 0, sizeof(*evq));
+    STAILQ_INIT(&evq->evq_list);
+}
+
+int
+os_eventq_inited(const struct os_eventq *evq)
+{
+    return evq->evq_list.stqh_last != NULL;
+}
+
+/**
+ * Put an event on the event queue.
+ *
+ * @param evq The event queue to put an event on
+ * @param ev The event to put on the queue
+ */
+void
+os_eventq_put(struct os_eventq *evq, struct os_event *ev)
+{
+    int resched;
+    os_sr_t sr;
+
+    OS_ENTER_CRITICAL(sr);
+
+    /* Do not queue if already queued */
+    if (OS_EVENT_QUEUED(ev)) {
+        OS_EXIT_CRITICAL(sr);
+        return;
+    }
+
+    os_trace_void(OS_TRACE_ID_EVQ_PUT);
+
+    /* Queue the event */
+    ev->ev_queued = 1;
+    STAILQ_INSERT_TAIL(&evq->evq_list, ev, ev_next);
+
+    resched = 0;
+    if (evq->evq_task) {
+        /* If task waiting on event, wake it up.
+         * Check if task is sleeping, because another event
+         * queue may have woken this task up beforehand.
+         */
+        if (evq->evq_task->t_state == OS_TASK_SLEEP) {
+            os_sched_wakeup(evq->evq_task);
+            resched = 1;
+        }
+        /* Either way, NULL out the task, because the task will
+         * be awake upon exit of this function.
+         */
+        evq->evq_task = NULL;
+    }
+
+    os_trace_end_call(OS_TRACE_ID_EVQ_PUT);
+    OS_EXIT_CRITICAL(sr);
+
+    if (resched) {
+        os_sched(NULL);
+    }
+}
+
+struct os_event *
+os_eventq_get_no_wait(struct os_eventq *evq)
+{
+    struct os_event *ev;
+
+    ev = STAILQ_FIRST(&evq->evq_list);
+    if (ev) {
+        STAILQ_REMOVE(&evq->evq_list, ev, os_event, ev_next);
+        ev->ev_queued = 0;
+    }
+
+    return ev;
+}
+
+/**
+ * Pull a single item from an event queue.  This function blocks until there
+ * is an item on the event queue to read.
+ *
+ * @param evq The event queue to pull an event from
+ *
+ * @return The event from the queue
+ */
+struct os_event *
+os_eventq_get(struct os_eventq *evq)
+{
+    struct os_event *ev;
+    os_sr_t sr;
+    struct os_task *t;
+
+    t = os_sched_get_current_task();
+    if (evq->evq_owner != t) {
+        if (evq->evq_owner == NULL) {
+            evq->evq_owner = t;
+        } else {
+            /*
+             * A task is trying to read from event queue which is handled
+             * by another.
+             */
+            assert(0);
+        }
+    }
+    OS_ENTER_CRITICAL(sr);
+    os_trace_void(OS_TRACE_ID_EVQ_GET);
+pull_one:
+    ev = STAILQ_FIRST(&evq->evq_list);
+    if (ev) {
+        STAILQ_REMOVE(&evq->evq_list, ev, os_event, ev_next);
+        ev->ev_queued = 0;
+        t->t_flags &= ~OS_TASK_FLAG_EVQ_WAIT;
+    } else {
+        evq->evq_task = t;
+        os_sched_sleep(evq->evq_task, OS_TIMEOUT_NEVER);
+        t->t_flags |= OS_TASK_FLAG_EVQ_WAIT;
+        OS_EXIT_CRITICAL(sr);
+
+        os_sched(NULL);
+
+        OS_ENTER_CRITICAL(sr);
+        evq->evq_task = NULL;
+        goto pull_one;
+    }
+    os_trace_end_call(OS_TRACE_ID_EVQ_GET);
+    OS_EXIT_CRITICAL(sr);
+
+    return (ev);
+}
+
+void
+os_eventq_run(struct os_eventq *evq)
+{
+    struct os_event *ev;
+
+    ev = os_eventq_get(evq);
+    assert(ev->ev_cb != NULL);
+
+    ev->ev_cb(ev);
+}
+
+static struct os_event *
+os_eventq_poll_0timo(struct os_eventq **evq, int nevqs)
+{
+    struct os_event *ev;
+    os_sr_t sr;
+    int i;
+
+    ev = NULL;
+
+    OS_ENTER_CRITICAL(sr);
+    for (i = 0; i < nevqs; i++) {
+        ev = STAILQ_FIRST(&evq[i]->evq_list);
+        if (ev) {
+            STAILQ_REMOVE(&evq[i]->evq_list, ev, os_event, ev_next);
+            ev->ev_queued = 0;
+            break;
+        }
+    }
+    OS_EXIT_CRITICAL(sr);
+
+    return ev;
+}
+
+/**
+ * Poll the list of event queues specified by the evq parameter
+ * (size nevqs), and return the "first" event available on any of
+ * the queues.  Event queues are searched in the order that they
+ * are passed in the array.
+ *
+ * @param evq Array of event queues
+ * @param nevqs Number of event queues in evq
+ * @param timo Timeout, forever if OS_WAIT_FOREVER is passed to poll.
+ *
+ * @return An event, or NULL if no events available
+ */
+struct os_event *
+os_eventq_poll(struct os_eventq **evq, int nevqs, os_time_t timo)
+{
+    struct os_event *ev;
+    struct os_task *cur_t;
+    int i, j;
+    os_sr_t sr;
+
+    /* If the timeout is 0, don't involve the scheduler at all.  Grab an event
+     * if one is available, else return immediately.
+     */
+    if (timo == 0) {
+        return os_eventq_poll_0timo(evq, nevqs);
+    }
+
+    ev = NULL;
+
+    OS_ENTER_CRITICAL(sr);
+    cur_t = os_sched_get_current_task();
+
+    for (i = 0; i < nevqs; i++) {
+        ev = STAILQ_FIRST(&evq[i]->evq_list);
+        if (ev) {
+            STAILQ_REMOVE(&evq[i]->evq_list, ev, os_event, ev_next);
+            ev->ev_queued = 0;
+            /* Reset the items that already have an evq task set. */
+            for (j = 0; j < i; j++) {
+                evq[j]->evq_task = NULL;
+            }
+
+            OS_EXIT_CRITICAL(sr);
+            goto has_event;
+        }
+        evq[i]->evq_task = cur_t;
+    }
+
+    cur_t->t_flags |= OS_TASK_FLAG_EVQ_WAIT;
+
+    os_sched_sleep(cur_t, timo);
+    OS_EXIT_CRITICAL(sr);
+
+    os_sched(NULL);
+
+    OS_ENTER_CRITICAL(sr);
+    cur_t->t_flags &= ~OS_TASK_FLAG_EVQ_WAIT;
+    for (i = 0; i < nevqs; i++) {
+        /* Go through the entire loop to clear the evq_task variable,
+         * given this task is no longer sleeping on the event queues.
+         * Return the first event found, so only grab the event if
+         * we haven't found one.
+         */
+        if (!ev) {
+            ev = STAILQ_FIRST(&evq[i]->evq_list);
+            if (ev) {
+                STAILQ_REMOVE(&evq[i]->evq_list, ev, os_event, ev_next);
+                ev->ev_queued = 0;
+            }
+        }
+        evq[i]->evq_task = NULL;
+    }
+    OS_EXIT_CRITICAL(sr);
+
+has_event:
+    return (ev);
+}
+
+/**
+ * Remove an event from the queue.
+ *
+ * @param evq The event queue to remove the event from
+ * @param ev  The event to remove from the queue
+ */
+void
+os_eventq_remove(struct os_eventq *evq, struct os_event *ev)
+{
+    os_sr_t sr;
+
+    OS_ENTER_CRITICAL(sr);
+    if (OS_EVENT_QUEUED(ev)) {
+        STAILQ_REMOVE(&evq->evq_list, ev, os_event, ev_next);
+    }
+    ev->ev_queued = 0;
+    OS_EXIT_CRITICAL(sr);
+}
+
+/**
+ * Retrieves the default event queue processed by OS main task.
+ *
+ * @return                      The default event queue.
+ */
+struct os_eventq *
+os_eventq_dflt_get(void)
+{
+    return &os_eventq_main;
+}
+
+/**
+ * [DEPRECATED - packages should manually enqueue start events to the default
+ * task instead of calling this function]
+ *
+ * Reassigns an event queue pointer to the specified value.  This function is
+ * used for configuring a package to use a particular event queue.  A package's
+ * event queue can generally be reassigned repeatedly.  If the package has a
+ * startup event, the event is moved from the current queue (if any) to the
+ * specified queue.
+ *
+ * @param cur_evq               Points to the eventq pointer to reassign.
+ *                                  *cur_evq should be NULL if the package's
+ *                                  eventq has not been assigned yet.
+ * @param new_evq               The eventq that the package should be
+ *                                  associated with.
+ * @param start_ev              The package's startup event, if any.  If this
+ *                                  is non-NULL, the event gets removed from
+ *                                  the current queue (if set), and enqueued to
+ *                                  the new eventq.
+ */
+void
+os_eventq_designate(struct os_eventq **cur_evq,
+                    struct os_eventq *new_evq,
+                    struct os_event *start_ev)
+{
+    struct os_eventq *prev_evq;
+
+    prev_evq = *cur_evq;
+    *cur_evq = new_evq;
+
+    if (start_ev != NULL) {
+        if (start_ev->ev_queued) {
+            assert(prev_evq != NULL);
+            os_eventq_remove(prev_evq, start_ev);
+        }
+        os_eventq_put(new_evq, start_ev);
+    }
+}
+
+/**
+ *   @} OSEvent
+ * @} OSKernel
+ */
diff --git a/porting/common/src/os/os_heap.c b/porting/common/src/os/os_heap.c
new file mode 100644
index 0000000..0d94325
--- /dev/null
+++ b/porting/common/src/os/os_heap.c
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 "syscfg/syscfg.h"
+
+#include <assert.h>
+#include "os/os_mutex.h"
+#include "os/os_heap.h"
+
+/**
+ * @addtogroup OSKernel
+ * @{
+ *   @defgroup OSGeneral
+ *   @{
+ */
+
+#if MYNEWT_VAL(OS_SCHEDULING)
+static struct os_mutex os_malloc_mutex;
+#endif
+
+static void
+os_malloc_lock(void)
+{
+#if MYNEWT_VAL(OS_SCHEDULING)
+    int rc;
+
+    if (g_os_started) {
+        rc = os_mutex_pend(&os_malloc_mutex, 0xffffffff);
+        assert(rc == 0);
+    }
+#endif
+}
+
+static void
+os_malloc_unlock(void)
+{
+#if MYNEWT_VAL(OS_SCHEDULING)
+    int rc;
+
+    if (g_os_started) {
+        rc = os_mutex_release(&os_malloc_mutex);
+        assert(rc == 0);
+    }
+#endif
+}
+
+/**
+ * Operating system level malloc().   This ensures that a safe malloc occurs
+ * within the context of the OS.  Depending on platform, the OS may rely on
+ * libc's malloc() implementation, which is not guaranteed to be thread-safe.
+ * This malloc() will always be thread-safe.
+ *
+ * @param size The number of bytes to allocate
+ *
+ * @return A pointer to the memory region allocated.
+ */
+void *
+os_malloc(size_t size)
+{
+    void *ptr;
+
+    os_malloc_lock();
+    ptr = malloc(size);
+    os_malloc_unlock();
+
+    return ptr;
+}
+
+/**
+ * Operating system level free().  See description of os_malloc() for reasoning.
+ *
+ * Free's memory allocated by malloc.
+ *
+ * @param mem The memory to free.
+ */
+void
+os_free(void *mem)
+{
+    os_malloc_lock();
+    free(mem);
+    os_malloc_unlock();
+}
+
+/**
+ * Operating system level realloc(). See description of os_malloc() for reasoning.
+ *
+ * Reallocates the memory at ptr, to be size contiguouos bytes.
+ *
+ * @param ptr A pointer to the memory to allocate
+ * @param size The number of contiguouos bytes to allocate at that location
+ *
+ * @return A pointer to memory of size, or NULL on failure to allocate
+ */
+void *
+os_realloc(void *ptr, size_t size)
+{
+    void *new_ptr;
+
+    os_malloc_lock();
+    new_ptr = realloc(ptr, size);
+    os_malloc_unlock();
+
+    return new_ptr;
+}
+
+/**
+ *   @} OSGeneral
+ * @} OS Kernel
+ */
diff --git a/porting/common/src/os/os_mbuf.c b/porting/common/src/os/os_mbuf.c
new file mode 100644
index 0000000..52c81ae
--- /dev/null
+++ b/porting/common/src/os/os_mbuf.c
@@ -0,0 +1,1368 @@
+/*
+ * Software in this file is based heavily on code written in the FreeBSD source
+ * code repostiory.  While the code is written from scratch, it contains
+ * many of the ideas and logic flow in the original source, this is a
+ * derivative work, and the following license applies as well:
+ *
+ * Copyright (c) 1982, 1986, 1988, 1991, 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.
+ *
+ */
+
+#include "os/os.h"
+
+#include <assert.h>
+#include <string.h>
+#include <limits.h>
+
+/**
+ * @addtogroup OSKernel
+ * @{
+ *   @defgroup OSMqueue Queue of Mbufs
+ *   @{
+ */
+
+STAILQ_HEAD(, os_mbuf_pool) g_msys_pool_list =
+    STAILQ_HEAD_INITIALIZER(g_msys_pool_list);
+
+/**
+ * Initializes an mqueue.  An mqueue is a queue of mbufs that ties to a
+ * particular task's event queue.  Mqueues form a helper API around a common
+ * paradigm: wait on an event queue until at least one packet is available,
+ * then process a queue of packets.
+ *
+ * When mbufs are available on the queue, an event OS_EVENT_T_MQUEUE_DATA
+ * will be posted to the task's mbuf queue.
+ *
+ * @param mq                    The mqueue to initialize
+ * @param ev_cb                 The callback to associate with the mqeueue
+ *                                  event.  Typically, this callback pulls each
+ *                                  packet off the mqueue and processes them.
+ * @param arg                   The argument to associate with the mqueue event.
+ *
+ * @return                      0 on success, non-zero on failure.
+ */
+int
+os_mqueue_init(struct os_mqueue *mq, os_event_fn *ev_cb, void *arg)
+{
+    struct os_event *ev;
+
+    STAILQ_INIT(&mq->mq_head);
+
+    ev = &mq->mq_ev;
+    memset(ev, 0, sizeof(*ev));
+    ev->ev_cb = ev_cb;
+    ev->ev_arg = arg;
+
+    return (0);
+}
+
+/**
+ * Remove and return a single mbuf from the mbuf queue.  Does not block.
+ *
+ * @param mq The mbuf queue to pull an element off of.
+ *
+ * @return The next mbuf in the queue, or NULL if queue has no mbufs.
+ */
+struct os_mbuf *
+os_mqueue_get(struct os_mqueue *mq)
+{
+    struct os_mbuf_pkthdr *mp;
+    struct os_mbuf *m;
+    os_sr_t sr;
+
+    OS_ENTER_CRITICAL(sr);
+    mp = STAILQ_FIRST(&mq->mq_head);
+    if (mp) {
+        STAILQ_REMOVE_HEAD(&mq->mq_head, omp_next);
+    }
+    OS_EXIT_CRITICAL(sr);
+
+    if (mp) {
+        m = OS_MBUF_PKTHDR_TO_MBUF(mp);
+    } else {
+        m = NULL;
+    }
+
+    return (m);
+}
+
+/**
+ * Adds a packet (i.e. packet header mbuf) to an mqueue. The event associated
+ * with the mqueue gets posted to the specified eventq.
+ *
+ * @param mq                    The mbuf queue to append the mbuf to.
+ * @param evq                   The event queue to post an event to.
+ * @param m                     The mbuf to append to the mbuf queue.
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+int
+os_mqueue_put(struct os_mqueue *mq, struct os_eventq *evq, struct os_mbuf *m)
+{
+    struct os_mbuf_pkthdr *mp;
+    os_sr_t sr;
+    int rc;
+
+    /* Can only place the head of a chained mbuf on the queue. */
+    if (!OS_MBUF_IS_PKTHDR(m)) {
+        rc = OS_EINVAL;
+        goto err;
+    }
+
+    mp = OS_MBUF_PKTHDR(m);
+
+    OS_ENTER_CRITICAL(sr);
+    STAILQ_INSERT_TAIL(&mq->mq_head, mp, omp_next);
+    OS_EXIT_CRITICAL(sr);
+
+    /* Only post an event to the queue if its specified */
+    if (evq) {
+        os_eventq_put(evq, &mq->mq_ev);
+    }
+
+    return (0);
+err:
+    return (rc);
+}
+
+/**
+ *   @} OSMqueue
+ * @} OSKernel
+ */
+
+
+/**
+ * @addtogroup OSKernel
+ * @{
+ *   @defgroup OSMsys System level mbuf
+ *   @{
+ */
+
+/**
+ * MSYS is a system level mbuf registry.  Allows the system to share
+ * packet buffers amongst the various networking stacks that can be running
+ * simultaeneously.
+ *
+ * Mbuf pools are created in the system initialization code, and then when
+ * a mbuf is allocated out of msys, it will try and find the best fit based
+ * upon estimated mbuf size.
+ *
+ * os_msys_register() registers a mbuf pool with MSYS, and allows MSYS to
+ * allocate mbufs out of it.
+ *
+ * @param new_pool The pool to register with MSYS
+ *
+ * @return 0 on success, non-zero on failure
+ */
+int
+os_msys_register(struct os_mbuf_pool *new_pool)
+{
+    struct os_mbuf_pool *pool;
+
+    pool = NULL;
+    STAILQ_FOREACH(pool, &g_msys_pool_list, omp_next) {
+        if (new_pool->omp_databuf_len > pool->omp_databuf_len) {
+            break;
+        }
+    }
+
+    if (pool) {
+        STAILQ_INSERT_AFTER(&g_msys_pool_list, pool, new_pool, omp_next);
+    } else {
+        STAILQ_INSERT_TAIL(&g_msys_pool_list, new_pool, omp_next);
+    }
+
+    return (0);
+}
+
+/**
+ * De-registers all mbuf pools from msys.
+ */
+void
+os_msys_reset(void)
+{
+    STAILQ_INIT(&g_msys_pool_list);
+}
+
+static struct os_mbuf_pool *
+_os_msys_find_pool(uint16_t dsize)
+{
+    struct os_mbuf_pool *pool;
+
+    pool = NULL;
+    STAILQ_FOREACH(pool, &g_msys_pool_list, omp_next) {
+        if (dsize <= pool->omp_databuf_len) {
+            break;
+        }
+    }
+
+    if (!pool) {
+        pool = STAILQ_LAST(&g_msys_pool_list, os_mbuf_pool, omp_next);
+    }
+
+    return (pool);
+}
+
+/**
+ * Allocate a mbuf from msys.  Based upon the data size requested,
+ * os_msys_get() will choose the mbuf pool that has the best fit.
+ *
+ * @param dsize The estimated size of the data being stored in the mbuf
+ * @param leadingspace The amount of leadingspace to allocate in the mbuf
+ *
+ * @return A freshly allocated mbuf on success, NULL on failure.
+ *
+ */
+struct os_mbuf *
+os_msys_get(uint16_t dsize, uint16_t leadingspace)
+{
+    struct os_mbuf *m;
+    struct os_mbuf_pool *pool;
+
+    pool = _os_msys_find_pool(dsize);
+    if (!pool) {
+        goto err;
+    }
+
+    m = os_mbuf_get(pool, leadingspace);
+    return (m);
+err:
+    return (NULL);
+}
+
+/**
+ * Allocate a packet header structure from the MSYS pool.  See
+ * os_msys_register() for a description of MSYS.
+ *
+ * @param dsize The estimated size of the data being stored in the mbuf
+ * @param user_hdr_len The length to allocate for the packet header structure
+ *
+ * @return A freshly allocated mbuf on success, NULL on failure.
+ */
+struct os_mbuf *
+os_msys_get_pkthdr(uint16_t dsize, uint16_t user_hdr_len)
+{
+    uint16_t total_pkthdr_len;
+    struct os_mbuf *m;
+    struct os_mbuf_pool *pool;
+
+    total_pkthdr_len =  user_hdr_len + sizeof(struct os_mbuf_pkthdr);
+    pool = _os_msys_find_pool(dsize + total_pkthdr_len);
+    if (!pool) {
+        goto err;
+    }
+
+    m = os_mbuf_get_pkthdr(pool, user_hdr_len);
+    return (m);
+err:
+    return (NULL);
+}
+
+int
+os_msys_count(void)
+{
+    struct os_mbuf_pool *omp;
+    int total;
+
+    total = 0;
+    STAILQ_FOREACH(omp, &g_msys_pool_list, omp_next) {
+        total += omp->omp_pool->mp_num_blocks;
+    }
+
+    return total;
+}
+
+int
+os_msys_num_free(void)
+{
+    struct os_mbuf_pool *omp;
+    int total;
+
+    total = 0;
+    STAILQ_FOREACH(omp, &g_msys_pool_list, omp_next) {
+        total += omp->omp_pool->mp_num_free;
+    }
+
+    return total;
+}
+
+/**
+ *   @} OSMsys
+ * @} OSKernel
+ */
+
+
+/**
+ * @addtogroup OSKernel
+ * @{
+ *   @defgroup OSMbuf Chained Memory Buffers
+ *   @{
+ */
+
+
+/**
+ * Initialize a pool of mbufs.
+ *
+ * @param omp     The mbuf pool to initialize
+ * @param mp      The memory pool that will hold this mbuf pool
+ * @param buf_len The length of the buffer itself.
+ * @param nbufs   The number of buffers in the pool
+ *
+ * @return 0 on success, error code on failure.
+ */
+int
+os_mbuf_pool_init(struct os_mbuf_pool *omp, struct os_mempool *mp,
+                  uint16_t buf_len, uint16_t nbufs)
+{
+    omp->omp_databuf_len = buf_len - sizeof(struct os_mbuf);
+    omp->omp_mbuf_count = nbufs;
+    omp->omp_pool = mp;
+
+    return (0);
+}
+
+/**
+ * Get an mbuf from the mbuf pool.  The mbuf is allocated, and initialized
+ * prior to being returned.
+ *
+ * @param omp The mbuf pool to return the packet from
+ * @param leadingspace The amount of leadingspace to put before the data
+ *     section by default.
+ *
+ * @return An initialized mbuf on success, and NULL on failure.
+ */
+struct os_mbuf *
+os_mbuf_get(struct os_mbuf_pool *omp, uint16_t leadingspace)
+{
+    struct os_mbuf *om;
+
+    if (leadingspace > omp->omp_databuf_len) {
+        goto err;
+    }
+
+    om = os_memblock_get(omp->omp_pool);
+    if (!om) {
+        goto err;
+    }
+
+    SLIST_NEXT(om, om_next) = NULL;
+    om->om_flags = 0;
+    om->om_pkthdr_len = 0;
+    om->om_len = 0;
+    om->om_data = (&om->om_databuf[0] + leadingspace);
+    om->om_omp = omp;
+
+    return (om);
+err:
+    return (NULL);
+}
+
+/**
+ * Allocate a new packet header mbuf out of the os_mbuf_pool.
+ *
+ * @param omp The mbuf pool to allocate out of
+ * @param user_pkthdr_len The packet header length to reserve for the caller.
+ *
+ * @return A freshly allocated mbuf on success, NULL on failure.
+ */
+struct os_mbuf *
+os_mbuf_get_pkthdr(struct os_mbuf_pool *omp, uint8_t user_pkthdr_len)
+{
+    uint16_t pkthdr_len;
+    struct os_mbuf_pkthdr *pkthdr;
+    struct os_mbuf *om;
+
+    /* User packet header must fit inside mbuf */
+    pkthdr_len = user_pkthdr_len + sizeof(struct os_mbuf_pkthdr);
+    if ((pkthdr_len > omp->omp_databuf_len) || (pkthdr_len > 255)) {
+        return NULL;
+    }
+
+    om = os_mbuf_get(omp, 0);
+    if (om) {
+        om->om_pkthdr_len = pkthdr_len;
+        om->om_data += pkthdr_len;
+
+        pkthdr = OS_MBUF_PKTHDR(om);
+        pkthdr->omp_len = 0;
+        pkthdr->omp_flags = 0;
+        STAILQ_NEXT(pkthdr, omp_next) = NULL;
+    }
+
+    return om;
+}
+
+/**
+ * Release a mbuf back to the pool
+ *
+ * @param omp The Mbuf pool to release back to
+ * @param om  The Mbuf to release back to the pool
+ *
+ * @return 0 on success, -1 on failure
+ */
+int
+os_mbuf_free(struct os_mbuf *om)
+{
+    int rc;
+
+    if (om->om_omp != NULL) {
+        rc = os_memblock_put(om->om_omp->omp_pool, om);
+        if (rc != 0) {
+            goto err;
+        }
+    }
+
+    return (0);
+err:
+    return (rc);
+}
+
+/**
+ * Free a chain of mbufs
+ *
+ * @param omp The mbuf pool to free the chain of mbufs into
+ * @param om  The starting mbuf of the chain to free back into the pool
+ *
+ * @return 0 on success, -1 on failure
+ */
+int
+os_mbuf_free_chain(struct os_mbuf *om)
+{
+    struct os_mbuf *next;
+    int rc;
+
+    while (om != NULL) {
+        next = SLIST_NEXT(om, om_next);
+
+        rc = os_mbuf_free(om);
+        if (rc != 0) {
+            goto err;
+        }
+
+        om = next;
+    }
+
+    return (0);
+err:
+    return (rc);
+}
+
+/**
+ * Copy a packet header from one mbuf to another.
+ *
+ * @param omp The mbuf pool associated with these buffers
+ * @param new_buf The new buffer to copy the packet header into
+ * @param old_buf The old buffer to copy the packet header from
+ */
+static inline void
+_os_mbuf_copypkthdr(struct os_mbuf *new_buf, struct os_mbuf *old_buf)
+{
+    assert(new_buf->om_len == 0);
+
+    memcpy(&new_buf->om_databuf[0], &old_buf->om_databuf[0],
+           old_buf->om_pkthdr_len);
+    new_buf->om_pkthdr_len = old_buf->om_pkthdr_len;
+    new_buf->om_data = new_buf->om_databuf + old_buf->om_pkthdr_len;
+}
+
+/**
+ * Append data onto a mbuf
+ *
+ * @param om   The mbuf to append the data onto
+ * @param data The data to append onto the mbuf
+ * @param len  The length of the data to append
+ *
+ * @return 0 on success, and an error code on failure
+ */
+int
+os_mbuf_append(struct os_mbuf *om, const void *data,  uint16_t len)
+{
+    struct os_mbuf_pool *omp;
+    struct os_mbuf *last;
+    struct os_mbuf *new;
+    int remainder;
+    int space;
+    int rc;
+
+    if (om == NULL) {
+        rc = OS_EINVAL;
+        goto err;
+    }
+
+    omp = om->om_omp;
+
+    /* Scroll to last mbuf in the chain */
+    last = om;
+    while (SLIST_NEXT(last, om_next) != NULL) {
+        last = SLIST_NEXT(last, om_next);
+    }
+
+    remainder = len;
+    space = OS_MBUF_TRAILINGSPACE(last);
+
+    /* If room in current mbuf, copy the first part of the data into the
+     * remaining space in that mbuf.
+     */
+    if (space > 0) {
+        if (space > remainder) {
+            space = remainder;
+        }
+
+        memcpy(OS_MBUF_DATA(last, uint8_t *) + last->om_len , data, space);
+
+        last->om_len += space;
+        data += space;
+        remainder -= space;
+    }
+
+    /* Take the remaining data, and keep allocating new mbufs and copying
+     * data into it, until data is exhausted.
+     */
+    while (remainder > 0) {
+        new = os_mbuf_get(omp, 0);
+        if (!new) {
+            break;
+        }
+
+        new->om_len = min(omp->omp_databuf_len, remainder);
+        memcpy(OS_MBUF_DATA(new, void *), data, new->om_len);
+        data += new->om_len;
+        remainder -= new->om_len;
+        SLIST_NEXT(last, om_next) = new;
+        last = new;
+    }
+
+    /* Adjust the packet header length in the buffer */
+    if (OS_MBUF_IS_PKTHDR(om)) {
+        OS_MBUF_PKTHDR(om)->omp_len += len - remainder;
+    }
+
+    if (remainder != 0) {
+        rc = OS_ENOMEM;
+        goto err;
+    }
+
+
+    return (0);
+err:
+    return (rc);
+}
+
+/**
+ * Reads data from one mbuf and appends it to another.  On error, the specified
+ * data range may be partially appended.  Neither mbuf is required to contain
+ * an mbuf packet header.
+ *
+ * @param dst                   The mbuf to append to.
+ * @param src                   The mbuf to copy data from.
+ * @param src_off               The absolute offset within the source mbuf
+ *                                  chain to read from.
+ * @param len                   The number of bytes to append.
+ *
+ * @return                      0 on success;
+ *                              OS_EINVAL if the specified range extends beyond
+ *                                  the end of the source mbuf chain.
+ */
+int
+os_mbuf_appendfrom(struct os_mbuf *dst, const struct os_mbuf *src,
+                   uint16_t src_off, uint16_t len)
+{
+    const struct os_mbuf *src_cur_om;
+    uint16_t src_cur_off;
+    uint16_t chunk_sz;
+    int rc;
+
+    src_cur_om = os_mbuf_off(src, src_off, &src_cur_off);
+    while (len > 0) {
+        if (src_cur_om == NULL) {
+            return OS_EINVAL;
+        }
+
+        chunk_sz = min(len, src_cur_om->om_len - src_cur_off);
+        rc = os_mbuf_append(dst, src_cur_om->om_data + src_cur_off, chunk_sz);
+        if (rc != 0) {
+            return rc;
+        }
+
+        len -= chunk_sz;
+        src_cur_om = SLIST_NEXT(src_cur_om, om_next);
+        src_cur_off = 0;
+    }
+
+    return 0;
+}
+
+/**
+ * Duplicate a chain of mbufs.  Return the start of the duplicated chain.
+ *
+ * @param omp The mbuf pool to duplicate out of
+ * @param om  The mbuf chain to duplicate
+ *
+ * @return A pointer to the new chain of mbufs
+ */
+struct os_mbuf *
+os_mbuf_dup(struct os_mbuf *om)
+{
+    struct os_mbuf_pool *omp;
+    struct os_mbuf *head;
+    struct os_mbuf *copy;
+
+    omp = om->om_omp;
+
+    head = NULL;
+    copy = NULL;
+
+    for (; om != NULL; om = SLIST_NEXT(om, om_next)) {
+        if (head) {
+            SLIST_NEXT(copy, om_next) = os_mbuf_get(omp,
+                    OS_MBUF_LEADINGSPACE(om));
+            if (!SLIST_NEXT(copy, om_next)) {
+                os_mbuf_free_chain(head);
+                goto err;
+            }
+
+            copy = SLIST_NEXT(copy, om_next);
+        } else {
+            head = os_mbuf_get(omp, OS_MBUF_LEADINGSPACE(om));
+            if (!head) {
+                goto err;
+            }
+
+            if (OS_MBUF_IS_PKTHDR(om)) {
+                _os_mbuf_copypkthdr(head, om);
+            }
+            copy = head;
+        }
+        copy->om_flags = om->om_flags;
+        copy->om_len = om->om_len;
+        memcpy(OS_MBUF_DATA(copy, uint8_t *), OS_MBUF_DATA(om, uint8_t *),
+                om->om_len);
+    }
+
+    return (head);
+err:
+    return (NULL);
+}
+
+/**
+ * Locates the specified absolute offset within an mbuf chain.  The offset
+ * can be one past than the total length of the chain, but no greater.
+ *
+ * @param om                    The start of the mbuf chain to seek within.
+ * @param off                   The absolute address to find.
+ * @param out_off               On success, this points to the relative offset
+ *                                  within the returned mbuf.
+ *
+ * @return                      The mbuf containing the specified offset on
+ *                                  success.
+ *                              NULL if the specified offset is out of bounds.
+ */
+struct os_mbuf *
+os_mbuf_off(const struct os_mbuf *om, int off, uint16_t *out_off)
+{
+    struct os_mbuf *next;
+    struct os_mbuf *cur;
+
+    /* Cast away const. */
+    cur = (struct os_mbuf *)om;
+
+    while (1) {
+        if (cur == NULL) {
+            return NULL;
+        }
+
+        next = SLIST_NEXT(cur, om_next);
+
+        if (cur->om_len > off ||
+            (cur->om_len == off && next == NULL)) {
+
+            *out_off = off;
+            return cur;
+        }
+
+        off -= cur->om_len;
+        cur = next;
+    }
+}
+
+/*
+ * Copy data from an mbuf chain starting "off" bytes from the beginning,
+ * continuing for "len" bytes, into the indicated buffer.
+ *
+ * @param m The mbuf chain to copy from
+ * @param off The offset into the mbuf chain to begin copying from
+ * @param len The length of the data to copy
+ * @param dst The destination buffer to copy into
+ *
+ * @return                      0 on success;
+ *                              -1 if the mbuf does not contain enough data.
+ */
+int
+os_mbuf_copydata(const struct os_mbuf *m, int off, int len, void *dst)
+{
+    unsigned int count;
+    uint8_t *udst;
+
+    if (!len) {
+        return 0;
+    }
+
+    udst = dst;
+
+    while (off > 0) {
+        if (!m) {
+            return (-1);
+        }
+
+        if (off < m->om_len)
+            break;
+        off -= m->om_len;
+        m = SLIST_NEXT(m, om_next);
+    }
+    while (len > 0 && m != NULL) {
+        count = min(m->om_len - off, len);
+        memcpy(udst, m->om_data + off, count);
+        len -= count;
+        udst += count;
+        off = 0;
+        m = SLIST_NEXT(m, om_next);
+    }
+
+    return (len > 0 ? -1 : 0);
+}
+
+/**
+ * Adjust the length of a mbuf, trimming either from the head or the tail
+ * of the mbuf.
+ *
+ * @param mp The mbuf chain to adjust
+ * @param req_len The length to trim from the mbuf.  If positive, trims
+ *                from the head of the mbuf, if negative, trims from the
+ *                tail of the mbuf.
+ */
+void
+os_mbuf_adj(struct os_mbuf *mp, int req_len)
+{
+    int len = req_len;
+    struct os_mbuf *m;
+    int count;
+
+    if ((m = mp) == NULL)
+        return;
+    if (len >= 0) {
+        /*
+         * Trim from head.
+         */
+        while (m != NULL && len > 0) {
+            if (m->om_len <= len) {
+                len -= m->om_len;
+                m->om_len = 0;
+                m = SLIST_NEXT(m, om_next);
+            } else {
+                m->om_len -= len;
+                m->om_data += len;
+                len = 0;
+            }
+        }
+        if (OS_MBUF_IS_PKTHDR(mp))
+            OS_MBUF_PKTHDR(mp)->omp_len -= (req_len - len);
+    } else {
+        /*
+         * Trim from tail.  Scan the mbuf chain,
+         * calculating its length and finding the last mbuf.
+         * If the adjustment only affects this mbuf, then just
+         * adjust and return.  Otherwise, rescan and truncate
+         * after the remaining size.
+         */
+        len = -len;
+        count = 0;
+        for (;;) {
+            count += m->om_len;
+            if (SLIST_NEXT(m, om_next) == (struct os_mbuf *)0)
+                break;
+            m = SLIST_NEXT(m, om_next);
+        }
+        if (m->om_len >= len) {
+            m->om_len -= len;
+            if (OS_MBUF_IS_PKTHDR(mp))
+                OS_MBUF_PKTHDR(mp)->omp_len -= len;
+            return;
+        }
+        count -= len;
+        if (count < 0)
+            count = 0;
+        /*
+         * Correct length for chain is "count".
+         * Find the mbuf with last data, adjust its length,
+         * and toss data from remaining mbufs on chain.
+         */
+        m = mp;
+        if (OS_MBUF_IS_PKTHDR(m))
+            OS_MBUF_PKTHDR(m)->omp_len = count;
+        for (; m; m = SLIST_NEXT(m, om_next)) {
+            if (m->om_len >= count) {
+                m->om_len = count;
+                if (SLIST_NEXT(m, om_next) != NULL) {
+                    os_mbuf_free_chain(SLIST_NEXT(m, om_next));
+                    SLIST_NEXT(m, om_next) = NULL;
+                }
+                break;
+            }
+            count -= m->om_len;
+        }
+    }
+}
+
+/**
+ * Performs a memory compare of the specified region of an mbuf chain against a
+ * flat buffer.
+ *
+ * @param om                    The start of the mbuf chain to compare.
+ * @param off                   The offset within the mbuf chain to start the
+ *                                  comparison.
+ * @param data                  The flat buffer to compare.
+ * @param len                   The length of the flat buffer.
+ *
+ * @return                      0 if both memory regions are identical;
+ *                              A memcmp return code if there is a mismatch;
+ *                              INT_MAX if the mbuf is too short.
+ */
+int
+os_mbuf_cmpf(const struct os_mbuf *om, int off, const void *data, int len)
+{
+    uint16_t chunk_sz;
+    uint16_t data_off;
+    uint16_t om_off;
+    int rc;
+
+    if (len <= 0) {
+        return 0;
+    }
+
+    data_off = 0;
+    om = os_mbuf_off(om, off, &om_off);
+    while (1) {
+        if (om == NULL) {
+            return INT_MAX;
+        }
+
+        chunk_sz = min(om->om_len - om_off, len - data_off);
+        if (chunk_sz > 0) {
+            rc = memcmp(om->om_data + om_off, data + data_off, chunk_sz);
+            if (rc != 0) {
+                return rc;
+            }
+        }
+
+        data_off += chunk_sz;
+        if (data_off == len) {
+            return 0;
+        }
+
+        om = SLIST_NEXT(om, om_next);
+        om_off = 0;
+
+        if (om == NULL) {
+            return INT_MAX;
+        }
+    }
+}
+
+/**
+ * Compares the contents of two mbuf chains.  The ranges of the two chains to
+ * be compared are specified via the two offset parameters and the len
+ * parameter.  Neither mbuf chain is required to contain a packet header.
+ *
+ * @param om1                   The first mbuf chain to compare.
+ * @param offset1               The absolute offset within om1 at which to
+ *                                  start the comparison.
+ * @param om2                   The second mbuf chain to compare.
+ * @param offset2               The absolute offset within om2 at which to
+ *                                  start the comparison.
+ * @param len                   The number of bytes to compare.
+ *
+ * @return                      0 if both mbuf segments are identical;
+ *                              A memcmp() return code if the segment contents
+ *                                  differ;
+ *                              INT_MAX if a specified range extends beyond the
+ *                                  end of its corresponding mbuf chain.
+ */
+int
+os_mbuf_cmpm(const struct os_mbuf *om1, uint16_t offset1,
+             const struct os_mbuf *om2, uint16_t offset2,
+             uint16_t len)
+{
+    const struct os_mbuf *cur1;
+    const struct os_mbuf *cur2;
+    uint16_t bytes_remaining;
+    uint16_t chunk_sz;
+    uint16_t om1_left;
+    uint16_t om2_left;
+    uint16_t om1_off;
+    uint16_t om2_off;
+    int rc;
+
+    om1_off = 0;
+    om2_off = 0;
+
+    cur1 = os_mbuf_off(om1, offset1, &om1_off);
+    cur2 = os_mbuf_off(om2, offset2, &om2_off);
+
+    bytes_remaining = len;
+    while (1) {
+        if (bytes_remaining == 0) {
+            return 0;
+        }
+
+        while (cur1 != NULL && om1_off >= cur1->om_len) {
+            cur1 = SLIST_NEXT(cur1, om_next);
+            om1_off = 0;
+        }
+        while (cur2 != NULL && om2_off >= cur2->om_len) {
+            cur2 = SLIST_NEXT(cur2, om_next);
+            om2_off = 0;
+        }
+
+        if (cur1 == NULL || cur2 == NULL) {
+            return INT_MAX;
+        }
+
+        om1_left = cur1->om_len - om1_off;
+        om2_left = cur2->om_len - om2_off;
+        chunk_sz = min(min(om1_left, om2_left), bytes_remaining);
+
+        rc = memcmp(cur1->om_data + om1_off, cur2->om_data + om2_off,
+                    chunk_sz);
+        if (rc != 0) {
+            return rc;
+        }
+
+        om1_off += chunk_sz;
+        om2_off += chunk_sz;
+        bytes_remaining -= chunk_sz;
+    }
+}
+
+/**
+ * Increases the length of an mbuf chain by adding data to the front.  If there
+ * is insufficient room in the leading mbuf, additional mbufs are allocated and
+ * prepended as necessary.  If this function fails to allocate an mbuf, the
+ * entire chain is freed.
+ *
+ * The specified mbuf chain does not need to contain a packet header.
+ *
+ * @param omp                   The mbuf pool to allocate from.
+ * @param om                    The head of the mbuf chain.
+ * @param len                   The number of bytes to prepend.
+ *
+ * @return                      The new head of the chain on success;
+ *                              NULL on failure.
+ */
+struct os_mbuf *
+os_mbuf_prepend(struct os_mbuf *om, int len)
+{
+    struct os_mbuf *p;
+    int leading;
+
+    while (1) {
+        /* Fill the available space at the front of the head of the chain, as
+         * needed.
+         */
+        leading = min(len, OS_MBUF_LEADINGSPACE(om));
+
+        om->om_data -= leading;
+        om->om_len += leading;
+        if (OS_MBUF_IS_PKTHDR(om)) {
+            OS_MBUF_PKTHDR(om)->omp_len += leading;
+        }
+
+        len -= leading;
+        if (len == 0) {
+            break;
+        }
+
+        /* The current head didn't have enough space; allocate a new head. */
+        if (OS_MBUF_IS_PKTHDR(om)) {
+            p = os_mbuf_get_pkthdr(om->om_omp,
+                om->om_pkthdr_len - sizeof (struct os_mbuf_pkthdr));
+        } else {
+            p = os_mbuf_get(om->om_omp, 0);
+        }
+        if (p == NULL) {
+            os_mbuf_free_chain(om);
+            om = NULL;
+            break;
+        }
+
+        if (OS_MBUF_IS_PKTHDR(om)) {
+            _os_mbuf_copypkthdr(p, om);
+            om->om_pkthdr_len = 0;
+        }
+
+        /* Move the new head's data pointer to the end so that data can be
+         * prepended.
+         */
+        p->om_data += OS_MBUF_TRAILINGSPACE(p);
+
+        SLIST_NEXT(p, om_next) = om;
+        om = p;
+    }
+
+    return om;
+}
+
+/**
+ * Prepends a chunk of empty data to the specified mbuf chain and ensures the
+ * chunk is contiguous.  If either operation fails, the specified mbuf chain is
+ * freed and NULL is returned.
+ *
+ * @param om                    The mbuf chain to prepend to.
+ * @param len                   The number of bytes to prepend and pullup.
+ *
+ * @return                      The modified mbuf on success;
+ *                              NULL on failure (and the mbuf chain is freed).
+ */
+struct os_mbuf *
+os_mbuf_prepend_pullup(struct os_mbuf *om, uint16_t len)
+{
+    om = os_mbuf_prepend(om, len);
+    if (om == NULL) {
+        return NULL;
+    }
+
+    om = os_mbuf_pullup(om, len);
+    if (om == NULL) {
+        return NULL;
+    }
+
+    return om;
+}
+
+/**
+ * Copies the contents of a flat buffer into an mbuf chain, starting at the
+ * specified destination offset.  If the mbuf is too small for the source data,
+ * it is extended as necessary.  If the destination mbuf contains a packet
+ * header, the header length is updated.
+ *
+ * @param omp                   The mbuf pool to allocate from.
+ * @param om                    The mbuf chain to copy into.
+ * @param off                   The offset within the chain to copy to.
+ * @param src                   The source buffer to copy from.
+ * @param len                   The number of bytes to copy.
+ *
+ * @return                      0 on success; nonzero on failure.
+ */
+int
+os_mbuf_copyinto(struct os_mbuf *om, int off, const void *src, int len)
+{
+    struct os_mbuf *next;
+    struct os_mbuf *cur;
+    const uint8_t *sptr;
+    uint16_t cur_off;
+    int copylen;
+    int rc;
+
+    /* Find the mbuf,offset pair for the start of the destination. */
+    cur = os_mbuf_off(om, off, &cur_off);
+    if (cur == NULL) {
+        return -1;
+    }
+
+    /* Overwrite existing data until we reach the end of the chain. */
+    sptr = src;
+    while (1) {
+        copylen = min(cur->om_len - cur_off, len);
+        if (copylen > 0) {
+            memcpy(cur->om_data + cur_off, sptr, copylen);
+            sptr += copylen;
+            len -= copylen;
+
+            copylen = 0;
+        }
+
+        if (len == 0) {
+            /* All the source data fit in the existing mbuf chain. */
+            return 0;
+        }
+
+        next = SLIST_NEXT(cur, om_next);
+        if (next == NULL) {
+            break;
+        }
+
+        cur = next;
+        cur_off = 0;
+    }
+
+    /* Append the remaining data to the end of the chain. */
+    rc = os_mbuf_append(cur, sptr, len);
+    if (rc != 0) {
+        return rc;
+    }
+
+    /* Fix up the packet header, if one is present. */
+    if (OS_MBUF_IS_PKTHDR(om)) {
+        OS_MBUF_PKTHDR(om)->omp_len =
+            max(OS_MBUF_PKTHDR(om)->omp_len, off + len);
+    }
+
+    return 0;
+}
+
+/**
+ * Attaches a second mbuf chain onto the end of the first.  If the first chain
+ * contains a packet header, the header's length is updated.  If the second
+ * chain has a packet header, its header is cleared.
+ *
+ * @param first                 The mbuf chain being attached to.
+ * @param second                The mbuf chain that gets attached.
+ */
+void
+os_mbuf_concat(struct os_mbuf *first, struct os_mbuf *second)
+{
+    struct os_mbuf *next;
+    struct os_mbuf *cur;
+
+    /* Point 'cur' to the last buffer in the first chain. */
+    cur = first;
+    while (1) {
+        next = SLIST_NEXT(cur, om_next);
+        if (next == NULL) {
+            break;
+        }
+
+        cur = next;
+    }
+
+    /* Attach the second chain to the end of the first. */
+    SLIST_NEXT(cur, om_next) = second;
+
+    /* If the first chain has a packet header, calculate the length of the
+     * second chain and add it to the header length.
+     */
+    if (OS_MBUF_IS_PKTHDR(first)) {
+        if (OS_MBUF_IS_PKTHDR(second)) {
+            OS_MBUF_PKTHDR(first)->omp_len += OS_MBUF_PKTHDR(second)->omp_len;
+        } else {
+            for (cur = second; cur != NULL; cur = SLIST_NEXT(cur, om_next)) {
+                OS_MBUF_PKTHDR(first)->omp_len += cur->om_len;
+            }
+        }
+    }
+
+    second->om_pkthdr_len = 0;
+}
+
+/**
+ * Increases the length of an mbuf chain by the specified amount.  If there is
+ * not sufficient room in the last buffer, a new buffer is allocated and
+ * appended to the chain.  It is an error to request more data than can fit in
+ * a single buffer.
+ *
+ * @param omp
+ * @param om                    The head of the chain to extend.
+ * @param len                   The number of bytes to extend by.
+ *
+ * @return                      A pointer to the new data on success;
+ *                              NULL on failure.
+ */
+void *
+os_mbuf_extend(struct os_mbuf *om, uint16_t len)
+{
+    struct os_mbuf *newm;
+    struct os_mbuf *last;
+    void *data;
+
+    if (len > om->om_omp->omp_databuf_len) {
+        return NULL;
+    }
+
+    /* Scroll to last mbuf in the chain */
+    last = om;
+    while (SLIST_NEXT(last, om_next) != NULL) {
+        last = SLIST_NEXT(last, om_next);
+    }
+
+    if (OS_MBUF_TRAILINGSPACE(last) < len) {
+        newm = os_mbuf_get(om->om_omp, 0);
+        if (newm == NULL) {
+            return NULL;
+        }
+
+        SLIST_NEXT(last, om_next) = newm;
+        last = newm;
+    }
+
+    data = last->om_data + last->om_len;
+    last->om_len += len;
+
+    if (OS_MBUF_IS_PKTHDR(om)) {
+        OS_MBUF_PKTHDR(om)->omp_len += len;
+    }
+
+    return data;
+}
+
+/**
+ * Rearrange a mbuf chain so that len bytes are contiguous,
+ * and in the data area of an mbuf (so that OS_MBUF_DATA() will
+ * work on a structure of size len.)  Returns the resulting
+ * mbuf chain on success, free's it and returns NULL on failure.
+ *
+ * If there is room, it will add up to "max_protohdr - len"
+ * extra bytes to the contiguous region, in an attempt to avoid being
+ * called next time.
+ *
+ * @param omp The mbuf pool to take the mbufs out of
+ * @param om The mbuf chain to make contiguous
+ * @param len The number of bytes in the chain to make contiguous
+ *
+ * @return The contiguous mbuf chain on success, NULL on failure.
+ */
+struct os_mbuf *
+os_mbuf_pullup(struct os_mbuf *om, uint16_t len)
+{
+    struct os_mbuf_pool *omp;
+    struct os_mbuf *next;
+    struct os_mbuf *om2;
+    int count;
+    int space;
+
+    omp = om->om_omp;
+
+    /*
+     * If first mbuf has no cluster, and has room for len bytes
+     * without shifting current data, pullup into it,
+     * otherwise allocate a new mbuf to prepend to the chain.
+     */
+    if (om->om_len >= len) {
+        return (om);
+    }
+    if (om->om_len + OS_MBUF_TRAILINGSPACE(om) >= len &&
+        SLIST_NEXT(om, om_next)) {
+        om2 = om;
+        om = SLIST_NEXT(om, om_next);
+        len -= om2->om_len;
+    } else {
+        if (len > omp->omp_databuf_len - om->om_pkthdr_len) {
+            goto bad;
+        }
+
+        om2 = os_mbuf_get(omp, 0);
+        if (om2 == NULL) {
+            goto bad;
+        }
+
+        if (OS_MBUF_IS_PKTHDR(om)) {
+            _os_mbuf_copypkthdr(om2, om);
+        }
+    }
+    space = OS_MBUF_TRAILINGSPACE(om2);
+    do {
+        count = min(min(len, space), om->om_len);
+        memcpy(om2->om_data + om2->om_len, om->om_data, count);
+        len -= count;
+        om2->om_len += count;
+        om->om_len -= count;
+        space -= count;
+        if (om->om_len) {
+            om->om_data += count;
+        } else {
+            next = SLIST_NEXT(om, om_next);
+            os_mbuf_free(om);
+            om = next;
+        }
+    } while (len > 0 && om);
+    if (len > 0) {
+        os_mbuf_free(om2);
+        goto bad;
+    }
+    SLIST_NEXT(om2, om_next) = om;
+    return (om2);
+bad:
+    os_mbuf_free_chain(om);
+    return (NULL);
+}
+
+/**
+ * Removes and frees empty mbufs from the front of a chain.  If the chain
+ * contains a packet header, it is preserved.
+ *
+ * @param om                    The mbuf chain to trim.
+ *
+ * @return                      The head of the trimmed mbuf chain.
+ */
+struct os_mbuf *
+os_mbuf_trim_front(struct os_mbuf *om)
+{
+    struct os_mbuf *next;
+    struct os_mbuf *cur;
+
+    /* Abort early if there is nothing to trim. */
+    if (om->om_len != 0) {
+        return om;
+    }
+
+    /* Starting with the second mbuf in the chain, continue removing and
+     * freeing mbufs until an non-empty one is encountered.
+     */
+    cur = SLIST_NEXT(om, om_next);
+    while (cur != NULL && cur->om_len == 0) {
+        next = SLIST_NEXT(cur, om_next);
+
+        SLIST_NEXT(om, om_next) = next;
+        os_mbuf_free(cur);
+
+        cur = next;
+    }
+
+    if (cur == NULL) {
+        /* All buffers after the first have been freed. */
+        return om;
+    }
+
+    /* Try to remove the first mbuf in the chain.  If this buffer contains a
+     * packet header, make sure the second buffer can accommodate it.
+     */
+    if (OS_MBUF_LEADINGSPACE(cur) >= om->om_pkthdr_len) {
+        /* Second buffer has room; copy packet header. */
+        cur->om_pkthdr_len = om->om_pkthdr_len;
+        memcpy(OS_MBUF_PKTHDR(cur), OS_MBUF_PKTHDR(om), om->om_pkthdr_len);
+
+        /* Free first buffer. */
+        os_mbuf_free(om);
+        om = cur;
+    }
+
+    return om;
+}
+
+/**
+ *   @} OSMbuf
+ * @} OSKernel
+ */
diff --git a/porting/common/src/os/os_mempool.c b/porting/common/src/os/os_mempool.c
new file mode 100644
index 0000000..65e4f61
--- /dev/null
+++ b/porting/common/src/os/os_mempool.c
@@ -0,0 +1,321 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 "os/os.h"
+
+#include <string.h>
+#include <assert.h>
+#include <stdbool.h>
+
+/**
+ * @addtogroup OSKernel
+ * @{
+ *   @defgroup OSMempool Memory Pools
+ *   @{
+ */
+
+#define OS_MEM_TRUE_BLOCK_SIZE(bsize)   OS_ALIGN(bsize, OS_ALIGNMENT)
+#define OS_MEMPOOL_TRUE_BLOCK_SIZE(mp) OS_MEM_TRUE_BLOCK_SIZE(mp->mp_block_size)
+
+STAILQ_HEAD(, os_mempool) g_os_mempool_list =
+    STAILQ_HEAD_INITIALIZER(g_os_mempool_list);
+
+#if MYNEWT_VAL(OS_MEMPOOL_POISON)
+static uint32_t os_mem_poison = 0xde7ec7ed;
+
+static void
+os_mempool_poison(void *start, int sz)
+{
+    int i;
+    char *p = start;
+
+    for (i = sizeof(struct os_memblock); i < sz;
+         i = i + sizeof(os_mem_poison)) {
+        memcpy(p + i, &os_mem_poison, min(sizeof(os_mem_poison), sz - i));
+    }
+}
+
+static void
+os_mempool_poison_check(void *start, int sz)
+{
+    int i;
+    char *p = start;
+
+    for (i = sizeof(struct os_memblock); i < sz;
+         i = i + sizeof(os_mem_poison)) {
+        assert(!memcmp(p + i, &os_mem_poison,
+               min(sizeof(os_mem_poison), sz - i)));
+    }
+}
+#else
+#define os_mempool_poison(start, sz)
+#define os_mempool_poison_check(start, sz)
+#endif
+
+/**
+ * os mempool init
+ *
+ * Initialize a memory pool.
+ *
+ * @param mp            Pointer to a pointer to a mempool
+ * @param blocks        The number of blocks in the pool
+ * @param blocks_size   The size of the block, in bytes.
+ * @param membuf        Pointer to memory to contain blocks.
+ * @param name          Name of the pool.
+ *
+ * @return os_error_t
+ */
+os_error_t
+os_mempool_init(struct os_mempool *mp, int blocks, int block_size,
+                void *membuf, char *name)
+{
+    int true_block_size;
+    uint8_t *block_addr;
+    struct os_memblock *block_ptr;
+
+    /* Check for valid parameters */
+    if (!mp || (blocks < 0) || (block_size <= sizeof(struct os_memblock))) {
+        return OS_INVALID_PARM;
+    }
+
+    if ((!membuf) && (blocks != 0)) {
+        return OS_INVALID_PARM;
+    }
+
+    if (membuf != NULL) {
+        /* Blocks need to be sized properly and memory buffer should be
+         * aligned
+         */
+        if (((uint32_t)membuf & (OS_ALIGNMENT - 1)) != 0) {
+            return OS_MEM_NOT_ALIGNED;
+        }
+    }
+    true_block_size = OS_MEM_TRUE_BLOCK_SIZE(block_size);
+
+    /* Initialize the memory pool structure */
+    mp->mp_block_size = block_size;
+    mp->mp_num_free = blocks;
+    mp->mp_min_free = blocks;
+    mp->mp_num_blocks = blocks;
+    mp->mp_membuf_addr = (uint32_t)membuf;
+    mp->name = name;
+    os_mempool_poison(membuf, true_block_size);
+    SLIST_FIRST(mp) = membuf;
+
+    /* Chain the memory blocks to the free list */
+    block_addr = (uint8_t *)membuf;
+    block_ptr = (struct os_memblock *)block_addr;
+    while (blocks > 1) {
+        block_addr += true_block_size;
+        os_mempool_poison(block_addr, true_block_size);
+        SLIST_NEXT(block_ptr, mb_next) = (struct os_memblock *)block_addr;
+        block_ptr = (struct os_memblock *)block_addr;
+        --blocks;
+    }
+
+    /* Last one in the list should be NULL */
+    SLIST_NEXT(block_ptr, mb_next) = NULL;
+
+    STAILQ_INSERT_TAIL(&g_os_mempool_list, mp, mp_list);
+
+    return OS_OK;
+}
+
+/**
+ * Performs an integrity check of the specified mempool.  This function
+ * attempts to detect memory corruption in the specified memory pool.
+ *
+ * @param mp                    The mempool to check.
+ *
+ * @return                      true if the memory pool passes the integrity
+ *                                  check;
+ *                              false if the memory pool is corrupt.
+ */
+bool
+os_mempool_is_sane(const struct os_mempool *mp)
+{
+    struct os_memblock *block;
+
+    /* Verify that each block in the free list belongs to the mempool. */
+    SLIST_FOREACH(block, mp, mb_next) {
+        if (!os_memblock_from(mp, block)) {
+            return false;
+        }
+        os_mempool_poison_check(block, OS_MEMPOOL_TRUE_BLOCK_SIZE(mp));
+    }
+
+    return true;
+}
+
+/**
+ * Checks if a memory block was allocated from the specified mempool.
+ *
+ * @param mp                    The mempool to check as parent.
+ * @param block_addr            The memory block to check as child.
+ *
+ * @return                      0 if the block does not belong to the mempool;
+ *                              1 if the block does belong to the mempool.
+ */
+int
+os_memblock_from(const struct os_mempool *mp, const void *block_addr)
+{
+    uint32_t true_block_size;
+    uint32_t baddr32;
+    uint32_t end;
+
+    _Static_assert(sizeof block_addr == sizeof baddr32,
+                   "Pointer to void must be 32-bits.");
+
+    baddr32 = (uint32_t)block_addr;
+    true_block_size = OS_MEMPOOL_TRUE_BLOCK_SIZE(mp);
+    end = mp->mp_membuf_addr + (mp->mp_num_blocks * true_block_size);
+
+    /* Check that the block is in the memory buffer range. */
+    if ((baddr32 < mp->mp_membuf_addr) || (baddr32 >= end)) {
+        return 0;
+    }
+
+    /* All freed blocks should be on true block size boundaries! */
+    if (((baddr32 - mp->mp_membuf_addr) % true_block_size) != 0) {
+        return 0;
+    }
+
+    return 1;
+}
+
+/**
+ * os memblock get
+ *
+ * Get a memory block from a memory pool
+ *
+ * @param mp Pointer to the memory pool
+ *
+ * @return void* Pointer to block if available; NULL otherwise
+ */
+void *
+os_memblock_get(struct os_mempool *mp)
+{
+    os_sr_t sr;
+    struct os_memblock *block;
+
+    /* Check to make sure they passed in a memory pool (or something) */
+    block = NULL;
+    if (mp) {
+        OS_ENTER_CRITICAL(sr);
+        /* Check for any free */
+        if (mp->mp_num_free) {
+            /* Get a free block */
+            block = SLIST_FIRST(mp);
+
+            os_mempool_poison_check(block, OS_MEMPOOL_TRUE_BLOCK_SIZE(mp));
+
+            /* Set new free list head */
+            SLIST_FIRST(mp) = SLIST_NEXT(block, mb_next);
+
+            /* Decrement number free by 1 */
+            mp->mp_num_free--;
+            if (mp->mp_min_free > mp->mp_num_free) {
+                mp->mp_min_free = mp->mp_num_free;
+            }
+        }
+        OS_EXIT_CRITICAL(sr);
+    }
+
+    return (void *)block;
+}
+
+/**
+ * os memblock put
+ *
+ * Puts the memory block back into the pool
+ *
+ * @param mp Pointer to memory pool
+ * @param block_addr Pointer to memory block
+ *
+ * @return os_error_t
+ */
+os_error_t
+os_memblock_put(struct os_mempool *mp, void *block_addr)
+{
+    os_sr_t sr;
+    struct os_memblock *block;
+
+    /* Make sure parameters are valid */
+    if ((mp == NULL) || (block_addr == NULL)) {
+        return OS_INVALID_PARM;
+    }
+
+#if MYNEWT_VAL(OS_MEMPOOL_CHECK)
+    /* Check that the block we are freeing is a valid block! */
+    assert(os_memblock_from(mp, block_addr));
+
+    /*
+     * Check for duplicate free.
+     */
+    SLIST_FOREACH(block, mp, mb_next) {
+        assert(block != (struct os_memblock *)block_addr);
+    }
+#endif
+    os_mempool_poison(block_addr, OS_MEMPOOL_TRUE_BLOCK_SIZE(mp));
+    block = (struct os_memblock *)block_addr;
+    OS_ENTER_CRITICAL(sr);
+
+    /* Chain current free list pointer to this block; make this block head */
+    SLIST_NEXT(block, mb_next) = SLIST_FIRST(mp);
+    SLIST_FIRST(mp) = block;
+
+    /* XXX: Should we check that the number free <= number blocks? */
+    /* Increment number free */
+    mp->mp_num_free++;
+
+    OS_EXIT_CRITICAL(sr);
+
+    return OS_OK;
+}
+
+
+struct os_mempool *
+os_mempool_info_get_next(struct os_mempool *mp, struct os_mempool_info *omi)
+{
+    struct os_mempool *cur;
+
+    if (mp == NULL) {
+        cur = STAILQ_FIRST(&g_os_mempool_list);
+    } else {
+        cur = STAILQ_NEXT(mp, mp_list);
+    }
+
+    if (cur == NULL) {
+        return (NULL);
+    }
+
+    omi->omi_block_size = cur->mp_block_size;
+    omi->omi_num_blocks = cur->mp_num_blocks;
+    omi->omi_num_free = cur->mp_num_free;
+    omi->omi_min_free = cur->mp_min_free;
+    strncpy(omi->omi_name, cur->name, sizeof(omi->omi_name));
+
+    return (cur);
+}
+
+
+/**
+ *   @} OSMempool
+ * @} OSKernel
+ */
diff --git a/porting/common/src/os/os_msys_init.c b/porting/common/src/os/os_msys_init.c
new file mode 100644
index 0000000..a907b41
--- /dev/null
+++ b/porting/common/src/os/os_msys_init.c
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 <assert.h>
+
+#include "../os/os_priv.h"
+#include "sysinit/sysinit.h"
+#include "syscfg/syscfg.h"
+#include "os/os_mempool.h"
+#include "mem/mem.h"
+
+#if MYNEWT_VAL(MSYS_1_BLOCK_COUNT) > 0
+#define SYSINIT_MSYS_1_MEMBLOCK_SIZE                \
+    OS_ALIGN(MYNEWT_VAL(MSYS_1_BLOCK_SIZE), 4)
+#define SYSINIT_MSYS_1_MEMPOOL_SIZE                 \
+    OS_MEMPOOL_SIZE(MYNEWT_VAL(MSYS_1_BLOCK_COUNT),  \
+                    SYSINIT_MSYS_1_MEMBLOCK_SIZE)
+static os_membuf_t os_msys_init_1_data[SYSINIT_MSYS_1_MEMPOOL_SIZE];
+static struct os_mbuf_pool os_msys_init_1_mbuf_pool;
+static struct os_mempool os_msys_init_1_mempool;
+#endif
+
+#if MYNEWT_VAL(MSYS_2_BLOCK_COUNT) > 0
+#define SYSINIT_MSYS_2_MEMBLOCK_SIZE                \
+    OS_ALIGN(MYNEWT_VAL(MSYS_2_BLOCK_SIZE), 4)
+#define SYSINIT_MSYS_2_MEMPOOL_SIZE                 \
+    OS_MEMPOOL_SIZE(MYNEWT_VAL(MSYS_2_BLOCK_COUNT),  \
+                    SYSINIT_MSYS_2_MEMBLOCK_SIZE)
+static os_membuf_t os_msys_init_2_data[SYSINIT_MSYS_2_MEMPOOL_SIZE];
+static struct os_mbuf_pool os_msys_init_2_mbuf_pool;
+static struct os_mempool os_msys_init_2_mempool;
+#endif
+
+static void
+os_msys_init_once(void *data, struct os_mempool *mempool,
+                  struct os_mbuf_pool *mbuf_pool,
+                  int block_count, int block_size, char *name)
+{
+    int rc;
+
+    rc = mem_init_mbuf_pool(data, mempool, mbuf_pool, block_count, block_size,
+                            name);
+    SYSINIT_PANIC_ASSERT(rc == 0);
+
+    rc = os_msys_register(mbuf_pool);
+    SYSINIT_PANIC_ASSERT(rc == 0);
+}
+
+void
+os_msys_init(void)
+{
+    os_msys_reset();
+
+    (void)os_msys_init_once;
+#if MYNEWT_VAL(MSYS_1_BLOCK_COUNT) > 0
+    os_msys_init_once(os_msys_init_1_data,
+                      &os_msys_init_1_mempool,
+                      &os_msys_init_1_mbuf_pool,
+                      MYNEWT_VAL(MSYS_1_BLOCK_COUNT),
+                      SYSINIT_MSYS_1_MEMBLOCK_SIZE,
+                      "msys_1");
+#endif
+
+#if MYNEWT_VAL(MSYS_2_BLOCK_COUNT) > 0
+    os_msys_init_once(os_msys_init_2_data,
+                      &os_msys_init_2_mempool,
+                      &os_msys_init_2_mbuf_pool,
+                      MYNEWT_VAL(MSYS_2_BLOCK_COUNT),
+                      SYSINIT_MSYS_2_MEMBLOCK_SIZE,
+                      "msys_2");
+#endif
+}
diff --git a/porting/common/src/os/os_mutex.c b/porting/common/src/os/os_mutex.c
new file mode 100644
index 0000000..117045f
--- /dev/null
+++ b/porting/common/src/os/os_mutex.c
@@ -0,0 +1,262 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 "os/os.h"
+#include "os/os_trace_api.h"
+#include <assert.h>
+
+/**
+ * @addtogroup OSKernel
+ * @{
+ *   @defgroup OSMutex Mutexes
+ *   @{
+ */
+
+
+/**
+ * os mutex create
+ *
+ * Create a mutex and initialize it.
+ *
+ * @param mu Pointer to mutex
+ *
+ * @return os_error_t
+ *      OS_INVALID_PARM     Mutex passed in was NULL.
+ *      OS_OK               no error.
+ */
+os_error_t
+os_mutex_init(struct os_mutex *mu)
+{
+    if (!mu) {
+        return OS_INVALID_PARM;
+    }
+
+    os_trace_void(OS_TRACE_ID_MUTEX_INIT);
+    /* Initialize to 0 */
+    mu->mu_prio = 0;
+    mu->mu_level = 0;
+    mu->mu_owner = NULL;
+    SLIST_FIRST(&mu->mu_head) = NULL;
+    os_trace_end_call(OS_TRACE_ID_MUTEX_INIT);
+
+    return OS_OK;
+}
+
+/**
+ * os mutex release
+ *
+ * Release a mutex.
+ *
+ * @param mu Pointer to the mutex to be released
+ *
+ * @return os_error_t
+ *      OS_INVALID_PARM Mutex passed in was NULL.
+ *      OS_BAD_MUTEX    Mutex was not granted to current task (not owner).
+ *      OS_OK           No error
+ */
+os_error_t
+os_mutex_release(struct os_mutex *mu)
+{
+    int resched;
+    os_sr_t sr;
+    struct os_task *current;
+    struct os_task *rdy;
+
+    /* Check if OS is started */
+    if (!g_os_started) {
+        return (OS_NOT_STARTED);
+    }
+
+    /* Check for valid mutex */
+    if (!mu) {
+        return OS_INVALID_PARM;
+    }
+
+    /* We better own this mutex! */
+    current = os_sched_get_current_task();
+    if ((mu->mu_level == 0) || (mu->mu_owner != current)) {
+        return (OS_BAD_MUTEX);
+    }
+
+    /* Decrement nesting level by 1. If not zero, nested (so dont release!) */
+    --mu->mu_level;
+    if (mu->mu_level != 0) {
+        return (OS_OK);
+    }
+
+    OS_ENTER_CRITICAL(sr);
+    os_trace_void(OS_TRACE_ID_MUTEX_RELEASE);
+
+    /* Restore owner task's priority; resort list if different  */
+    if (current->t_prio != mu->mu_prio) {
+        current->t_prio = mu->mu_prio;
+        os_sched_resort(current);
+    }
+
+    /* Check if tasks are waiting for the mutex */
+    rdy = SLIST_FIRST(&mu->mu_head);
+    if (rdy) {
+        /* There is one waiting. Wake it up */
+        assert(rdy->t_obj);
+        os_sched_wakeup(rdy);
+
+        /* Set mutex internals */
+        mu->mu_level = 1;
+        mu->mu_prio = rdy->t_prio;
+    }
+
+    /* Set new owner of mutex (or NULL if not owned) */
+    mu->mu_owner = rdy;
+    if (rdy) {
+        rdy->t_lockcnt++;
+    }
+    --current->t_lockcnt;
+
+    /* Do we need to re-schedule? */
+    resched = 0;
+    rdy = os_sched_next_task();
+    if (rdy != current) {
+        resched = 1;
+    }
+    OS_EXIT_CRITICAL(sr);
+
+    /* Re-schedule if needed */
+    if (resched) {
+        os_sched(rdy);
+    }
+    os_trace_end_call(OS_TRACE_ID_MUTEX_RELEASE);
+
+    return OS_OK;
+}
+
+/**
+ * os mutex pend
+ *
+ * Pend (wait) for a mutex.
+ *
+ * @param mu Pointer to mutex.
+ * @param timeout Timeout, in os ticks. A timeout of 0 means do
+ *                not wait if not available. A timeout of
+ *                0xFFFFFFFF means wait forever.
+ *
+ *
+ * @return os_error_t
+ *      OS_INVALID_PARM     Mutex passed in was NULL.
+ *      OS_TIMEOUT          Mutex was owned by another task and timeout=0
+ *      OS_OK               no error.
+ */
+os_error_t
+os_mutex_pend(struct os_mutex *mu, uint32_t timeout)
+{
+    os_sr_t sr;
+    os_error_t rc;
+    struct os_task *current;
+    struct os_task *entry;
+    struct os_task *last;
+
+    /* OS must be started when calling this function */
+    if (!g_os_started) {
+        return (OS_NOT_STARTED);
+    }
+
+    /* Check for valid mutex */
+    if (!mu) {
+        return OS_INVALID_PARM;
+    }
+
+    OS_ENTER_CRITICAL(sr);
+
+    /* Is this owned? */
+    current = os_sched_get_current_task();
+    if (mu->mu_level == 0) {
+        mu->mu_owner = current;
+        mu->mu_prio  = current->t_prio;
+        current->t_lockcnt++;
+        mu->mu_level = 1;
+        OS_EXIT_CRITICAL(sr);
+        return OS_OK;
+    }
+
+    /* Are we owner? */
+    if (mu->mu_owner == current) {
+        ++mu->mu_level;
+        OS_EXIT_CRITICAL(sr);
+        return OS_OK;
+    }
+
+    /* Mutex is not owned by us. If timeout is 0, return immediately */
+    if (timeout == 0) {
+        OS_EXIT_CRITICAL(sr);
+        return OS_TIMEOUT;
+    }
+
+    os_trace_void(OS_TRACE_ID_MUTEX_PEND);
+
+    /* Change priority of owner if needed */
+    if (mu->mu_owner->t_prio > current->t_prio) {
+        mu->mu_owner->t_prio = current->t_prio;
+        os_sched_resort(mu->mu_owner);
+    }
+
+    /* Link current task to tasks waiting for mutex */
+    last = NULL;
+    if (!SLIST_EMPTY(&mu->mu_head)) {
+        /* Insert in priority order */
+        SLIST_FOREACH(entry, &mu->mu_head, t_obj_list) {
+            if (current->t_prio < entry->t_prio) {
+                break;
+            }
+            last = entry;
+        }
+    }
+
+    if (last) {
+        SLIST_INSERT_AFTER(last, current, t_obj_list);
+    } else {
+        SLIST_INSERT_HEAD(&mu->mu_head, current, t_obj_list);
+    }
+
+    /* Set mutex pointer in task */
+    current->t_obj = mu;
+    current->t_flags |= OS_TASK_FLAG_MUTEX_WAIT;
+    os_sched_sleep(current, timeout);
+    OS_EXIT_CRITICAL(sr);
+
+    os_sched(NULL);
+
+    OS_ENTER_CRITICAL(sr);
+    current->t_flags &= ~OS_TASK_FLAG_MUTEX_WAIT;
+    OS_EXIT_CRITICAL(sr);
+
+    /* If we are owner we did not time out. */
+    if (mu->mu_owner == current) {
+        rc = OS_OK;
+    } else {
+        rc = OS_TIMEOUT;
+    }
+    os_trace_end_call(OS_TRACE_ID_MUTEX_PEND);
+
+    return rc;
+}
+
+
+/**
+ *   @} OSMutex
+ * @} OSKernel
+ */
diff --git a/porting/common/src/os/os_priv.h b/porting/common/src/os/os_priv.h
new file mode 100644
index 0000000..be7f458
--- /dev/null
+++ b/porting/common/src/os/os_priv.h
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 H_OS_PRIV_
+#define H_OS_PRIV_
+
+#include "os/queue.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern struct os_task g_idle_task;
+extern struct os_task_list g_os_run_list;
+extern struct os_task_list g_os_sleep_list;
+extern struct os_task_stailq g_os_task_list;
+extern struct os_callout_list g_callout_list;
+
+void os_msys_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/porting/common/src/os/os_sanity.c b/porting/common/src/os/os_sanity.c
new file mode 100644
index 0000000..5b96711
--- /dev/null
+++ b/porting/common/src/os/os_sanity.c
@@ -0,0 +1,250 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 <assert.h>
+#include <string.h>
+
+#include "os/os.h"
+
+/**
+ * @addtogroup OSKernel
+ * @{
+ *   @defgroup OSSanity Sanity
+ *   @{
+ */
+
+SLIST_HEAD(, os_sanity_check) g_os_sanity_check_list =
+    SLIST_HEAD_INITIALIZER(os_sanity_check_list);
+
+struct os_mutex g_os_sanity_check_mu;
+
+/**
+ * Initialize a sanity check
+ *
+ * @param sc The sanity check to initialize
+ *
+ * @return 0 on success, error code on failure.
+ */
+int
+os_sanity_check_init(struct os_sanity_check *sc)
+{
+    memset(sc, 0, sizeof(*sc));
+
+    return (0);
+}
+
+/**
+ * Lock the sanity check list
+ *
+ * @return 0 on success, error code on failure.
+ */
+static int
+os_sanity_check_list_lock(void)
+{
+    int rc;
+
+    if (!g_os_started) {
+        return (0);
+    }
+
+    rc = os_mutex_pend(&g_os_sanity_check_mu, OS_WAIT_FOREVER);
+    if (rc != OS_OK) {
+        goto err;
+    }
+
+    return (0);
+err:
+    return (rc);
+}
+
+/**
+ * Unlock the sanity check list
+ *
+ * @return 0 on success, error code on failure
+ */
+static int
+os_sanity_check_list_unlock(void)
+{
+    int rc;
+
+    if (!g_os_started) {
+        return (0);
+    }
+
+    rc = os_mutex_release(&g_os_sanity_check_mu);
+    if (rc != 0) {
+        goto err;
+    }
+
+    return (0);
+err:
+    return (rc);
+}
+
+/**
+ * Provide a "task checkin" for the sanity task.
+ *
+ * @param t The task to check in
+ *
+ * @return 0 on success, error code on failure
+ */
+int
+os_sanity_task_checkin(struct os_task *t)
+{
+    int rc;
+
+    if (t == NULL) {
+        t = os_sched_get_current_task();
+    }
+
+    rc = os_sanity_check_reset(&t->t_sanity_check);
+    if (rc != OS_OK) {
+        goto err;
+    }
+
+    return (0);
+err:
+    return (rc);
+}
+
+
+/**
+ * Register a sanity check
+ *
+ * @param sc The sanity check to register
+ *
+ * @return 0 on success, error code on failure
+ */
+int
+os_sanity_check_register(struct os_sanity_check *sc)
+{
+    int rc;
+
+    rc = os_sanity_check_list_lock();
+    if (rc != OS_OK) {
+        goto err;
+    }
+
+    SLIST_INSERT_HEAD(&g_os_sanity_check_list, sc, sc_next);
+
+    rc = os_sanity_check_list_unlock();
+    if (rc != OS_OK) {
+        goto err;
+    }
+
+    return (0);
+err:
+    return (rc);
+}
+
+
+/**
+ * Reset the os sanity check, so that it doesn't trip up the
+ * sanity timer.
+ *
+ * @param sc The sanity check to reset
+ *
+ * @return 0 on success, error code on failure
+ */
+int
+os_sanity_check_reset(struct os_sanity_check *sc)
+{
+    int rc;
+
+    rc = os_sanity_check_list_lock();
+    if (rc != OS_OK) {
+        goto err;
+    }
+
+    sc->sc_checkin_last = os_time_get();
+
+    rc = os_sanity_check_list_unlock();
+    if (rc != OS_OK) {
+        goto err;
+    }
+
+    return (0);
+err:
+    return (rc);
+}
+
+/*
+ * Called from the IDLE task context, every MYNEWT_VAL(SANITY_INTERVAL) msecs.
+ *
+ * Goes through the sanity check list, and performs sanity checks.  If any of
+ * these checks failed, or tasks have not checked in, it resets the processor.
+ */
+void
+os_sanity_run(void)
+{
+    struct os_sanity_check *sc;
+    int rc;
+
+    rc = os_sanity_check_list_lock();
+    if (rc != 0) {
+        assert(0);
+    }
+
+    SLIST_FOREACH(sc, &g_os_sanity_check_list, sc_next) {
+        rc = OS_OK;
+
+        if (sc->sc_func) {
+            rc = sc->sc_func(sc, sc->sc_arg);
+            if (rc == OS_OK) {
+                sc->sc_checkin_last = os_time_get();
+                continue;
+            }
+        }
+
+        if (OS_TIME_TICK_GT(os_time_get(),
+                    sc->sc_checkin_last + sc->sc_checkin_itvl)) {
+            assert(0);
+        }
+    }
+
+    rc = os_sanity_check_list_unlock();
+    if (rc != 0) {
+        assert(0);
+    }
+}
+
+/**
+ * Initialize the sanity task and mutex.
+ *
+ * @return 0 on success, error code on failure
+ */
+int
+os_sanity_init(void)
+{
+    int rc;
+
+    rc = os_mutex_init(&g_os_sanity_check_mu);
+    if (rc != 0) {
+        goto err;
+    }
+
+    return (0);
+err:
+    return (rc);
+}
+
+/**
+ *   @} OSSanity
+ * @} OSKernel
+ */
diff --git a/porting/common/src/os/os_sched.c b/porting/common/src/os/os_sched.c
new file mode 100644
index 0000000..9204a73
--- /dev/null
+++ b/porting/common/src/os/os_sched.c
@@ -0,0 +1,377 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 "os/os.h"
+#include "os/os_trace_api.h"
+#include "os/queue.h"
+#include <assert.h>
+#include "../os/os_priv.h"
+
+/**
+ * @addtogroup OSKernel
+ * @{
+ *   @defgroup OSSched Scheduler
+ *   @{
+ */
+
+struct os_task_list g_os_run_list = TAILQ_HEAD_INITIALIZER(g_os_run_list);
+struct os_task_list g_os_sleep_list = TAILQ_HEAD_INITIALIZER(g_os_sleep_list);
+
+struct os_task *g_current_task;
+
+extern os_time_t g_os_time;
+os_time_t g_os_last_ctx_sw_time;
+
+/**
+ * os sched insert
+ *
+ * Insert a task into the scheduler list. This causes the task to be evaluated
+ * for running when os_sched is called.
+ *
+ * @param t     Pointer to task to insert in run list
+ *
+ * @return int  OS_OK: task was inserted into run list
+ *              OS_EINVAL: Task was not in ready state.
+ */
+os_error_t
+os_sched_insert(struct os_task *t)
+{
+    struct os_task *entry;
+    os_sr_t sr;
+    os_error_t rc;
+
+    if (t->t_state != OS_TASK_READY) {
+        rc = OS_EINVAL;
+        goto err;
+    }
+
+    entry = NULL;
+    OS_ENTER_CRITICAL(sr);
+    TAILQ_FOREACH(entry, &g_os_run_list, t_os_list) {
+        if (t->t_prio < entry->t_prio) {
+            break;
+        }
+    }
+    if (entry) {
+        TAILQ_INSERT_BEFORE(entry, (struct os_task *) t, t_os_list);
+    } else {
+        TAILQ_INSERT_TAIL(&g_os_run_list, (struct os_task *) t, t_os_list);
+    }
+    OS_EXIT_CRITICAL(sr);
+
+    return (0);
+err:
+    return (rc);
+}
+
+void
+os_sched_ctx_sw_hook(struct os_task *next_t)
+{
+#if MYNEWT_VAL(OS_CTX_SW_STACK_CHECK)
+    os_stack_t *top;
+    int i;
+
+    top = g_current_task->t_stacktop - g_current_task->t_stacksize;
+    for (i = 0; i < MYNEWT_VAL(OS_CTX_SW_STACK_GUARD); i++) {
+        assert(top[i] == OS_STACK_PATTERN);
+    }
+#endif
+    os_trace_task_start_exec(next_t->t_taskid);
+    next_t->t_ctx_sw_cnt++;
+    g_current_task->t_run_time += g_os_time - g_os_last_ctx_sw_time;
+    g_os_last_ctx_sw_time = g_os_time;
+}
+
+/**
+ * os sched get current task
+ *
+ * Returns the currently running task. Note that this task may or may not be
+ * the highest priority task ready to run.
+ *
+ *
+ * @return struct os_task*
+ */
+struct os_task *
+os_sched_get_current_task(void)
+{
+    return (g_current_task);
+}
+
+/**
+ * os sched set current task
+ *
+ * Sets the currently running task to 't'. Note that this function simply sets
+ * the global variable holding the currently running task. It does not perform
+ * a context switch or change the os run or sleep list.
+ *
+ * @param t Pointer to currently running task.
+ */
+void
+os_sched_set_current_task(struct os_task *t)
+{
+    g_current_task = t;
+}
+
+/**
+ * os sched
+ *
+ * Performs a context switch. When called, it will either find the highest
+ * priority task ready to run if next_t is NULL (i.e. the head of the os run
+ * list) or will schedule next_t as the task to run.
+ *
+ * @param next_t Task to run
+ */
+void
+os_sched(struct os_task *next_t)
+{
+    os_sr_t sr;
+
+    OS_ENTER_CRITICAL(sr);
+
+    if (!next_t) {
+        next_t = os_sched_next_task();
+    }
+
+    os_arch_ctx_sw(next_t);
+
+    OS_EXIT_CRITICAL(sr);
+}
+
+/**
+ * os sched sleep
+ *
+ * Removes the task from the run list and puts it on the sleep list.
+ *
+ * @param t Task to put to sleep
+ * @param nticks Number of ticks to put task to sleep
+ *
+ * @return int
+ *
+ * NOTE: must be called with interrupts disabled! This function does not call
+ * the scheduler
+ */
+int
+os_sched_sleep(struct os_task *t, os_time_t nticks)
+{
+    struct os_task *entry;
+
+    entry = NULL;
+
+    TAILQ_REMOVE(&g_os_run_list, t, t_os_list);
+    t->t_state = OS_TASK_SLEEP;
+    t->t_next_wakeup = os_time_get() + nticks;
+    if (nticks == OS_TIMEOUT_NEVER) {
+        t->t_flags |= OS_TASK_FLAG_NO_TIMEOUT;
+        TAILQ_INSERT_TAIL(&g_os_sleep_list, t, t_os_list);
+    } else {
+        TAILQ_FOREACH(entry, &g_os_sleep_list, t_os_list) {
+            if ((entry->t_flags & OS_TASK_FLAG_NO_TIMEOUT) ||
+                    OS_TIME_TICK_GT(entry->t_next_wakeup, t->t_next_wakeup)) {
+                break;
+            }
+        }
+        if (entry) {
+            TAILQ_INSERT_BEFORE(entry, t, t_os_list);
+        } else {
+            TAILQ_INSERT_TAIL(&g_os_sleep_list, t, t_os_list);
+        }
+    }
+
+    os_trace_task_stop_ready(t->t_taskid, OS_TASK_SLEEP);
+    return (0);
+}
+
+/**
+ * os sched remove
+ *
+ * XXX
+ * NOTE - This routine is currently experimental and not ready for common use
+ *
+ * Stops a task and removes it from the task list.
+ *
+ * @return int
+ *
+ * NOTE: must be called with interrupts disabled! This function does not call
+ * the scheduler
+ */
+int
+os_sched_remove(struct os_task *t)
+{
+
+    if (t->t_state == OS_TASK_SLEEP) {
+        TAILQ_REMOVE(&g_os_sleep_list, t, t_os_list);
+    } else if (t->t_state == OS_TASK_READY) {
+        TAILQ_REMOVE(&g_os_run_list, t, t_os_list);
+    }
+    t->t_next_wakeup = 0;
+    t->t_flags |= OS_TASK_FLAG_NO_TIMEOUT;
+
+    STAILQ_REMOVE(&g_os_task_list, t, os_task, t_os_task_list);
+
+    os_trace_task_stop_exec();
+    return OS_OK;
+}
+
+/**
+ * os sched wakeup
+ *
+ * Called to wake up a task. Waking up a task consists of setting the task state
+ * to READY and moving it from the sleep list to the run list.
+ *
+ * @param t     Pointer to task to wake up.
+ *
+ * @return int
+ *
+ * NOTE: This function must be called with interrupts disabled.
+ */
+int
+os_sched_wakeup(struct os_task *t)
+{
+    struct os_task_obj *os_obj;
+
+    assert(t->t_state == OS_TASK_SLEEP);
+
+    /* Remove self from object list if waiting on one */
+    if (t->t_obj) {
+        os_obj = (struct os_task_obj *)t->t_obj;
+        assert(!SLIST_EMPTY(&os_obj->obj_head));
+        SLIST_REMOVE(&os_obj->obj_head, t, os_task, t_obj_list);
+        SLIST_NEXT(t, t_obj_list) = NULL;
+        t->t_obj = NULL;
+    }
+
+    /* Remove task from sleep list */
+    t->t_state = OS_TASK_READY;
+    t->t_next_wakeup = 0;
+    t->t_flags &= ~OS_TASK_FLAG_NO_TIMEOUT;
+    TAILQ_REMOVE(&g_os_sleep_list, t, t_os_list);
+    os_sched_insert(t);
+
+    return (0);
+}
+
+/**
+ * os sched os timer exp
+ *
+ * Called when the OS tick timer expires. Search the sleep list for any tasks
+ * that need waking up. This occurs when the current OS time exceeds the next
+ * wakeup time stored in the task. Any tasks that need waking up will be
+ * removed from the sleep list and added to the run list.
+ *
+ */
+void
+os_sched_os_timer_exp(void)
+{
+    struct os_task *t;
+    struct os_task *next;
+    os_time_t now;
+    os_sr_t sr;
+
+    now = os_time_get();
+
+    OS_ENTER_CRITICAL(sr);
+
+    /*
+     * Wakeup any tasks that have their sleep timer expired
+     */
+    t = TAILQ_FIRST(&g_os_sleep_list);
+    while (t) {
+        /* If task waiting forever, do not check next wakeup time */
+        if (t->t_flags & OS_TASK_FLAG_NO_TIMEOUT) {
+            break;
+        }
+        next = TAILQ_NEXT(t, t_os_list);
+        if (OS_TIME_TICK_GEQ(now, t->t_next_wakeup)) {
+            os_trace_task_start_ready(t->t_taskid);
+            os_sched_wakeup(t);
+        } else {
+            break;
+        }
+        t = next;
+    }
+
+    OS_EXIT_CRITICAL(sr);
+}
+
+/*
+ * Return the number of ticks until the first sleep timer expires.If there are
+ * no such tasks then return OS_TIMEOUT_NEVER instead.
+ */
+os_time_t
+os_sched_wakeup_ticks(os_time_t now)
+{
+    os_time_t rt;
+    struct os_task *t;
+
+    OS_ASSERT_CRITICAL();
+
+    t = TAILQ_FIRST(&g_os_sleep_list);
+    if (t == NULL || (t->t_flags & OS_TASK_FLAG_NO_TIMEOUT)) {
+        rt = OS_TIMEOUT_NEVER;
+    } else if (OS_TIME_TICK_GEQ(t->t_next_wakeup, now)) {
+        rt = t->t_next_wakeup - now;
+    } else {
+        rt = 0;     /* wakeup time was in the past */
+    }
+    return (rt);
+}
+
+/**
+ * os sched next task
+ *
+ * Returns the task that we should be running. This is the task at the head
+ * of the run list.
+ *
+ * NOTE: if you want to guarantee that the os run list does not change after
+ * calling this function you have to call it with interrupts disabled.
+ *
+ * @return struct os_task*
+ */
+struct os_task *
+os_sched_next_task(void)
+{
+    return (TAILQ_FIRST(&g_os_run_list));
+}
+
+/**
+ * os sched resort
+ *
+ * Resort a task that is in the ready list as its priority has
+ * changed. If the task is not in the ready state, there is
+ * nothing to do.
+ *
+ * @param t Pointer to task to insert back into ready to run
+ *          list.
+ *
+ * NOTE: this function expects interrupts to be disabled so they
+ * are not disabled here.
+ */
+void
+os_sched_resort(struct os_task *t)
+{
+    if (t->t_state == OS_TASK_READY) {
+        TAILQ_REMOVE(&g_os_run_list, t, t_os_list);
+        os_sched_insert(t);
+    }
+}
+
+/**
+ *   @} OSSched
+ * @} OSKernel
+ */
diff --git a/porting/common/src/os/os_sem.c b/porting/common/src/os/os_sem.c
new file mode 100644
index 0000000..7566087
--- /dev/null
+++ b/porting/common/src/os/os_sem.c
@@ -0,0 +1,225 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 "os/os.h"
+#include <assert.h>
+
+
+/**
+ * @addtogroup OSKernel
+ * @{
+ *   @defgroup OSSem Semaphores
+ *   @{
+ */
+
+/* XXX:
+ * 1) Should I check to see if we are within an ISR for some of these?
+ * 2) Would I do anything different for os_sem_release() if we were in an
+ *    ISR when this was called?
+ */
+
+/**
+ * os sem initialize
+ *
+ * Initialize a semaphore
+ *
+ * @param sem Pointer to semaphore
+ *        tokens: # of tokens the semaphore should contain initially.
+ *
+ * @return os_error_t
+ *      OS_INVALID_PARM     Semaphore passed in was NULL.
+ *      OS_OK               no error.
+ */
+os_error_t
+os_sem_init(struct os_sem *sem, uint16_t tokens)
+{
+    if (!sem) {
+        return OS_INVALID_PARM;
+    }
+
+    sem->sem_tokens = tokens;
+    SLIST_FIRST(&sem->sem_head) = NULL;
+
+    return OS_OK;
+}
+
+/**
+ * os sem release
+ *
+ * Release a semaphore.
+ *
+ * @param sem Pointer to the semaphore to be released
+ *
+ * @return os_error_t
+ *      OS_INVALID_PARM Semaphore passed in was NULL.
+ *      OS_OK No error
+ */
+os_error_t
+os_sem_release(struct os_sem *sem)
+{
+    int resched;
+    os_sr_t sr;
+    struct os_task *current;
+    struct os_task *rdy;
+
+    /* OS must be started to release semaphores */
+    if (!g_os_started) {
+        return (OS_NOT_STARTED);
+    }
+
+    /* Check for valid semaphore */
+    if (!sem) {
+        return OS_INVALID_PARM;
+    }
+
+    /* Get current task */
+    resched = 0;
+    current = os_sched_get_current_task();
+
+    OS_ENTER_CRITICAL(sr);
+
+    /* Check if tasks are waiting for the semaphore */
+    rdy = SLIST_FIRST(&sem->sem_head);
+    if (rdy) {
+        /* Clear flag that we are waiting on the semaphore; wake up task */
+        rdy->t_flags &= ~OS_TASK_FLAG_SEM_WAIT;
+        os_sched_wakeup(rdy);
+
+        /* Schedule if waiting task higher priority */
+        if (current->t_prio > rdy->t_prio) {
+            resched = 1;
+        }
+    } else {
+        /* Add to the number of tokens */
+        sem->sem_tokens++;
+    }
+
+    OS_EXIT_CRITICAL(sr);
+
+    /* Re-schedule if needed */
+    if (resched) {
+        os_sched(rdy);
+    }
+
+    return OS_OK;
+}
+
+/**
+ * os sem pend
+ *
+ * Pend (wait) for a semaphore.
+ *
+ * @param mu Pointer to semaphore.
+ * @param timeout Timeout, in os ticks. A timeout of 0 means do
+ *                not wait if not available. A timeout of
+ *                0xFFFFFFFF means wait forever.
+ *
+ *
+ * @return os_error_t
+ *      OS_INVALID_PARM     Semaphore passed in was NULL.
+ *      OS_TIMEOUT          Semaphore was owned by another task and timeout=0
+ *      OS_OK               no error.
+ */
+os_error_t
+os_sem_pend(struct os_sem *sem, uint32_t timeout)
+{
+    os_sr_t sr;
+    os_error_t rc;
+    int sched;
+    struct os_task *current;
+    struct os_task *entry;
+    struct os_task *last;
+
+    /* Check if OS is started */
+    if (!g_os_started) {
+        return (OS_NOT_STARTED);
+    }
+
+    /* Check for valid semaphore */
+    if (!sem) {
+        return OS_INVALID_PARM;
+    }
+
+    /* Assume we dont have to put task to sleep; get current task */
+    sched = 0;
+    current = os_sched_get_current_task();
+
+    OS_ENTER_CRITICAL(sr);
+
+    /*
+     * If there is a token available, take it. If no token, either return
+     * with error if timeout was 0 or put this task to sleep.
+     */
+    if (sem->sem_tokens != 0) {
+        sem->sem_tokens--;
+        rc = OS_OK;
+    } else if (timeout == 0) {
+        rc = OS_TIMEOUT;
+    } else {
+        /* Silence gcc maybe-uninitialized warning. */
+        rc = OS_OK;
+
+        /* Link current task to tasks waiting for semaphore */
+        current->t_obj = sem;
+        current->t_flags |= OS_TASK_FLAG_SEM_WAIT;
+        last = NULL;
+        if (!SLIST_EMPTY(&sem->sem_head)) {
+            /* Insert in priority order */
+            SLIST_FOREACH(entry, &sem->sem_head, t_obj_list) {
+                if (current->t_prio < entry->t_prio) {
+                    break;
+                }
+                last = entry;
+            }
+        }
+
+        if (last) {
+            SLIST_INSERT_AFTER(last, current, t_obj_list);
+        } else {
+            SLIST_INSERT_HEAD(&sem->sem_head, current, t_obj_list);
+        }
+
+        /* We will put this task to sleep */
+        sched = 1;
+        os_sched_sleep(current, timeout);
+    }
+
+    OS_EXIT_CRITICAL(sr);
+
+    if (sched) {
+        os_sched(NULL);
+        /* Check if we timed out or got the semaphore */
+        if (current->t_flags & OS_TASK_FLAG_SEM_WAIT) {
+            OS_ENTER_CRITICAL(sr);
+            current->t_flags &= ~OS_TASK_FLAG_SEM_WAIT;
+            OS_EXIT_CRITICAL(sr);
+            rc = OS_TIMEOUT;
+        } else {
+            rc = OS_OK;
+        }
+    }
+
+    return rc;
+}
+
+
+/**
+ *   @} OSSched
+ * @} OSKernel
+ */
diff --git a/porting/common/src/os/os_task.c b/porting/common/src/os/os_task.c
new file mode 100644
index 0000000..4f96209
--- /dev/null
+++ b/porting/common/src/os/os_task.c
@@ -0,0 +1,284 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 "os/os.h"
+#include "os/os_trace_api.h"
+
+#include <assert.h>
+#include <string.h>
+#include "../os/os_priv.h"
+
+/**
+ * @addtogroup OSKernel
+ * @{
+ *   @defgroup OSTask Tasks
+ *   @{
+ */
+
+uint8_t g_task_id;
+
+struct os_task_stailq g_os_task_list;
+
+static void
+_clear_stack(os_stack_t *stack_bottom, int size)
+{
+    int i;
+
+    for (i = 0; i < size; i++) {
+        stack_bottom[i] = OS_STACK_PATTERN;
+    }
+}
+
+static inline uint8_t
+os_task_next_id(void)
+{
+    uint8_t rc;
+    os_sr_t sr;
+
+    OS_ENTER_CRITICAL(sr);
+    rc = g_task_id;
+    g_task_id++;
+    OS_EXIT_CRITICAL(sr);
+
+    return (rc);
+}
+
+/**
+ * Return the number of tasks initialized.
+ *
+ * @return number of tasks initialized
+ */
+uint8_t
+os_task_count(void)
+{
+    return (g_task_id);
+}
+
+/**
+ * Initialize a task.
+ *
+ * This function initializes the task structure pointed to by t,
+ * clearing and setting it's stack pointer, provides sane defaults
+ * and sets the task as ready to run, and inserts it into the operating
+ * system scheduler.
+ *
+ * @param t The task to initialize
+ * @param name The name of the task to initialize
+ * @param func The task function to call
+ * @param arg The argument to pass to this task function
+ * @param prio The priority at which to run this task
+ * @param sanity_itvl The time at which this task should check in with the
+ *                    sanity task.  OS_WAIT_FOREVER means never check in
+ *                    here.
+ * @param stack_bottom A pointer to the bottom of a task's stack
+ * @param stack_size The overall size of the task's stack.
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+int
+os_task_init(struct os_task *t, const char *name, os_task_func_t func,
+        void *arg, uint8_t prio, os_time_t sanity_itvl,
+        os_stack_t *stack_bottom, uint16_t stack_size)
+{
+    struct os_sanity_check *sc;
+    int rc;
+    struct os_task *task;
+
+    memset(t, 0, sizeof(*t));
+
+    t->t_func = func;
+    t->t_arg = arg;
+
+    t->t_taskid = os_task_next_id();
+    t->t_prio = prio;
+
+    t->t_state = OS_TASK_READY;
+    t->t_name = name;
+    t->t_next_wakeup = 0;
+
+    rc = os_sanity_check_init(&t->t_sanity_check);
+    if (rc != OS_OK) {
+        goto err;
+    }
+
+    if (sanity_itvl != OS_WAIT_FOREVER) {
+        sc = (struct os_sanity_check *) &t->t_sanity_check;
+        sc->sc_checkin_itvl = sanity_itvl;
+
+        rc = os_sanity_check_register(sc);
+        if (rc != OS_OK) {
+            goto err;
+        }
+    }
+
+    _clear_stack(stack_bottom, stack_size);
+    t->t_stacktop = &stack_bottom[stack_size];
+    t->t_stacksize = stack_size;
+    t->t_stackptr = os_arch_task_stack_init(t, t->t_stacktop,
+            t->t_stacksize);
+
+    STAILQ_FOREACH(task, &g_os_task_list, t_os_task_list) {
+        assert(t->t_prio != task->t_prio);
+    }
+
+    /* insert this task into the task list */
+    STAILQ_INSERT_TAIL(&g_os_task_list, t, t_os_task_list);
+
+    /* insert this task into the scheduler list */
+    rc = os_sched_insert(t);
+    if (rc != OS_OK) {
+        goto err;
+    }
+
+    os_trace_task_info(t);
+
+    return (0);
+err:
+    return (rc);
+}
+
+/*
+ * Removes specified task
+ * XXX
+ * NOTE: This interface is currently experimental and not ready for common use
+ */
+int
+os_task_remove(struct os_task *t)
+{
+    struct os_task *current;
+    int rc;
+    os_sr_t sr;
+
+    current = os_sched_get_current_task();
+    /*
+     * Can't suspend yourself
+     */
+    if (t->t_taskid == current->t_taskid) {
+        return OS_INVALID_PARM;
+    }
+
+    /*
+     * If state is not READY or SLEEP, assume task has not been initialized
+     */
+    if (t->t_state != OS_TASK_READY && t->t_state != OS_TASK_SLEEP)
+    {
+        return OS_NOT_STARTED;
+    }
+
+    /*
+     * Disallow suspending tasks which are waiting on a lock
+     */
+    if (t->t_flags & (OS_TASK_FLAG_SEM_WAIT | OS_TASK_FLAG_MUTEX_WAIT |
+                                               OS_TASK_FLAG_EVQ_WAIT)) {
+        return OS_EBUSY;
+    }
+
+    /*
+     * Disallowing suspending tasks which are holding a mutex
+     */
+    if (t->t_lockcnt) {
+        return OS_EBUSY;
+    }
+
+    OS_ENTER_CRITICAL(sr);
+    rc = os_sched_remove(t);
+    OS_EXIT_CRITICAL(sr);
+    return rc;
+}
+
+/**
+ * Iterate through tasks, and return the following information about them:
+ *
+ * - Priority
+ * - Task ID
+ * - State (ACTIVE, SLEEP)
+ * - Total Stack Usage
+ * - Stack Size
+ * - Context Switch Count
+ * - Runtime
+ * - Last & Next Sanity checkin
+ * - Task Name
+ *
+ * To get the first task in the list, call os_task_info_get_next() with a
+ * NULL pointer in the prev argument, and os_task_info_get_next() will
+ * return a pointer to the task structure, and fill out the os_task_info
+ * structure pointed to by oti.
+ *
+ * To get the next task in the list, provide the task structure returned
+ * by the previous call to os_task_info_get_next(), and os_task_info_get_next()
+ * will fill out the task structure pointed to by oti again, and return
+ * the next task in the list.
+ *
+ * @param prev The previous task returned by os_task_info_get_next(), or NULL
+ *             to begin iteration.
+ * @param oti  The OS task info structure to fill out.
+ *
+ * @return A pointer to the OS task that has been read, or NULL when finished
+ *         iterating through all tasks.
+ */
+struct os_task *
+os_task_info_get_next(const struct os_task *prev, struct os_task_info *oti)
+{
+    struct os_task *next;
+    os_stack_t *top;
+    os_stack_t *bottom;
+
+    if (prev != NULL) {
+        next = STAILQ_NEXT(prev, t_os_task_list);
+    } else {
+        next = STAILQ_FIRST(&g_os_task_list);
+    }
+
+    if (next == NULL) {
+        return (NULL);
+    }
+
+    /* Otherwise, copy OS task information into the OTI structure, and
+     * return 1, which means continue
+     */
+    oti->oti_prio = next->t_prio;
+    oti->oti_taskid = next->t_taskid;
+    oti->oti_state = next->t_state;
+
+    top = next->t_stacktop;
+    bottom = next->t_stacktop - next->t_stacksize;
+    while (bottom < top) {
+        if (*bottom != OS_STACK_PATTERN) {
+            break;
+        }
+        ++bottom;
+    }
+
+    oti->oti_stkusage = (uint16_t) (next->t_stacktop - bottom);
+    oti->oti_stksize = next->t_stacksize;
+    oti->oti_cswcnt = next->t_ctx_sw_cnt;
+    oti->oti_runtime = next->t_run_time;
+    oti->oti_last_checkin = next->t_sanity_check.sc_checkin_last;
+    oti->oti_next_checkin = next->t_sanity_check.sc_checkin_last +
+        next->t_sanity_check.sc_checkin_itvl;
+    strncpy(oti->oti_name, next->t_name, sizeof(oti->oti_name));
+
+    return (next);
+}
+
+/**
+ *   @} OSTask
+ * @} OSKernel
+ */
diff --git a/porting/common/src/os/os_time.c b/porting/common/src/os/os_time.c
new file mode 100644
index 0000000..3f6816d
--- /dev/null
+++ b/porting/common/src/os/os_time.c
@@ -0,0 +1,268 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 "syscfg/syscfg.h"
+
+#include <assert.h>
+
+#include "os/os.h"
+#include "os/queue.h"
+
+/**
+ * @addtogroup OSKernel
+ * @{
+ *   @defgroup OSTime Time
+ *   @{
+ */
+
+CTASSERT(sizeof(os_time_t) == 4);
+
+#define OS_USEC_PER_TICK    (1000000 / OS_TICKS_PER_SEC)
+
+os_time_t g_os_time;
+
+/*
+ * Time-of-day collateral.
+ */
+static struct {
+    os_time_t ostime;
+    struct os_timeval uptime;
+    struct os_timeval utctime;
+    struct os_timezone timezone;
+} basetod;
+
+static void
+os_deltatime(os_time_t delta, const struct os_timeval *base,
+    struct os_timeval *result)
+{
+    struct os_timeval tvdelta;
+
+    tvdelta.tv_sec = delta / OS_TICKS_PER_SEC;
+    tvdelta.tv_usec = (delta % OS_TICKS_PER_SEC) * OS_USEC_PER_TICK;
+    os_timeradd(base, &tvdelta, result);
+}
+
+/**
+ * Get the current OS time in ticks
+ *
+ * @return OS time in ticks
+ */
+os_time_t
+os_time_get(void)
+{
+    return (g_os_time);
+}
+
+#if MYNEWT_VAL(OS_SCHEDULING)
+static void
+os_time_tick(int ticks)
+{
+    os_sr_t sr;
+    os_time_t delta, prev_os_time;
+
+    assert(ticks >= 0);
+
+    OS_ENTER_CRITICAL(sr);
+    prev_os_time = g_os_time;
+    g_os_time += ticks;
+
+    /*
+     * Update 'basetod' when 'g_os_time' crosses the 0x00000000 and
+     * 0x80000000 thresholds.
+     */
+    if ((prev_os_time ^ g_os_time) >> 31) {
+        delta = g_os_time - basetod.ostime;
+        os_deltatime(delta, &basetod.uptime, &basetod.uptime);
+        os_deltatime(delta, &basetod.utctime, &basetod.utctime);
+        basetod.ostime = g_os_time;
+    }
+    OS_EXIT_CRITICAL(sr);
+}
+
+/**
+ * Move OS time forward ticks.
+ *
+ * @param ticks The number of ticks to move time forward.
+ */
+void
+os_time_advance(int ticks)
+{
+    assert(ticks >= 0);
+
+    if (ticks > 0) {
+        if (!os_started()) {
+            g_os_time += ticks;
+        } else {
+            os_time_tick(ticks);
+            os_callout_tick();
+            os_sched_os_timer_exp();
+            os_sched(NULL);
+        }
+    }
+}
+#else
+void
+os_time_advance(int ticks)
+{
+    g_os_time += ticks;
+}
+#endif
+
+/**
+ * Puts the current task to sleep for the specified number of os ticks. There
+ * is no delay if ticks is <= 0.
+ *
+ * @param osticks Number of ticks to delay (<= 0 means no delay).
+ */
+void
+os_time_delay(int32_t osticks)
+{
+    os_sr_t sr;
+
+    if (osticks > 0) {
+        OS_ENTER_CRITICAL(sr);
+        os_sched_sleep(os_sched_get_current_task(), (os_time_t)osticks);
+        OS_EXIT_CRITICAL(sr);
+        os_sched(NULL);
+    }
+}
+
+/**
+ * Set the time of day.  This does not modify os time, but rather just modifies
+ * the offset by which we are tracking real time against os time.
+ *
+ * @param utctime A timeval representing the UTC time we are setting
+ * @param tz The time-zone to apply against the utctime being set.
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+int
+os_settimeofday(struct os_timeval *utctime, struct os_timezone *tz)
+{
+    os_sr_t sr;
+    os_time_t delta;
+
+    OS_ENTER_CRITICAL(sr);
+    if (utctime != NULL) {
+        /*
+         * Update all time-of-day base values.
+         */
+        delta = os_time_get() - basetod.ostime;
+        os_deltatime(delta, &basetod.uptime, &basetod.uptime);
+        basetod.utctime = *utctime;
+        basetod.ostime += delta;
+    }
+
+    if (tz != NULL) {
+        basetod.timezone = *tz;
+    }
+    OS_EXIT_CRITICAL(sr);
+
+    return (0);
+}
+
+/**
+ * Get the current time of day.  Returns the time of day in UTC
+ * into the tv argument, and returns the timezone (if set) into
+ * tz.
+ *
+ * @param tv The structure to put the UTC time of day into
+ * @param tz The structure to put the timezone information into
+ *
+ * @return 0 on success, non-zero on failure
+ */
+int
+os_gettimeofday(struct os_timeval *tv, struct os_timezone *tz)
+{
+    os_sr_t sr;
+    os_time_t delta;
+
+    OS_ENTER_CRITICAL(sr);
+    if (tv != NULL) {
+        delta = os_time_get() - basetod.ostime;
+        os_deltatime(delta, &basetod.utctime, tv);
+    }
+
+    if (tz != NULL) {
+        *tz = basetod.timezone;
+    }
+    OS_EXIT_CRITICAL(sr);
+
+    return (0);
+}
+
+/**
+ * Get time since boot in microseconds.
+ *
+ * @return time since boot in microseconds
+ */
+int64_t
+os_get_uptime_usec(void)
+{
+  struct os_timeval tv;
+  os_time_t delta;
+  os_sr_t sr;
+  os_time_t ostime;
+
+
+  OS_ENTER_CRITICAL(sr);
+  tv = basetod.uptime;
+  ostime = basetod.ostime;
+  delta = os_time_get() - ostime;
+  OS_EXIT_CRITICAL(sr);
+
+  os_deltatime(delta, &tv, &tv);
+
+  return(tv.tv_sec * 1000000 + tv.tv_usec);
+}
+
+/**
+ * Converts milliseconds to OS ticks.
+ *
+ * @param ms                    The milliseconds input.
+ * @param out_ticks             The OS ticks output.
+ *
+ * @return                      0 on success; OS_EINVAL if the result is too
+ *                                  large to fit in a uint32_t.
+ */
+int
+os_time_ms_to_ticks(uint32_t ms, uint32_t *out_ticks)
+{
+    uint64_t ticks;
+
+#if OS_TICKS_PER_SEC == 1000
+    *out_ticks = ms;
+    return 0;
+#endif
+
+    _Static_assert(OS_TICKS_PER_SEC <= UINT32_MAX,
+                   "OS_TICKS_PER_SEC must be <= UINT32_MAX");
+
+    ticks = (uint64_t)ms * OS_TICKS_PER_SEC / 1000;
+    if (ticks > UINT32_MAX) {
+        return OS_EINVAL;
+    }
+
+    *out_ticks = ticks;
+    return 0;
+}
+
+/**
+ *   @} OSKernel
+ * @} OSTime
+ */
diff --git a/porting/common/src/sysinit/sysinit.c b/porting/common/src/sysinit/sysinit.c
new file mode 100644
index 0000000..393d1c5
--- /dev/null
+++ b/porting/common/src/sysinit/sysinit.c
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 <stdio.h>
+#include <stddef.h>
+#include <limits.h>
+#include "os/os_fault.h"
+#include "syscfg/syscfg.h"
+#include "sysinit/sysinit.h"
+
+static void
+sysinit_dflt_panic_cb(const char *file, int line, const char *func,
+                      const char *expr, const char *msg)
+{
+#if MYNEWT_VAL(SYSINIT_PANIC_MESSAGE)
+    if (msg != NULL) {
+        fprintf(stderr, "sysinit failure: %s\n", msg);
+    }
+#endif
+
+    __assert_func(file, line, func, expr);
+}
+
+sysinit_panic_fn *sysinit_panic_cb = sysinit_dflt_panic_cb;
+
+uint8_t sysinit_active;
+
+/**
+ * Sets the sysinit panic function; i.e., the function which executes when
+ * initialization fails.  By default, a panic triggers a failed assertion.
+ */
+void
+sysinit_panic_set(sysinit_panic_fn *panic_cb)
+{
+    sysinit_panic_cb = panic_cb;
+}
+
+void
+sysinit_start(void)
+{
+    sysinit_active = 1;
+}
+
+void
+sysinit_end(void)
+{
+    sysinit_active = 0;
+}
diff --git a/porting/freertos_nrf5_sdk/Makefile b/porting/freertos_nrf5_sdk/Makefile
new file mode 100644
index 0000000..fb2818b
--- /dev/null
+++ b/porting/freertos_nrf5_sdk/Makefile
@@ -0,0 +1,257 @@
+PROJECT_NAME     := nimble_FreeRTOS_pca10040
+TARGETS          := nrf52832_xxaa
+OUTPUT_DIRECTORY := _build
+
+NRF5_SDK_ROOT ?= ./nrf5_sdk
+PROJ_ROOT := ../..
+
+$(OUTPUT_DIRECTORY)/nrf52832_xxaa.out: \
+  LINKER_SCRIPT  := nimble_FreeRTOS_gcc_nrf52.ld
+
+# Source files common to all targets
+SRC_FILES += \
+  $(NRF5_SDK_ROOT)/components/libraries/log/src/nrf_log_backend_serial.c \
+  $(NRF5_SDK_ROOT)/components/libraries/log/src/nrf_log_frontend.c \
+  $(NRF5_SDK_ROOT)/components/libraries/button/app_button.c \
+  $(NRF5_SDK_ROOT)/components/libraries/util/app_error.c \
+  $(NRF5_SDK_ROOT)/components/libraries/util/app_error_weak.c \
+  $(NRF5_SDK_ROOT)/components/libraries/timer/app_timer_freertos.c \
+  $(NRF5_SDK_ROOT)/components/libraries/util/app_util_platform.c \
+  $(NRF5_SDK_ROOT)/components/libraries/util/nrf_assert.c \
+  $(NRF5_SDK_ROOT)/components/libraries/util/sdk_errors.c \
+  $(NRF5_SDK_ROOT)/external/freertos/source/croutine.c \
+  $(NRF5_SDK_ROOT)/external/freertos/source/event_groups.c \
+  $(NRF5_SDK_ROOT)/external/freertos/source/portable/MemMang/heap_1.c \
+  $(NRF5_SDK_ROOT)/external/freertos/source/list.c \
+  $(NRF5_SDK_ROOT)/external/freertos/portable/GCC/nrf52/port.c \
+  $(NRF5_SDK_ROOT)/external/freertos/portable/CMSIS/nrf52/port_cmsis.c \
+  $(NRF5_SDK_ROOT)/external/freertos/portable/CMSIS/nrf52/port_cmsis_systick.c \
+  $(NRF5_SDK_ROOT)/external/freertos/source/queue.c \
+  $(NRF5_SDK_ROOT)/external/freertos/source/tasks.c \
+  $(NRF5_SDK_ROOT)/external/freertos/source/timers.c \
+  $(NRF5_SDK_ROOT)/components/boards/boards.c \
+  $(NRF5_SDK_ROOT)/components/drivers_nrf/clock/nrf_drv_clock.c \
+  $(NRF5_SDK_ROOT)/components/drivers_nrf/common/nrf_drv_common.c \
+  $(NRF5_SDK_ROOT)/components/drivers_nrf/gpiote/nrf_drv_gpiote.c \
+  $(NRF5_SDK_ROOT)/components/drivers_nrf/uart/nrf_drv_uart.c \
+  $(NRF5_SDK_ROOT)/components/drivers_nrf/nrf_soc_nosd/nrf_nvic.c \
+  $(NRF5_SDK_ROOT)/components/drivers_nrf/nrf_soc_nosd/nrf_soc.c \
+  $(NRF5_SDK_ROOT)/components/libraries/bsp/bsp.c \
+  $(NRF5_SDK_ROOT)/components/libraries/bsp/bsp_nfc.c \
+  $(NRF5_SDK_ROOT)/external/segger_rtt/RTT_Syscalls_GCC.c \
+  $(NRF5_SDK_ROOT)/external/segger_rtt/SEGGER_RTT.c \
+  $(NRF5_SDK_ROOT)/external/segger_rtt/SEGGER_RTT_printf.c \
+  $(NRF5_SDK_ROOT)/components/toolchain/gcc/gcc_startup_nrf52.S \
+  $(NRF5_SDK_ROOT)/components/toolchain/system_nrf52.c \
+  ./src/main.c \
+  ./src/ble_task.c \
+  ./src/os_port.c \
+  ./src/cmsis_nvic.c \
+  ./src/hal_timer.c \
+  $(PROJ_ROOT)/porting/common/src/nimble_port.c \
+  $(PROJ_ROOT)/porting/common/src/mem/mem.c \
+  $(PROJ_ROOT)/porting/common/src/os/endian.c \
+  $(PROJ_ROOT)/porting/common/src/os/os_cputime.c \
+  $(PROJ_ROOT)/porting/common/src/os/os_cputime_pwr2.c \
+  $(PROJ_ROOT)/porting/common/src/os/os_mbuf.c \
+  $(PROJ_ROOT)/porting/common/src/os/os_mempool.c \
+  $(PROJ_ROOT)/porting/common/src/os/os_msys_init.c \
+  $(PROJ_ROOT)/porting/common/src/sysinit/sysinit.c \
+  $(PROJ_ROOT)/nimble/src/ble_util.c \
+  $(PROJ_ROOT)/nimble/src/hci_common.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_att_clt.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_att_cmd.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_att.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_att_svr.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_eddystone.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_gap.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_gattc.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_gatts_lcl.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_gatts.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_hs_adv.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_hs_atomic.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_hs_cfg.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_hs_conn.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_hs_dbg.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_hs_hci_cmd.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_hs_hci_evt.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_hs_hci.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_hs_hci_util.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_hs_id.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_hs_log.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_hs_mbuf.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_hs_misc.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_hs.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_hs_pvcy.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_hs_startup.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_ibeacon.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_l2cap_coc.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_l2cap.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_l2cap_sig_cmd.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_l2cap_sig.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_monitor.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_sm_alg.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_sm_cmd.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_sm_lgcy.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_sm.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_sm_sc.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_store.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_store_util.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_uuid.c \
+  $(PROJ_ROOT)/nimble/host/src/ble_uuid.c \
+  $(PROJ_ROOT)/nimble/host/services/ans/src/ble_svc_ans.c \
+  $(PROJ_ROOT)/nimble/host/services/gap/src/ble_svc_gap.c \
+  $(PROJ_ROOT)/nimble/host/services/gatt/src/ble_svc_gatt.c \
+  $(PROJ_ROOT)/nimble/host/services/ias/src/ble_svc_ias.c \
+  $(PROJ_ROOT)/nimble/host/services/lls/src/ble_svc_lls.c \
+  $(PROJ_ROOT)/nimble/host/services/tps/src/ble_svc_tps.c \
+  $(PROJ_ROOT)/nimble/host/store/ram/src/ble_store_ram.c \
+  $(PROJ_ROOT)/nimble/controller/src/ble_ll_sched.c \
+  $(PROJ_ROOT)/nimble/controller/src/ble_ll_xcvr.c \
+  $(PROJ_ROOT)/nimble/controller/src/ble_ll_whitelist.c \
+  $(PROJ_ROOT)/nimble/controller/src/ble_ll_ctrl.c \
+  $(PROJ_ROOT)/nimble/controller/src/ble_ll_hci.c \
+  $(PROJ_ROOT)/nimble/controller/src/ble_ll_supp_cmd.c \
+  $(PROJ_ROOT)/nimble/controller/src/ble_ll_adv.c \
+  $(PROJ_ROOT)/nimble/controller/src/ble_ll_conn.c \
+  $(PROJ_ROOT)/nimble/controller/src/ble_ll_resolv.c \
+  $(PROJ_ROOT)/nimble/controller/src/ble_ll_conn_hci.c \
+  $(PROJ_ROOT)/nimble/controller/src/ble_ll_rand.c \
+  $(PROJ_ROOT)/nimble/controller/src/ble_ll.c \
+  $(PROJ_ROOT)/nimble/controller/src/ble_ll_scan.c \
+  $(PROJ_ROOT)/nimble/controller/src/ble_ll_hci_ev.c \
+  $(PROJ_ROOT)/nimble/transport/ram/src/ble_hci_ram.c \
+  $(PROJ_ROOT)/nimble/drivers/nrf52/src/ble_hw.c \
+  $(PROJ_ROOT)/nimble/drivers/nrf52/src/ble_phy.c \
+  $(PROJ_ROOT)/tinycrypt/src/aes_decrypt.c \
+  $(PROJ_ROOT)/tinycrypt/src/aes_encrypt.c \
+  $(PROJ_ROOT)/tinycrypt/src/cmac_mode.c \
+  $(PROJ_ROOT)/tinycrypt/src/ecc.c \
+  $(PROJ_ROOT)/tinycrypt/src/ecc_dh.c \
+  $(PROJ_ROOT)/tinycrypt/src/utils.c \
+
+# Include folders common to all targets
+INC_FOLDERS += \
+  ./config \
+  $(NRF5_SDK_ROOT)/components \
+  $(NRF5_SDK_ROOT)/components/toolchain/cmsis/include \
+  $(NRF5_SDK_ROOT)/external/freertos/source/include \
+  $(NRF5_SDK_ROOT)/external/freertos/config \
+  $(NRF5_SDK_ROOT)/components/libraries/util \
+  $(NRF5_SDK_ROOT)/components/drivers_nrf/uart \
+  $(NRF5_SDK_ROOT)/components/libraries/bsp \
+  $(NRF5_SDK_ROOT)/components/device \
+  $(NRF5_SDK_ROOT)/components/libraries/log \
+  $(NRF5_SDK_ROOT)/components/libraries/button \
+  $(NRF5_SDK_ROOT)/components/libraries/timer \
+  $(NRF5_SDK_ROOT)/external/freertos/portable/CMSIS/nrf52 \
+  $(NRF5_SDK_ROOT)/components/drivers_nrf/gpiote \
+  $(NRF5_SDK_ROOT)/external/segger_rtt \
+  $(NRF5_SDK_ROOT)/components/drivers_nrf/nrf_soc_nosd \
+  $(NRF5_SDK_ROOT)/components/boards \
+  $(NRF5_SDK_ROOT)/components/drivers_nrf/hal \
+  $(NRF5_SDK_ROOT)/components/toolchain/gcc \
+  $(NRF5_SDK_ROOT)/components/toolchain \
+  $(NRF5_SDK_ROOT)/components/drivers_nrf/common \
+  $(NRF5_SDK_ROOT)/components/drivers_nrf/clock \
+  $(NRF5_SDK_ROOT)/external/freertos/portable/GCC/nrf52 \
+  $(NRF5_SDK_ROOT)/components/libraries/log/src \
+  ./include \
+  $(PROJ_ROOT)/porting/common/include \
+  $(PROJ_ROOT)/nimble/include \
+  $(PROJ_ROOT)/nimble/host/include \
+  $(PROJ_ROOT)/nimble/host/mesh/include \
+  $(PROJ_ROOT)/nimble/host/services/ans/include \
+  $(PROJ_ROOT)/nimble/host/services/gap/include \
+  $(PROJ_ROOT)/nimble/host/services/gatt/include \
+  $(PROJ_ROOT)/nimble/host/services/ias/include \
+  $(PROJ_ROOT)/nimble/host/services/lls/include \
+  $(PROJ_ROOT)/nimble/host/services/tps/include \
+  $(PROJ_ROOT)/nimble/host/store/ram/include \
+  $(PROJ_ROOT)/nimble/controller/include \
+  $(PROJ_ROOT)/nimble/transport/ram/include \
+  $(PROJ_ROOT)/nimble/drivers/nrf52/include \
+  $(PROJ_ROOT)/tinycrypt/include \
+
+# Libraries common to all targets
+LIB_FILES += \
+
+# C flags common to all targets
+CFLAGS += -DNRF52_PAN_12
+CFLAGS += -DNRF52_PAN_15
+CFLAGS += -DNRF52_PAN_58
+CFLAGS += -DFREERTOS
+CFLAGS += -DNRF52_PAN_20
+CFLAGS += -DNRF52_PAN_54
+CFLAGS += -DNRF52
+CFLAGS += -DNRF52_PAN_51
+CFLAGS += -DNRF52_PAN_36
+CFLAGS += -DCONFIG_GPIO_AS_PINRESET
+CFLAGS += -DNRF52_PAN_64
+CFLAGS += -DNRF52_PAN_55
+CFLAGS += -DBOARD_PCA10040
+CFLAGS += -DNRF52_PAN_31
+CFLAGS += -DNRF52832
+CFLAGS += -mcpu=cortex-m4
+CFLAGS += -mthumb -mabi=aapcs
+CFLAGS +=  -Wall -Werror -Og -g3
+CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
+# keep every function in separate section, this allows linker to discard unused ones
+CFLAGS += -ffunction-sections -fdata-sections -fno-strict-aliasing
+CFLAGS += -fno-builtin --short-enums 
+
+# C++ flags common to all targets
+CXXFLAGS += \
+
+# Assembler flags common to all targets
+ASMFLAGS += -x assembler-with-cpp
+ASMFLAGS += -DNRF52_PAN_12
+ASMFLAGS += -DNRF52_PAN_15
+ASMFLAGS += -DNRF52_PAN_58
+ASMFLAGS += -DFREERTOS
+ASMFLAGS += -DNRF52_PAN_20
+ASMFLAGS += -DNRF52_PAN_54
+ASMFLAGS += -DNRF52
+ASMFLAGS += -DNRF52_PAN_51
+ASMFLAGS += -DNRF52_PAN_36
+ASMFLAGS += -DCONFIG_GPIO_AS_PINRESET
+ASMFLAGS += -DNRF52_PAN_64
+ASMFLAGS += -DNRF52_PAN_55
+ASMFLAGS += -DBOARD_PCA10040
+ASMFLAGS += -DNRF52_PAN_31
+ASMFLAGS += -DNRF52832
+
+# Linker flags
+LDFLAGS += -mthumb -mabi=aapcs -L $(TEMPLATE_PATH) -T$(LINKER_SCRIPT)
+LDFLAGS += -mcpu=cortex-m4
+LDFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
+# let linker to dump unused sections
+LDFLAGS += -Wl,--gc-sections
+# use newlib in nano version
+LDFLAGS += --specs=nano.specs -lc -lnosys
+
+
+.PHONY: $(TARGETS) default all clean help flash 
+
+# Default target - first one defined
+default: nrf52832_xxaa
+
+# Print all targets that can be built
+help:
+	@echo following targets are available:
+	@echo 	nrf52832_xxaa
+
+TEMPLATE_PATH := $(NRF5_SDK_ROOT)/components/toolchain/gcc
+
+include $(TEMPLATE_PATH)/Makefile.common
+
+$(foreach target, $(TARGETS), $(call define_target, $(target)))
+
+# Flash the program
+flash: $(OUTPUT_DIRECTORY)/nrf52832_xxaa.hex
+	@echo Flashing: $<
+	nrfjprog --program $< -f nrf52 --sectorerase
+	nrfjprog --reset -f nrf52
+
+erase:
+	nrfjprog --eraseall -f nrf52
diff --git a/porting/freertos_nrf5_sdk/config/FreeRTOSConfig.h b/porting/freertos_nrf5_sdk/config/FreeRTOSConfig.h
new file mode 100644
index 0000000..7569484
--- /dev/null
+++ b/porting/freertos_nrf5_sdk/config/FreeRTOSConfig.h
@@ -0,0 +1,229 @@
+/*
+    FreeRTOS V8.0.1 - Copyright (C) 2014 Real Time Engineers Ltd.
+    All rights reserved
+
+    VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+    ***************************************************************************
+     *                                                                       *
+     *    FreeRTOS provides completely free yet professionally developed,    *
+     *    robust, strictly quality controlled, supported, and cross          *
+     *    platform software that has become a de facto standard.             *
+     *                                                                       *
+     *    Help yourself get started quickly and support the FreeRTOS         *
+     *    project by purchasing a FreeRTOS tutorial book, reference          *
+     *    manual, or both from: http://www.FreeRTOS.org/Documentation        *
+     *                                                                       *
+     *    Thank you!                                                         *
+     *                                                                       *
+    ***************************************************************************
+
+    This file is part of the FreeRTOS distribution.
+
+    FreeRTOS is free software; you can redistribute it and/or modify it under
+    the terms of the GNU General Public License (version 2) as published by the
+    Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+    >>!   NOTE: The modification to the GPL is included to allow you to     !<<
+    >>!   distribute a combined work that includes FreeRTOS without being   !<<
+    >>!   obliged to provide the source code for proprietary components     !<<
+    >>!   outside of the FreeRTOS kernel.                                   !<<
+
+    FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+    FOR A PARTICULAR PURPOSE.  Full license text is available from the following
+    link: http://www.freertos.org/a00114.html
+
+    1 tab == 4 spaces!
+
+    ***************************************************************************
+     *                                                                       *
+     *    Having a problem?  Start by reading the FAQ "My application does   *
+     *    not run, what could be wrong?"                                     *
+     *                                                                       *
+     *    http://www.FreeRTOS.org/FAQHelp.html                               *
+     *                                                                       *
+    ***************************************************************************
+
+    http://www.FreeRTOS.org - Documentation, books, training, latest versions,
+    license and Real Time Engineers Ltd. contact details.
+
+    http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+    including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+    compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+    http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
+    Integrity Systems to sell under the OpenRTOS brand.  Low cost OpenRTOS
+    licenses offer ticketed support, indemnification and middleware.
+
+    http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+    engineered and independently SIL3 certified version for use in safety and
+    mission critical applications that require provable dependability.
+
+    1 tab == 4 spaces!
+*/
+
+
+#ifndef FREERTOS_CONFIG_H
+#define FREERTOS_CONFIG_H
+
+#ifdef SOFTDEVICE_PRESENT
+#include "nrf_soc.h"
+#endif
+
+/*-----------------------------------------------------------
+ * Possible configurations for system timer
+ */
+#define FREERTOS_USE_RTC      0 /**< Use real time clock for the system */
+#define FREERTOS_USE_SYSTICK  1 /**< Use SysTick timer for system */
+
+/*-----------------------------------------------------------
+ * Application specific definitions.
+ *
+ * These definitions should be adjusted for your particular hardware and
+ * application requirements.
+ *
+ * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
+ * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
+ *
+ * See http://www.freertos.org/a00110.html.
+ *----------------------------------------------------------*/
+
+#define configTICK_SOURCE FREERTOS_USE_RTC
+
+#define configUSE_PREEMPTION 1
+#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
+#define configUSE_TICKLESS_IDLE 1
+#define configUSE_TICKLESS_IDLE_SIMPLE_DEBUG                                      1 /* See into vPortSuppressTicksAndSleep source code for explanation */
+#define configCPU_CLOCK_HZ                                                        ( SystemCoreClock )
+#define configTICK_RATE_HZ                                                        1000
+#define configMAX_PRIORITIES                                                      ( 3 )
+#define configMINIMAL_STACK_SIZE                                                  ( 60 )
+#define configTOTAL_HEAP_SIZE                                                     ( 6144 )
+#define configMAX_TASK_NAME_LEN                                                   ( 4 )
+#define configUSE_16_BIT_TICKS                                                    0
+#define configIDLE_SHOULD_YIELD                                                   1
+#define configUSE_MUTEXES                                                         1
+#define configUSE_RECURSIVE_MUTEXES                                               1
+#define configUSE_COUNTING_SEMAPHORES                                             1
+#define configUSE_ALTERNATIVE_API                                                 0    /* Deprecated! */
+#define configQUEUE_REGISTRY_SIZE                                                 2
+#define configUSE_QUEUE_SETS                                                      0
+#define configUSE_TIME_SLICING                                                    0
+#define configUSE_NEWLIB_REENTRANT                                                0
+#define configENABLE_BACKWARD_COMPATIBILITY                                       1
+
+/* Hook function related definitions. */
+#define configUSE_IDLE_HOOK                                                       0
+#define configUSE_TICK_HOOK                                                       0
+#define configCHECK_FOR_STACK_OVERFLOW                                            0
+#define configUSE_MALLOC_FAILED_HOOK                                              0
+
+/* Run time and task stats gathering related definitions. */
+#define configGENERATE_RUN_TIME_STATS                                             0
+#define configUSE_TRACE_FACILITY                                                  0
+#define configUSE_STATS_FORMATTING_FUNCTIONS                                      0
+
+/* Co-routine definitions. */
+#define configUSE_CO_ROUTINES                                                     0
+#define configMAX_CO_ROUTINE_PRIORITIES                                           ( 2 )
+
+/* Software timer definitions. */
+#define configUSE_TIMERS 1
+#define configTIMER_TASK_PRIORITY                                                 ( 2 )
+#define configTIMER_QUEUE_LENGTH                                                  32
+#define configTIMER_TASK_STACK_DEPTH                                              ( 80 )
+
+/* Tickless Idle configuration. */
+#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP                                     2
+
+/* Tickless idle/low power functionality. */
+
+
+/* Define to trap errors during development. */
+#if defined(DEBUG_NRF) || defined(DEBUG_NRF_USER)
+#define configASSERT( x )                                                         ASSERT(x)
+#endif
+
+/* FreeRTOS MPU specific definitions. */
+#define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS                    1
+
+/* Optional functions - most linkers will remove unused functions anyway. */
+#define INCLUDE_vTaskPrioritySet                                                  1
+#define INCLUDE_uxTaskPriorityGet                                                 1
+#define INCLUDE_vTaskDelete                                                       1
+#define INCLUDE_vTaskSuspend                                                      1
+#define INCLUDE_xResumeFromISR                                                    1
+#define INCLUDE_vTaskDelayUntil                                                   1
+#define INCLUDE_vTaskDelay                                                        1
+#define INCLUDE_xTaskGetSchedulerState                                            1
+#define INCLUDE_xTaskGetCurrentTaskHandle                                         1
+#define INCLUDE_uxTaskGetStackHighWaterMark                                       1
+#define INCLUDE_xTaskGetIdleTaskHandle                                            1
+#define INCLUDE_xTimerGetTimerDaemonTaskHandle                                    1
+#define INCLUDE_pcTaskGetTaskName                                                 1
+#define INCLUDE_eTaskGetState                                                     1
+#define INCLUDE_xEventGroupSetBitFromISR                                          1
+#define INCLUDE_xTimerPendFunctionCall                                            1
+
+/* The lowest interrupt priority that can be used in a call to a "set priority"
+function. */
+#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY         0xf
+
+/* The highest interrupt priority that can be used by any interrupt service
+routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL
+INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
+PRIORITY THAN THIS! (higher priorities are lower numeric values. */
+#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY    1
+
+/* Interrupt priorities used by the kernel port layer itself.  These are generic
+to all Cortex-M ports, and do not rely on any particular library functions. */
+#define configKERNEL_INTERRUPT_PRIORITY                 configLIBRARY_LOWEST_INTERRUPT_PRIORITY
+/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
+See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
+#define configMAX_SYSCALL_INTERRUPT_PRIORITY            configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
+
+/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
+standard names - or at least those used in the unmodified vector table. */
+
+#define vPortSVCHandler                                                           SVC_Handler
+#define xPortPendSVHandler                                                        PendSV_Handler
... 3734 lines suppressed ...

-- 
To stop receiving notification emails like this one, please contact
"commits@mynewt.apache.org" <co...@mynewt.apache.org>.