initial commit of tadpole repository
diff --git a/compiler/sim/compiler.yml b/compiler/sim/compiler.yml
new file mode 100644
index 0000000..b3eb903
--- /dev/null
+++ b/compiler/sim/compiler.yml
@@ -0,0 +1,30 @@
+#
+# Copyright (c) 2015 Runtime Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+############################# Compiler Variables #############################
+
+compiler.path.cc: "/usr/local/bin/gcc-5" 
+compiler.path.archive: "ar"
+compiler.path.objdump: "gobjdump"
+compiler.path.objsize: "objsize"
+
+compiler.flags.base: >
+    -m32 -Wall -Werror -ggdb -O0
+
+compiler.flags.default: [compiler.flags.base]
+compiler.flags.debug: [compiler.flags.base, -ggdb -O0]
+
+compiler.ld.mapfile: false
diff --git a/hw/bsp/native/LICENSE b/hw/bsp/native/LICENSE
new file mode 100644
index 0000000..8f71f43
--- /dev/null
+++ b/hw/bsp/native/LICENSE
@@ -0,0 +1,202 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
diff --git a/hw/bsp/native/README.md b/hw/bsp/native/README.md
new file mode 100644
index 0000000..67071c5
--- /dev/null
+++ b/hw/bsp/native/README.md
@@ -0,0 +1,3 @@
+# ffs
+
+
diff --git a/hw/bsp/native/pkg.yml b/hw/bsp/native/pkg.yml
new file mode 100644
index 0000000..ab0b494
--- /dev/null
+++ b/hw/bsp/native/pkg.yml
@@ -0,0 +1,3 @@
+pkg.name: "hw/bsp/native"
+pkg.deps: 
+    - hw/mcu/native
diff --git a/hw/hal/README.MD b/hw/hal/README.MD
new file mode 100644
index 0000000..783c182
--- /dev/null
+++ b/hw/hal/README.MD
@@ -0,0 +1 @@
+# hal
diff --git a/hw/hal/include/hal/hal_cputime.h b/hw/hal/include/hal/hal_cputime.h
new file mode 100644
index 0000000..286736c
--- /dev/null
+++ b/hw/hal/include/hal/hal_cputime.h
@@ -0,0 +1,184 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef H_HAL_CPUTIME_
+#define H_HAL_CPUTIME_
+
+#include "os/queue.h"
+
+/* CPU timer callback function */
+struct cpu_timer;
+typedef void (*cputimer_func)(void *arg);
+
+/* CPU timer */
+struct cpu_timer
+{
+    cputimer_func   cb;
+    void            *arg;
+    uint32_t        cputime;
+    TAILQ_ENTRY(cpu_timer) link;
+};
+
+/**
+ * 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 cputime_init(uint32_t clock_freq);
+
+/**
+ * cputime get64
+ *  
+ * Returns cputime as a 64-bit number. 
+ * 
+ * @return uint64_t The 64-bit representation of cputime.
+ */
+uint64_t cputime_get64(void);
+
+/**
+ * cputime get32 
+ *  
+ * Returns the low 32 bits of cputime. 
+ * 
+ * @return uint32_t The lower 32 bits of cputime
+ */
+uint32_t cputime_get32(void);
+
+/**
+ * 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 cputime_nsecs_to_ticks(uint32_t nsecs);
+
+/**
+ * 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 cputime_ticks_to_nsecs(uint32_t ticks);
+
+/**
+ * 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 cputime_usecs_to_ticks(uint32_t usecs);
+
+/**
+ * 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 cputime_ticks_to_usecs(uint32_t ticks);
+
+/**
+ * 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 cputime_delay_ticks(uint32_t ticks);
+
+/**
+ * cputime delay nsecs 
+ *  
+ * Wait until 'nsecs' nanoseconds has elapsed. This is a blocking delay. 
+ *  
+ * @param nsecs The number of nanoseconds to wait.
+ */
+void cputime_delay_nsecs(uint32_t nsecs);
+
+/**
+ * cputime delay usecs 
+ *  
+ * Wait until 'usecs' microseconds has elapsed. This is a blocking delay. 
+ *  
+ * @param usecs The number of usecs to wait.
+ */
+void cputime_delay_usecs(uint32_t usecs);
+
+/**
+ * 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 cputime_timer_init(struct cpu_timer *timer, cputimer_func fp, void *arg);
+
+/**
+ * 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). 
+ * 
+ * @param timer     Pointer to timer to start. Cannot be NULL.
+ * @param cputime   The cputime at which the timer should expire.
+ */
+void cputime_timer_start(struct cpu_timer *timer, uint32_t cputime);
+
+/**
+ * cputimer timer relative 
+ *  
+ * Sets a cpu timer that will expire 'usecs' microseconds from the current 
+ * cputime. 
+ * 
+ * @param timer Pointer to timer. Cannot be NULL.
+ * @param usecs The number of usecs from now at which the timer will expire.
+ */
+void cputime_timer_relative(struct cpu_timer *timer, uint32_t usecs);
+
+/**
+ * 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 running. 
+ * 
+ * @param timer Pointer to cputimer to stop. Cannot be NULL.
+ */
+void cputime_timer_stop(struct cpu_timer *timer);
+
+#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)
+
+#endif /* H_HAL_CPUTIMER_ */
diff --git a/hw/hal/include/hal/hal_flash.h b/hw/hal/include/hal/hal_flash.h
new file mode 100644
index 0000000..98813d1
--- /dev/null
+++ b/hw/hal/include/hal/hal_flash.h
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef H_HAL_FLASH_
+#define H_HAL_FLASH_
+
+#include <inttypes.h>
+
+int flash_read(uint32_t address, void *dst, uint32_t num_bytes);
+int flash_write(uint32_t address, const void *src, uint32_t num_bytes);
+int flash_erase_sector(uint32_t sector_address);
+int flash_erase(uint32_t address, uint32_t num_bytes);
+int flash_init(void);
+
+#endif
+
diff --git a/hw/hal/include/hal/hal_gpio.h b/hw/hal/include/hal/hal_gpio.h
new file mode 100644
index 0000000..4f177b6
--- /dev/null
+++ b/hw/hal/include/hal/hal_gpio.h
@@ -0,0 +1,141 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef H_HAL_GPIO_
+#define H_HAL_GPIO_
+
+/*
+ * The "mode" of the gpio. The gpio is either an input, output, or it is
+ * "not connected" (the pin specified is not functioning as a gpio)
+ */
+enum gpio_mode_e
+{
+    GPIO_MODE_NC = -1,
+    GPIO_MODE_IN = 0,
+    GPIO_MODE_OUT = 1
+};
+typedef enum gpio_mode_e gpio_mode_t;
+
+/*
+ * The "pull" of the gpio. This is either an input or an output.
+ */
+enum gpio_pull
+{
+    GPIO_PULL_NONE = 0,     /* pull-up/down not enabled */
+    GPIO_PULL_UP = 1,       /* pull-up enabled */
+    GPIO_PULL_DOWN = 2      /* pull-down enabled */
+};
+typedef enum gpio_pull gpio_pull_t;
+
+/*
+ * IRQ trigger type. 
+ */
+enum gpio_irq_trigger
+{
+    GPIO_TRIG_NONE = 0,
+    GPIO_TRIG_RISING = 1,   /* IRQ occurs on rising edge */
+    GPIO_TRIG_FALLING = 2,  /* IRQ occurs on falling edge */
+    GPIO_TRIG_BOTH = 3,     /* IRQ occurs on either edge */
+    GPIO_TRIG_LOW = 4,      /* IRQ occurs when line is low */
+    GPIO_TRIG_HIGH = 5      /* IRQ occurs when line is high */
+};
+typedef enum gpio_irq_trigger gpio_irq_trig_t;
+
+/* Function proto for GPIO irq handler functions */
+typedef void (*gpio_irq_handler_t)(void *arg);
+
+/**
+ * gpio init in 
+ *  
+ * Initializes the specified pin as an input 
+ * 
+ * @param pin   Pin number to set as input
+ * @param pull  pull type
+ * 
+ * @return int  0: no error; -1 otherwise. 
+ */
+int gpio_init_in(int pin, gpio_pull_t pull);
+
+/**
+ * gpio init out 
+ *  
+ * Initialize the specified pin as an output, setting the pin to the specified 
+ * value. 
+ * 
+ * @param pin Pin number to set as output
+ * @param val Value to set pin
+ * 
+ * @return int  0: no error; -1 otherwise. 
+ */
+int gpio_init_out(int pin, int val);
+
+/**
+ * gpio set 
+ *  
+ * Sets specified pin to 1 (high) 
+ * 
+ * @param pin 
+ */
+void gpio_set(int pin);
+
+/**
+ * gpio clear
+ *  
+ * Sets specified pin to 0 (low). 
+ * 
+ * @param pin 
+ */
+void gpio_clear(int pin);
+
+/**
+ * gpio write 
+ *  
+ * Write a value (either high or low) to the specified pin.
+ * 
+ * @param pin Pin to set
+ * @param val Value to set pin (0:low 1:high)
+ */
+void gpio_write(int pin, int val);
+
+/**
+ * gpio read 
+ *  
+ * Reads the specified pin. 
+ *  
+ *  
+ * @param pin Pin number to read
+ * 
+ * @return int 0: low, 1: high
+ */
+int gpio_read(int pin);
+
+/**
+ * gpio toggle 
+ *  
+ * Toggles the specified pin
+ * 
+ * @param pin Pin number to toggle
+ */
+void gpio_toggle(int pin);
+
+int gpio_irq_init(int pin, gpio_irq_handler_t handler, void *arg,
+                  gpio_irq_trig_t trig, gpio_pull_t pull);
+void gpio_irq_release(int pin);
+void gpio_irq_enable(int pin);
+void gpio_irq_disable(int pin);
+
+
+#endif /* H_HAL_GPIO_ */
diff --git a/hw/hal/include/hal/hal_system.h b/hw/hal/include/hal/hal_system.h
new file mode 100644
index 0000000..3d5569c
--- /dev/null
+++ b/hw/hal/include/hal/hal_system.h
@@ -0,0 +1,22 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef H_HAL_SYSTEM_
+#define H_HAL_SYSTEM_
+
+void system_reset(void);
+
+#endif
diff --git a/hw/hal/pkg.yml b/hw/hal/pkg.yml
new file mode 100644
index 0000000..1166bfe
--- /dev/null
+++ b/hw/hal/pkg.yml
@@ -0,0 +1,3 @@
+pkg.name: hw/hal
+pkg.vers: 0.1 
+pkg.deps: libs/os
diff --git a/hw/mcu/native/pkg.yml b/hw/mcu/native/pkg.yml
new file mode 100644
index 0000000..c3b77a3
--- /dev/null
+++ b/hw/mcu/native/pkg.yml
@@ -0,0 +1,2 @@
+pkg.name: "hw/mcu/native"
+pkg.deps: hw/hal
diff --git a/hw/mcu/native/src/hal_flash.c b/hw/mcu/native/src/hal_flash.c
new file mode 100644
index 0000000..63f3645
--- /dev/null
+++ b/hw/mcu/native/src/hal_flash.c
@@ -0,0 +1,274 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <inttypes.h>
+#include "hal/hal_flash.h"
+
+static FILE *file;
+
+static const struct flash_area_desc {
+    uint32_t fad_offset;
+    uint32_t fad_length;
+    uint32_t fad_sector_id;
+} flash_area_descs[] = {
+    { 0x00000000, 16 * 1024,  0 },
+    { 0x00004000, 16 * 1024,  1 },
+    { 0x00008000, 16 * 1024,  2 },
+    { 0x0000c000, 16 * 1024,  3 },
+    { 0x00010000, 64 * 1024,  4 },
+    { 0x00020000, 128 * 1024, 5 },
+    { 0x00040000, 128 * 1024, 6 },
+    { 0x00060000, 128 * 1024, 7 },
+    { 0x00080000, 128 * 1024, 8 },
+    { 0x000a0000, 128 * 1024, 9 },
+    { 0x000c0000, 128 * 1024, 10 },
+    { 0x000e0000, 128 * 1024, 11 },
+};
+
+#define FLASH_NUM_AREAS   (int)(sizeof flash_area_descs /       \
+                                sizeof flash_area_descs[0])
+
+static void
+flash_native_erase(uint32_t addr, uint32_t len)
+{
+    static uint8_t buf[256];
+    uint32_t end;
+    int chunk_sz;
+    int rc;
+
+    end = addr + len;
+    memset(buf, 0xff, sizeof buf);
+
+    rc = fseek(file, addr, SEEK_SET);
+    assert(rc == 0);
+
+    while (addr < end) {
+        if (end - addr < sizeof buf) {
+            chunk_sz = end - addr;
+        } else {
+            chunk_sz = sizeof buf;
+        }
+        rc = fwrite(buf, chunk_sz, 1, file);
+        assert(rc == 1);
+
+        addr += chunk_sz;
+    }
+    fflush(file);
+}
+
+static void
+flash_native_ensure_file_open(void)
+{
+    int expected_sz;
+    int i;
+
+    if (file == NULL) {
+        expected_sz = 0;
+        for (i = 0; i < FLASH_NUM_AREAS; i++) {
+            expected_sz += flash_area_descs[i].fad_length;
+        }
+
+        file = tmpfile();
+        assert(file != NULL);
+        flash_native_erase(0, expected_sz);
+    }
+}
+
+static int
+flash_native_write_internal(uint32_t address, const void *src, uint32_t length,
+                            int allow_overwrite)
+{
+    static uint8_t buf[256];
+    uint32_t cur;
+    uint32_t end;
+    int chunk_sz;
+    int rc;
+    int i;
+
+    if (length == 0) {
+        return 0;
+    }
+
+    end = address + length;
+
+    flash_native_ensure_file_open();
+
+    fseek(file, address, SEEK_SET);
+
+    cur = address;
+    while (cur < end) {
+        if (end - cur < sizeof buf) {
+            chunk_sz = end - cur;
+        } else {
+            chunk_sz = sizeof buf;
+        }
+
+        /* Ensure data is not being overwritten. */
+        if (!allow_overwrite) {
+            rc = flash_read(cur, buf, chunk_sz);
+            assert(rc == 0);
+            for (i = 0; i < chunk_sz; i++) {
+                assert(buf[i] == 0xff);
+            }
+        }
+
+        cur += chunk_sz;
+    }
+
+    fseek(file, address, SEEK_SET);
+    rc = fwrite(src, length, 1, file);
+    assert(rc == 1);
+
+    fflush(file);
+    return 0;
+}
+
+int
+flash_write(uint32_t address, const void *src, uint32_t length)
+{
+    return flash_native_write_internal(address, src, length, 0);
+}
+
+int
+flash_native_overwrite(uint32_t address, const void *src, uint32_t length)
+{
+    return flash_native_write_internal(address, src, length, 1);
+}
+
+int
+flash_native_memset(uint32_t offset, uint8_t c, uint32_t len)
+{
+    uint8_t buf[256];
+    int chunk_sz;
+    int rc;
+
+    memset(buf, c, sizeof buf);
+
+    while (len > 0) {
+        if (len > sizeof buf) {
+            chunk_sz = sizeof buf;
+        } else {
+            chunk_sz = len;
+        }
+
+        rc = flash_native_overwrite(offset, buf, chunk_sz);
+        if (rc != 0) {
+            return rc;
+        }
+
+        offset += chunk_sz;
+        len -= chunk_sz;
+    }
+
+    return 0;
+}
+
+int
+flash_read(uint32_t address, void *dst, uint32_t length)
+{
+    flash_native_ensure_file_open();
+    fseek(file, address, SEEK_SET);
+    fread(dst, length, 1, file);
+
+    return 0;
+}
+
+static int
+find_area(uint32_t address)
+{
+    int i;
+
+    for (i = 0; i < FLASH_NUM_AREAS; i++) {
+        if (flash_area_descs[i].fad_offset == address) {
+            return i;
+        }
+    }
+
+    return -1;
+}
+
+int
+flash_erase_sector(uint32_t sector_address)
+{
+    int next_sector_id;
+    int sector_id;
+    int area_id;
+
+    flash_native_ensure_file_open();
+
+    area_id = find_area(sector_address);
+    if (area_id == -1) {
+        return -1;
+    }
+
+    sector_id = flash_area_descs[area_id].fad_sector_id;
+    while (1) {
+        flash_native_erase(sector_address,
+                           flash_area_descs[area_id].fad_length);
+
+        area_id++;
+        if (area_id >= FLASH_NUM_AREAS) {
+            break;
+        }
+
+        next_sector_id = flash_area_descs[area_id].fad_sector_id;
+        if (next_sector_id != sector_id) {
+            break;
+        }
+
+        sector_id = next_sector_id;
+    }
+
+    return 0;
+}
+
+int
+flash_erase(uint32_t address, uint32_t num_bytes)
+{
+    const struct flash_area_desc *area;
+    uint32_t end;
+    int i;
+
+    flash_native_ensure_file_open();
+
+    end = address + num_bytes;
+
+    for (i = 0; i < FLASH_NUM_AREAS; i++) {
+        area = flash_area_descs + i;
+
+        if (area->fad_offset >= end) {
+            return 0;
+        }
+
+        if (address >= area->fad_offset &&
+            address < area->fad_offset + area->fad_length) {
+
+            flash_native_erase(area->fad_offset, area->fad_length);
+        }
+    }
+
+    return 0;
+}
+
+int
+flash_init(void)
+{
+    return 0;
+}
+
diff --git a/hw/mcu/native/src/hal_system.c b/hw/mcu/native/src/hal_system.c
new file mode 100644
index 0000000..00a981e
--- /dev/null
+++ b/hw/mcu/native/src/hal_system.c
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "hal/hal_system.h"
+
+void
+system_reset(void)
+{ }
diff --git a/libs/os/.gitignore b/libs/os/.gitignore
new file mode 100644
index 0000000..1da1f50
--- /dev/null
+++ b/libs/os/.gitignore
@@ -0,0 +1,3 @@
+bin
+obj
+*.swp
diff --git a/libs/os/LICENSE b/libs/os/LICENSE
new file mode 100644
index 0000000..8f71f43
--- /dev/null
+++ b/libs/os/LICENSE
@@ -0,0 +1,202 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
diff --git a/libs/os/README.md b/libs/os/README.md
new file mode 100644
index 0000000..b9a0f1e
--- /dev/null
+++ b/libs/os/README.md
@@ -0,0 +1,3 @@
+# Stack OS 
+
+This is documentation on stack OS 
diff --git a/libs/os/include/os/arch/arm/os/os_arch.h b/libs/os/include/os/arch/arm/os/os_arch.h
new file mode 100755
index 0000000..0917dec
--- /dev/null
+++ b/libs/os/include/os/arch/arm/os/os_arch.h
@@ -0,0 +1,75 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _OS_ARCH_ARM_H 
+#define _OS_ARCH_ARM_H 
+
+#include <stdint.h>
+
+struct os_task;
+
+/* Run in priviliged or unprivileged Thread mode */
+#define OS_RUN_UNPRIV       (0)
+#define OS_RUN_PRIV         (1)
+
+/* Time tick in miliseconds that the OS runs */
+#define OS_TIME_TICK        (1)
+#define OS_TICKS_PER_SEC    (OS_TIME_TICK * 1000)
+
+/* CPU status register */
+typedef uint32_t os_sr_t;
+/* Stack type, aligned to a 32-bit word. */
+#define OS_STACK_PATTERN    (0xdeadbeef)
+
+typedef uint32_t os_stack_t;
+#define OS_ALIGNMENT        (4) 
+#define OS_STACK_ALIGNMENT  (8)
+
+#define OS_STACK_ALIGN(__nmemb) \
+    (OS_ALIGN((__nmemb), OS_STACK_ALIGNMENT))
+
+/* Enter a critical section, save processor state, and block interrupts */
+#define OS_ENTER_CRITICAL(__os_sr) (__os_sr = os_arch_save_sr()) 
+/* Exit a critical section, restore processor state and unblock interrupts */
+#define OS_EXIT_CRITICAL(__os_sr) (os_arch_restore_sr(__os_sr))
+
+/* Define special stackos sections */
+#define sec_data_core   __attribute__((section(".data.core")))
+#define sec_bss_core    __attribute__((section(".bss.core")))
+#define sec_bss_nz_core __attribute__((section(".bss.core.nz")))
+
+/* Define "assert" funtion */
+void _Die(char *file, int line);
+
+os_stack_t *os_arch_task_stack_init(struct os_task *, os_stack_t *, int);
+void timer_handler(void);
+void os_arch_ctx_sw(struct os_task *);
+void os_arch_ctx_sw_isr(struct os_task *);
+os_sr_t os_arch_save_sr(void);
+void os_arch_restore_sr(os_sr_t);
+void os_arch_init(void);
+uint32_t os_arch_start(void);
+os_error_t os_arch_os_init(void);
+os_error_t os_arch_os_start(void);
+void os_set_env(void);
+void os_arch_init_task_stack(os_stack_t *sf);
+
+/* External function prototypes supplied by BSP */
+void os_bsp_systick_init(uint32_t os_tick_usecs);
+void os_bsp_init(void);
+void os_bsp_ctx_sw(void);
+
+#endif /* _OS_ARCH_X86_H */ 
diff --git a/libs/os/include/os/arch/sim/os/os_arch.h b/libs/os/include/os/arch/sim/os/os_arch.h
new file mode 100644
index 0000000..c9c7da9
--- /dev/null
+++ b/libs/os/include/os/arch/sim/os/os_arch.h
@@ -0,0 +1,59 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _OS_ARCH_SIM_H 
+#define _OS_ARCH_SIM_H 
+
+struct os_task;
+
+/* Time tick in miliseconds that the OS runs */
+
+#define OS_TIME_TICK (1)
+#define OS_TICKS_PER_SEC (OS_TIME_TICK * 1000)
+
+/* CPU status register */
+typedef unsigned int os_sr_t;
+/* Stack type, aligned to a 32-bit word. */
+#define OS_STACK_PATTERN (0xdeadbeef)
+
+typedef unsigned int os_stack_t;
+#define OS_ALIGNMENT (4) 
+#define OS_STACK_ALIGNMENT (16)
+
+#define OS_STACK_ALIGN(__nmemb) \
+    (OS_ALIGN((__nmemb), OS_STACK_ALIGNMENT))
+
+/* Enter a critical section, save processor state, and block interrupts */
+#define OS_ENTER_CRITICAL(__os_sr) (__os_sr = os_arch_save_sr()) 
+/* Exit a critical section, restore processor state and unblock interrupts */
+#define OS_EXIT_CRITICAL(__os_sr) (os_arch_restore_sr(__os_sr))
+
+/* Define special stackos sections */
+#define sec_data_core 
+#define sec_bss_core 
+#define sec_bss_nz_core 
+
+void _Die(char *file, int line);
+
+os_stack_t *os_arch_task_stack_init(struct os_task *, os_stack_t *, int);
+void os_arch_ctx_sw(struct os_task *);
+void os_arch_ctx_sw_isr(struct os_task *);
+os_sr_t os_arch_save_sr(void);
+void os_arch_restore_sr(int);
+os_error_t os_arch_os_init(void);
+os_error_t os_arch_os_start(void);
+
+#endif /* _OS_ARCH_SIM_H */ 
diff --git a/libs/os/include/os/os.h b/libs/os/include/os/os.h
new file mode 100644
index 0000000..d27bb39
--- /dev/null
+++ b/libs/os/include/os/os.h
@@ -0,0 +1,95 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _OS_H
+#define _OS_H 
+
+#include <stdlib.h>
+//#include <stdint.h>
+
+#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))))    \
+        )
+
+
+/** 
+ * Whether or not the operating system has been started.  Set to 
+ * 1 right before first task is run.
+ */
+extern int g_os_started; 
+
+/**
+ * Returns 1 if the OS has been started, 0 if it has not yet been 
+ * been started.
+ */
+int os_started(void);
+
+/* 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,     /* Operating must be started to call this function, but isn't */
+};
+
+#define OS_WAIT_FOREVER (-1) 
+
+typedef enum os_error os_error_t;
+
+#define OS_SANITY_STACK_SIZE (1024) 
+#define OS_SANITY_PRIO (0xfe)
+
+#define OS_IDLE_STACK_SIZE (1024) 
+#define OS_IDLE_PRIO (0xff)
+
+void os_init(void);
+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/os_sanity.h"
+#include "os/os_arch.h"
+#include "os/os_time.h"
+#include "os/os_task.h"
+#include "os/os_sched.h"
+#include "os/os_eventq.h"
+#include "os/os_callout.h" 
+#include "os/os_mutex.h"
+#include "os/os_sem.h"
+#include "os/os_mempool.h"
+#include "os/os_mbuf.h"
+
+#endif /* _OS_H */
diff --git a/libs/os/include/os/os_callout.h b/libs/os/include/os/os_callout.h
new file mode 100644
index 0000000..0fcfc49
--- /dev/null
+++ b/libs/os/include/os/os_callout.h
@@ -0,0 +1,61 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef _OS_CALLOUT_H 
+#define _OS_CALLOUT_H 
+
+#define OS_CALLOUT_F_QUEUED (0x01) 
+#define OS_CALLOUT_QUEUED(__c) ((__c)->c_flags & OS_CALLOUT_F_QUEUED)
+
+#define OS_CALLOUT_INITIALIZER(__c) { \
+    OS_EVENT_INITIALIZER(&(__c)->c_ev, OS_EVENT_T_TIMER, NULL), \
+    NULL, 0, {0, 0, 0}, 0, { NULL, NULL } \
+} 
+
+struct os_callout {
+    struct os_event c_ev; 
+    struct os_eventq *c_evq;
+    uint8_t c_flags;
+    uint8_t _pad[3];
+    uint32_t c_ticks;
+    TAILQ_ENTRY(os_callout) c_next;
+};
+
+#define OS_CALLOUT_FUNC_INITIALIZER(__c, __func, __arg) { \
+    OS_CALLOUT_INITIALIZER(__c), (__func), (__arg) \
+}
+
+typedef void (*os_callout_func_t)(void *);
+
+struct os_callout_func { 
+    struct os_callout cf_c; 
+    os_callout_func_t cf_func; 
+    void *cf_arg;
+};
+
+void os_callout_init(struct os_callout *);
+void os_callout_stop(struct os_callout *);
+int os_callout_reset(struct os_callout *, int32_t, struct os_eventq *, 
+        void *);
+int os_callout_func_reset(struct os_callout_func *, int32_t, 
+    struct os_eventq *, os_callout_func_t, void *);
+void os_callout_tick(void);
+
+#endif /* _OS_CALLOUT_H */ 
+
+
+
diff --git a/libs/os/include/os/os_cfg.h b/libs/os/include/os/os_cfg.h
new file mode 100644
index 0000000..158a8eb
--- /dev/null
+++ b/libs/os/include/os/os_cfg.h
@@ -0,0 +1,22 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef _OS_CFG_H_
+#define _OS_CFG_H_ 
+
+
+#endif /* _OS_CFG_H_ */
diff --git a/libs/os/include/os/os_eventq.h b/libs/os/include/os/os_eventq.h
new file mode 100644
index 0000000..656844c
--- /dev/null
+++ b/libs/os/include/os/os_eventq.h
@@ -0,0 +1,48 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _OS_EVENTQ_H 
+#define _OS_EVENTQ_H 
+
+struct os_event { 
+    uint8_t ev_queued; 
+    uint8_t ev_type;
+    void *ev_arg;
+    TAILQ_ENTRY(os_event) ev_next; 
+};
+
+#define OS_EVENT_QUEUED(__ev) ((__ev)->ev_queued) 
+
+#define OS_EVENT_INITIALIZER(ev, __type, __arg) { \
+    0, (__type), (__arg), { NULL } \
+}
+
+#define OS_EVENT_T_TIMER (1)
+#define OS_EVENT_T_PERUSER (16) 
+
+struct os_eventq {
+    struct os_task *evq_task;
+    TAILQ_HEAD(, os_event) evq_list;
+};
+
+void os_eventq_init(struct os_eventq *);
+void os_eventq_put2(struct os_eventq *, struct os_event *, int);
+void os_eventq_put(struct os_eventq *, struct os_event *);
+struct os_event *os_eventq_get(struct os_eventq *);
+void os_eventq_remove(struct os_eventq *, struct os_event *);
+
+#endif /* _OS_EVENTQ_H */
+
diff --git a/libs/os/include/os/os_heap.h b/libs/os/include/os/os_heap.h
new file mode 100644
index 0000000..46346e6
--- /dev/null
+++ b/libs/os/include/os/os_heap.h
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef H_OS_HEAP_
+#define H_OS_HEAP_
+
+#include <stddef.h>
+
+void *os_malloc(size_t size);
+void os_free(void *mem);
+void *os_realloc(void *ptr, size_t size);
+
+#endif
+
diff --git a/libs/os/include/os/os_malloc.h b/libs/os/include/os/os_malloc.h
new file mode 100644
index 0000000..f6123d5
--- /dev/null
+++ b/libs/os/include/os/os_malloc.h
@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef H_OS_MALLOC_
+#define H_OS_MALLOC_
+
+#include "os/os_heap.h"
+
+#undef  malloc
+#define malloc  os_malloc
+
+#undef  free
+#define free    os_free
+
+#undef  realloc
+#define realloc  os_realloc
+
+#endif
diff --git a/libs/os/include/os/os_mbuf.h b/libs/os/include/os/os_mbuf.h
new file mode 100644
index 0000000..280b75f
--- /dev/null
+++ b/libs/os/include/os/os_mbuf.h
@@ -0,0 +1,211 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _OS_MBUF_H 
+#define _OS_MBUF_H 
+
+
+/**
+ * A mbuf pool to allocate a mbufs out of.  This contains a pointer to the 
+ * mempool to allocate mbufs out of, along with convenient housekeeping 
+ * information on mbufs in the pool (e.g. length of variable packet header)
+ */
+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 length of the variable portion of the mbuf header
+     */
+    uint16_t omp_hdr_len;
+    /**
+     * The memory pool which to allocate mbufs out of 
+     */
+    struct os_mempool *omp_pool;
+};
+
+
+/**
+ * A packet header structure that preceeds the mbuf packet headers.
+ */
+struct os_mbuf_pkthdr {
+    /**
+     * Overall length of the packet. 
+     */
+    uint32_t omp_len;
+    /**
+     * 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
+     */
+    uint16_t om_flags;
+    /**
+     * Length of data in this buffer 
+     */
+    uint16_t om_len;
+
+    /**
+     * 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];
+};
+
+/*
+ * Mbuf flags: 
+ *  - OS_MBUF_F_PKTHDR: Whether or not this mbuf is a packet header mbuf
+ *  - OS_MBUF_F_USER: The base user defined mbuf flag, start defining your 
+ *    own flags from this flag number.
+ */
+
+#define OS_MBUF_F_PKTHDR (0)
+#define OS_MBUF_F_USER   (OS_MBUF_F_PKTHDR + 1) 
+
+/*
+ * 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_flags & OS_MBUF_F_MASK(OS_MBUF_F_PKTHDR))
+
+
+#define OS_MBUF_PKTHDR(__om) ((struct os_mbuf_pkthdr *) &(__om)->om_databuf[0])
+
+/*
+ * 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)
+
+
+
+
+/**
+ * Returns the end offset of a mbuf buffer 
+ * 
+ * @param __omp 
+ */
+#define OS_MBUF_END_OFF(__omp) ((__omp)->omp_databuf_len)
+
+/**
+ * Returns the start offset of a mbuf buffer
+ */
+#define OS_MBUF_START_OFF(__omp) (0)
+
+
+/*
+ * Called by OS_MBUF_LEADINGSPACE() macro
+ */
+static inline uint16_t 
+_os_mbuf_leadingspace(struct os_mbuf_pool *omp, struct os_mbuf *om)
+{
+    uint16_t startoff;
+    uint16_t leadingspace;
+
+    startoff = 0;
+    if (OS_MBUF_IS_PKTHDR(om)) {
+        startoff = sizeof(struct os_mbuf_pkthdr) + omp->omp_hdr_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(__omp, __om) _os_mbuf_leadingspace(__omp, __om)
+
+/* Called by OS_MBUF_TRAILINGSPACE() macro. */
+static inline uint16_t 
+_os_mbuf_trailingspace(struct os_mbuf_pool *omp, struct os_mbuf *om)
+{
+    return (&om->om_databuf[0] + omp->omp_databuf_len) - om->om_data;
+}
+
+/**
+ * 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(__omp, __om) _os_mbuf_trailingspace(__omp, __om)
+
+
+/* Initialize a mbuf pool */
+int os_mbuf_pool_init(struct os_mbuf_pool *, struct os_mempool *mp, uint16_t, 
+        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);
+/* Duplicate a mbuf from the pool */
+struct os_mbuf *os_mbuf_dup(struct os_mbuf_pool *omp, struct os_mbuf *m);
+
+/* Append data onto a mbuf */
+int os_mbuf_append(struct os_mbuf_pool *omp, struct os_mbuf *m, void *, 
+        uint16_t);
+
+/* Free a mbuf */
+int os_mbuf_free(struct os_mbuf_pool *omp, struct os_mbuf *mb);
+/* Free a mbuf chain */
+int os_mbuf_free_chain(struct os_mbuf_pool *omp, struct os_mbuf *om);
+
+#endif /* _OS_MBUF_H */ 
diff --git a/libs/os/include/os/os_mempool.h b/libs/os/include/os/os_mempool.h
new file mode 100644
index 0000000..789ff8c
--- /dev/null
+++ b/libs/os/include/os/os_mempool.h
@@ -0,0 +1,74 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _OS_MEMPOOL_H_
+#define _OS_MEMPOOL_H_
+
+#include "os/os.h"
+#include "os/queue.h"
+
+/* 
+ * 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 */
+    SLIST_HEAD(,os_memblock);   /* Pointer to list of free blocks */
+    char *name;                 /* Name for memory block */
+};
+
+/* 
+ * 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);
+
+/* 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);
+
+#endif  /* _OS_MEMPOOL_H_ */
diff --git a/libs/os/include/os/os_mutex.h b/libs/os/include/os/os_mutex.h
new file mode 100644
index 0000000..716ba60
--- /dev/null
+++ b/libs/os/include/os/os_mutex.h
@@ -0,0 +1,59 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _OS_MUTEX_H_
+#define _OS_MUTEX_H_
+
+#include "os/os.h"
+#include "os/queue.h"
+
+struct os_mutex
+{
+    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 */
+    SLIST_HEAD(, os_task) mu_head;  /* chain of waiting tasks */
+};
+
+/* 
+  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);
+
+/* Delete a mutex */
+os_error_t os_mutex_delete(struct os_mutex *mu);
+
+#endif  /* _OS_MUTEX_H_ */
diff --git a/libs/os/include/os/os_sanity.h b/libs/os/include/os/os_sanity.h
new file mode 100644
index 0000000..4824c5d
--- /dev/null
+++ b/libs/os/include/os/os_sanity.h
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _OS_SANITY_H
+#define _OS_SANITY_H
+
+#include <stdint.h> 
+
+#include "os/os_time.h"
+#include "os/queue.h" 
+
+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;
+
+}; 
+
+int os_sanity_task_init(void);
+
+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 *);
+
+#endif /* _OS_SANITY_H */
diff --git a/libs/os/include/os/os_sched.h b/libs/os/include/os/os_sched.h
new file mode 100644
index 0000000..ee84f76
--- /dev/null
+++ b/libs/os/include/os/os_sched.h
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _OS_SCHED_H
+#define _OS_SCHED_H
+
+#include "os/os_task.h"
+
+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 *, int);
+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 *);
+void os_sched_resort(struct os_task *);
+
+#endif /* _OS_SCHED_H */
diff --git a/libs/os/include/os/os_sem.h b/libs/os/include/os/os_sem.h
new file mode 100644
index 0000000..73e84ee
--- /dev/null
+++ b/libs/os/include/os/os_sem.h
@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _OS_SEM_H_
+#define _OS_SEM_H_
+
+#include "os/queue.h"
+
+struct os_sem
+{
+    uint16_t    _pad;
+    uint16_t    sem_tokens;             /* # of tokens */
+    SLIST_HEAD(, os_task) sem_head; /* chain of waiting tasks */
+};
+
+/* 
+  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);
+
+/* Delete a semaphore */
+os_error_t os_sem_delete(struct os_sem *sem);
+
+#endif  /* _OS_MUTEX_H_ */
diff --git a/libs/os/include/os/os_task.h b/libs/os/include/os/os_task.h
new file mode 100644
index 0000000..a057f4d
--- /dev/null
+++ b/libs/os/include/os/os_task.h
@@ -0,0 +1,72 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _OS_TASK_H
+#define _OS_TASK_H
+
+#include "os/os.h"
+#include "os/os_sanity.h" 
+#include "os/queue.h"
+
+#ifndef OS_TASK_NAME_SIZE
+#define OS_TASK_NAME_SIZE (36) 
+#endif 
+
+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     (0x0001U)
+#define OS_TASK_FLAG_SEM_WAIT       (0x0002U)
+
+typedef void (*os_task_func_t)(void *);
+
+struct os_task {
+    os_stack_t *t_stackptr;
+    uint16_t t_stacksize;
+    uint16_t t_flags;
+
+    uint8_t t_taskid;
+    uint8_t t_prio;
+    uint8_t t_pad[2];
+
+    char *t_name;
+    os_task_func_t t_func;
+    void *t_arg;
+
+    struct os_mutex *t_mutex;
+
+    struct os_sanity_check t_sanity_check; 
+
+    os_task_state_t t_state;
+    os_time_t t_next_wakeup;
+    
+    /* 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;
+};
+
+int os_task_init(struct os_task *, char *, os_task_func_t, void *, uint8_t,
+        os_time_t, os_stack_t *, uint16_t);
+
+int os_task_sanity_checkin(struct os_task *);
+
+
+#endif /* _OS_TASK_H */
diff --git a/libs/os/include/os/os_test.h b/libs/os/include/os/os_test.h
new file mode 100644
index 0000000..8f4bece
--- /dev/null
+++ b/libs/os/include/os/os_test.h
@@ -0,0 +1,22 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef H_OS_TEST_
+#define H_OS_TEST_
+
+int os_test_all(void);
+
+#endif
diff --git a/libs/os/include/os/os_time.h b/libs/os/include/os/os_time.h
new file mode 100644
index 0000000..d934a68
--- /dev/null
+++ b/libs/os/include/os/os_time.h
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _OS_TIME_H 
+#define _OS_TIME_H 
+
+typedef uint32_t os_time_t;
+
+#ifndef UINT32_MAX
+#define UINT32_MAX  0xFFFFFFFFU
+#endif
+ 
+/* Used to wait forever for events and mutexs */
+#define OS_TIMEOUT_NEVER    (UINT32_MAX)
+
+os_time_t os_time_get(void);
+void os_time_tick(void);
+void os_time_delay(int32_t osticks);
+
+#define OS_TIME_TICK_LT(__t1, __t2) ((int32_t) ((__t1) - (__t2)) < 0)
+#define OS_TIME_TICK_GT(__t1, __t2) ((int32_t) ((__t1) - (__t2)) > 0)
+#define OS_TIME_TICK_GEQ(__t1, __t2) ((int32_t) ((__t1) - (__t2)) >= 0)
+
+
+#endif /* _OS_TIME_H */
diff --git a/libs/os/include/os/queue.h b/libs/os/include/os/queue.h
new file mode 100755
index 0000000..39826dd
--- /dev/null
+++ b/libs/os/include/os/queue.h
@@ -0,0 +1,535 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/*
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 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_
+
+/*
+ * 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)
+
+#endif /* !_QUEUE_H_ */
diff --git a/libs/os/pkg.yml b/libs/os/pkg.yml
new file mode 100644
index 0000000..467b8a3
--- /dev/null
+++ b/libs/os/pkg.yml
@@ -0,0 +1,5 @@
+pkg.name: libs/os
+pkg.vers: 0.1 
+pkg.deps:
+    - libs/cmsis-core
+    - libs/testutil
diff --git a/libs/os/src/arch/arm/cortex-m/m4/HAL_CM4.s b/libs/os/src/arch/arm/cortex-m/m4/HAL_CM4.s
new file mode 100755
index 0000000..1c5651d
--- /dev/null
+++ b/libs/os/src/arch/arm/cortex-m/m4/HAL_CM4.s
@@ -0,0 +1,208 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*----------------------------------------------------------------------------
+ * Copyright (c) 1999-2009 KEIL, 2009-2013 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - 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.
+ *  - Neither the name of ARM  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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDERS AND 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.
+ *---------------------------------------------------------------------------*/
+
+        .file   "HAL_CM4.S"
+        .syntax unified
+
+/*----------------------------------------------------------------------------
+ *      Functions
+ *---------------------------------------------------------------------------*/
+
+        .thumb
+
+        .section ".text"
+        .align  2
+
+/*--------------------------- os_set_env ------------------------------------*/
+#       void os_set_env (void);
+        /* Switch to Unprivileged/Privileged Thread mode, use PSP. */
+
+        .thumb_func
+        .type   os_set_env, %function
+        .global os_set_env
+os_set_env:
+        .fnstart
+        .cantunwind
+
+        MOV     R0,SP                   /* PSP = MSP */
+        MSR     PSP,R0
+        LDR     R0,=os_flags
+        LDRB    R0,[R0]
+        LSLS    R0,#31
+        ITE     NE
+        MOVNE   R0,#0x02                /* Privileged Thread mode, use PSP */
+        MOVEQ   R0,#0x03                /* Unprivileged Thread mode, use PSP */
+        MSR     CONTROL,R0
+        ISB
+        BX      LR
+
+        .fnend
+        .size   os_set_env, .-os_set_env
+/*--------------------------- os_set_env ------------------------------------*/
+
+
+/*--------------------------- os_arch_init_task_stack------------------------*/
+#       void os_arch_init_task_stack(os_stack_t *sf);
+# NOTE: This function only stores R4 through R11 on stack. The reason we do 
+# this is that the application may have stored some values in some of the
+# registers and we want to preserve those values (position independent code
+# is a good example). The other registers are handled in the C startup code.
+        .thumb_func
+        .type   os_arch_init_task_stack, %function
+        .global os_arch_init_task_stack
+os_arch_init_task_stack:
+        .fnstart
+
+        STMIA   R0,{R4-R11}
+        BX      LR
+
+        .fnend
+        .size   os_arch_init_task_stack, .-os_arch_init_task_stack
+/*--------------------------- os_set_env ------------------------------------*/
+
+
+/*-------------------------- SVC_Handler ------------------------------------*/
+
+#       void SVC_Handler (void);
+
+        .thumb_func
+        .type   SVC_Handler, %function
+        .global SVC_Handler
+SVC_Handler:
+        .fnstart
+        .cantunwind
+
+        MRS     R0,PSP                  /* Read PSP */
+        LDR     R1,[R0,#24]             /* Read Saved PC from Stack */
+        LDRB    R1,[R1,#-2]             /* Load SVC Number */
+        CBNZ    R1,SVC_User
+
+        LDM     R0,{R0-R3,R12}          /* Read R0-R3,R12 from stack */
+        PUSH    {R4,LR}                 /* Save EXC_RETURN */
+        BLX     R12                     /* Call SVC Function */
+        POP     {R4,LR}                 /* Restore EXC_RETURN */
+
+        MRS     R12,PSP                 /* Read PSP */
+        STM     R12,{R0-R2}             /* Store return values */
+        BX      LR                      /* Return from interrupt */
+
+        /*------------------- User SVC ------------------------------*/
+SVC_User:
+        PUSH    {R4,LR}                 /* Save EXC_RETURN */
+        LDR     R2,=SVC_Count
+        LDR     R2,[R2]
+        CMP     R1,R2
+        BHI     SVC_Done                /* Overflow */
+
+        LDR     R4,=SVC_Table-4
+        LDR     R4,[R4,R1,LSL #2]       /* Load SVC Function Address */
+
+        LDM     R0,{R0-R3,R12}          /* Read R0-R3,R12 from stack */
+        BLX     R4                      /* Call SVC Function */
+
+        MRS     R12,PSP
+        STM     R12,{R0-R3}             /* Function return values */
+SVC_Done:
+        POP     {R4,LR}                 /* Restore EXC_RETURN */
+        BX      LR                      /* Return from interrupt */
+
+        .fnend
+        .size   SVC_Handler, .-SVC_Handler
+
+
+/*-------------------------- PendSV_Handler ---------------------------------*/
+
+#       void PendSV_Handler (void);
+
+        .thumb_func
+        .type   PendSV_Handler, %function
+        .global PendSV_Handler
+PendSV_Handler:
+        .fnstart
+        .cantunwind
+
+        LDR     R3,=g_os_run_list       /* Get highest priority task ready to run */
+        LDR     R2,[R3]                 /* Store in R2 */
+        LDR     R3,=g_current_task      /* Get current task */
+        LDR     R1,[R3]                 /* Current task in R1 */
+        CMP     R1,R2
+        IT      EQ
+        BXEQ    LR                      /* RETI, no task switch */
+
+        MRS     R12,PSP                 /* Read PSP */
+        STMDB   R12!,{R4-R11}           /* Save Old context */
+        STR     R12,[R1,#0]             /* Update stack pointer in current task */
+        STR     R2,[R3]                 /* g_current_task = highest ready */
+
+        LDR     R12,[R2,#0]             /* get stack pointer of task we will start */
+        LDMIA   R12!,{R4-R11}           /* Restore New Context */
+        MSR     PSP,R12                 /* Write PSP */
+        BX      LR                      /* Return to Thread Mode */
+
+        .fnend
+        .size   PendSV_Handler, .-PendSV_Handler
+
+
+/*-------------------------- SysTick_Handler --------------------------------*/
+
+#       void SysTick_Handler (void);
+        .thumb_func
+        .type   SysTick_Handler, %function
+        .global SysTick_Handler
+SysTick_Handler:
+        .fnstart
+        .cantunwind
+
+        PUSH    {R4,LR}                 /* Save EXC_RETURN */
+        BL      timer_handler
+        POP     {R4,LR}                 /* Restore EXC_RETURN */
+        BX      LR
+
+        .fnend
+        .size   SysTick_Handler, .-SysTick_Handler
+
+        .end
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
diff --git a/libs/os/src/arch/arm/cortex-m/m4/SVC_Table.s b/libs/os/src/arch/arm/cortex-m/m4/SVC_Table.s
new file mode 100755
index 0000000..8a252f7
--- /dev/null
+++ b/libs/os/src/arch/arm/cortex-m/m4/SVC_Table.s
@@ -0,0 +1,73 @@
+; /**
+; * Copyright (c) 2015 Runtime Inc.
+; *
+; * Licensed under the Apache License, Version 2.0 (the "License");
+; * you may not use this file except in compliance with the License.
+; * You may obtain a copy of the License at
+; * 
+; *   http://www.apache.org/licenses/LICENSE-2.0
+; *
+; * Unless required by applicable law or agreed to in writing, software
+; * distributed under the License is distributed on an "AS IS" BASIS,
+; * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; * See the License for the specific language governing permissions and
+; * limitations under the License.
+; */
+;
+;
+;/*----------------------------------------------------------------------------
+; *      RL-ARM - RTX
+; *----------------------------------------------------------------------------
+; *      Name:    SVC_TABLE.S
+; *      Purpose: Pre-defined SVC Table for Cortex-M
+; *      Rev.:    V4.70
+; *----------------------------------------------------------------------------
+; *
+; * Copyright (c) 1999-2009 KEIL, 2009-2013 ARM Germany GmbH
+; * All rights reserved.
+; * Redistribution and use in source and binary forms, with or without
+; * modification, are permitted provided that the following conditions are met:
+; *  - Redistributions of source code must retain the above copyright
+; *    notice, this list of conditions and the following disclaimer.
+; *  - 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.
+; *  - Neither the name of ARM  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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDERS AND 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.
+; *---------------------------------------------------------------------------*/
+
+
+        .file   "SVC_Table.S"
+
+
+        .section ".svc_table"
+
+        .global  SVC_Table
+SVC_Table:
+/* Insert user SVC functions here. SVC 0 used by RTL Kernel. */
+#       .long   __SVC_1                 /* user SVC function */
+SVC_End:
+
+        .global  SVC_Count
+SVC_Count:
+        .long   (SVC_End-SVC_Table)/4
+
+
+        .end
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
diff --git a/libs/os/src/arch/arm/cortex-m/os_arch_arm.c b/libs/os/src/arch/arm/cortex-m/os_arch_arm.c
new file mode 100755
index 0000000..2ef08da
--- /dev/null
+++ b/libs/os/src/arch/arm/cortex-m/os_arch_arm.c
@@ -0,0 +1,281 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "os/os.h"
+#include "os/os_arch.h"
+
+/* XXX: How do we know which cortex to use? */
+#define __CMSIS_GENERIC
+#include "cmsis-core/core_cm4.h"
+
+/* Initial program status register */
+#define INITIAL_xPSR    0x01000000
+
+/* Stack frame structure */
+struct stack_frame {
+    uint32_t    r4;
+    uint32_t    r5;
+    uint32_t    r6;
+    uint32_t    r7;
+    uint32_t    r8;
+    uint32_t    r9;
+    uint32_t    r10;
+    uint32_t    r11;
+    uint32_t    r0;
+    uint32_t    r1;
+    uint32_t    r2;
+    uint32_t    r3;
+    uint32_t    r12;
+    uint32_t    lr;
+    uint32_t    pc;
+    uint32_t    xpsr;
+};
+
+int     die_line;
+char    *die_module;
+
+#define SVC_ArgN(n) \
+  register int __r##n __asm("r"#n);
+
+#define SVC_Arg0()  \
+  SVC_ArgN(0)       \
+  SVC_ArgN(1)       \
+  SVC_ArgN(2)       \
+  SVC_ArgN(3)
+
+#if (defined (__CORTEX_M0)) || defined (__CORTEX_M0PLUS)
+#define SVC_Call(f)                                                     \
+  __asm volatile                                                        \
+  (                                                                     \
+    "ldr r7,="#f"\n\t"                                                  \
+    "mov r12,r7\n\t"                                                    \
+    "svc 0"                                                             \
+    :               "=r" (__r0), "=r" (__r1), "=r" (__r2), "=r" (__r3)  \
+    :                "r" (__r0),  "r" (__r1),  "r" (__r2),  "r" (__r3)  \
+    : "r7", "r12", "lr", "cc"                                           \
+  );
+#else
+#define SVC_Call(f)                                                     \
+  __asm volatile                                                        \
+  (                                                                     \
+    "ldr r12,="#f"\n\t"                                                 \
+    "svc 0"                                                             \
+    :               "=r" (__r0), "=r" (__r1), "=r" (__r2), "=r" (__r3)  \
+    :                "r" (__r0),  "r" (__r1),  "r" (__r2),  "r" (__r3)  \
+    : "r12", "lr", "cc"                                                 \
+  );
+#endif
+
+/* XXX: determine how we will deal with running un-privileged */
+uint32_t os_flags = OS_RUN_PRIV;
+
+void
+timer_handler(void)
+{
+    os_time_tick();
+    os_callout_tick();
+    os_sched_os_timer_exp();
+    os_sched(NULL, 1); 
+}
+
+void
+os_arch_ctx_sw(struct os_task *t)
+{
+    os_bsp_ctx_sw();
+}
+
+void
+os_arch_ctx_sw_isr(struct os_task *t)
+{
+    os_bsp_ctx_sw();
+}
+
+os_sr_t 
+os_arch_save_sr(void)
+{
+    uint32_t isr_ctx;
+
+    isr_ctx = __get_PRIMASK();
+    __disable_irq();
+    return (isr_ctx & 1); 
+}
+
+void
+os_arch_restore_sr(os_sr_t isr_ctx)
+{
+    if (!isr_ctx) {
+        __enable_irq();
+    }
+}
+
+void
+_Die(char *file, int line)
+{
+    die_line = line;
+    die_module = file;
+    while (1) {
+    }
+}
+
+os_stack_t *
+os_arch_task_stack_init(struct os_task *t, os_stack_t *stack_top, int size) 
+{
+    int i;
+    os_stack_t *s;
+    struct stack_frame *sf;
+
+    /* Get stack frame pointer */
+    s = (os_stack_t *) ((uint8_t *) stack_top - sizeof(*sf));
+
+    /* Zero out R1-R3, R12, LR */
+    for (i = 9; i < 14; ++i) {
+        s[i] = 0;
+    }
+
+    /* Set registers R4 - R11 on stack. */
+    os_arch_init_task_stack(s);
+
+    /* Set remaining portions of stack frame */
+    sf = (struct stack_frame *) s;
+    sf->xpsr = INITIAL_xPSR;
+    sf->pc = (uint32_t)t->t_func; 
+    sf->r0 = (uint32_t)t->t_arg;
+
+    return (s);
+}
+
+void
+os_arch_init(void)
+{
+    os_init_idle_task();
+}
+
+__attribute__((always_inline)) 
+static inline void
+svc_os_arch_init(void)
+{
+    SVC_Arg0();
+    SVC_Call(os_arch_init);
+}
+
+os_error_t 
+os_arch_os_init(void)
+{
+    os_error_t err;
+
+    /* Cannot be called within an ISR */
+    err = OS_ERR_IN_ISR;
+    if (__get_IPSR() == 0) {
+        err = OS_OK;
+
+        /* Call bsp related OS initializations */
+        os_bsp_init();
+
+        /* 
+         * Set the os environment. This will set stack pointers and, based
+         * on the contents of os_flags, will determine if the tasks run in
+         * priviliged or un-privileged mode.
+         */
+        os_set_env();
+
+        /* Check if priviliged or not */
+        if ((__get_CONTROL() & 1) == 0) {
+            os_arch_init();
+        } else {
+            svc_os_arch_init();
+        }
+    }
+
+    return err;
+}
+
+uint32_t
+os_arch_start(void)
+{
+    struct os_task *t;
+
+    /* Get the highest priority ready to run to set the current task */
+    t = os_sched_next_task();
+    os_sched_set_current_task(t);
+
+    /* Adjust PSP so it looks like this task just took an exception */
+    __set_PSP((uint32_t)t->t_stackptr + offsetof(struct stack_frame, r0));
+
+    /* Intitialize and start system clock timer */
+    os_bsp_systick_init(OS_TIME_TICK * 1000);
+
+    /* Mark the OS as started, right before we run our first task */
+    g_os_started = 1; 
+
+    /* Perform context switch */
+    os_arch_ctx_sw(t);
+
+    return (uint32_t)(t->t_arg);
+}
+
+__attribute__((always_inline)) 
+static inline void svc_os_arch_start(void)
+{
+    SVC_Arg0();
+    SVC_Call(os_arch_start);
+}
+
+os_error_t 
+os_arch_os_start(void)
+{
+    os_error_t err;
+
+    err = OS_ERR_IN_ISR;
+    if (__get_IPSR() == 0) {
+        /* 
+         * The following switch statement is really just a sanity check to
+         * insure that the os initialization routine was called prior to the
+         * os start routine.
+         */
+        err = OS_OK;
+        switch (__get_CONTROL() & 0x03) {
+        /* 
+         * These two cases are for completeness. Thread mode should be set
+         * to use PSP already.
+         * 
+         * Fall-through intentional!
+         */ 
+        case 0x00:
+        case 0x01:
+            err = OS_ERR_PRIV;
+            break;
+        case 0x02:
+            /* Privileged Thread mode w/SP = PSP */
+            if ((os_flags & 1) == 0) {
+                err = OS_ERR_PRIV;
+            }
+            break;
+        case 0x03:
+            /* Unpriviliged thread mode w/sp = PSP */
+            if  (os_flags & 1) {
+                err = OS_ERR_PRIV;
+            }
+            break;
+        }
+        if (err == OS_OK) {
+            /* Always start OS through SVC call */
+            svc_os_arch_start();
+        }
+    }
+
+    return err;
+}
+
diff --git a/libs/os/src/arch/sim/os_arch_sim.c b/libs/os/src/arch/sim/os_arch_sim.c
new file mode 100644
index 0000000..aecbb57
--- /dev/null
+++ b/libs/os/src/arch/sim/os_arch_sim.c
@@ -0,0 +1,338 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "os/os.h"
+#include "os_priv.h"
+
+#ifdef __APPLE__
+#define _XOPEN_SOURCE
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <assert.h> 
+
+/* XXX: 
+ * Stack must be 16-byte aligned, any changes to this structure 
+ * must keep that alignment.
+ */
+struct stack_frame {
+    jmp_buf sf_jb;
+    int sf_sigsblocked;
+    os_task_func_t sf_func; 
+    void *sf_arg;
+    int _pad[3];
+};
+
+#define CTX_SWITCH_ISR (1)
+#define CTX_SWITCH_TASK (2)
+
+#define ISR_BLOCK_OFF (0) 
+#define ISR_BLOCK_ON (1)
+
+#define sim_setjmp(__jb) _setjmp(__jb)
+#define sim_longjmp(__jb, __ret) _longjmp(__jb, __ret) 
+
+sigset_t g_sigset;  
+volatile int g_block_isr = ISR_BLOCK_OFF;
+
+static volatile int g_block_isr_on = ISR_BLOCK_ON;
+static volatile int g_block_isr_off = ISR_BLOCK_OFF;
+
+static int g_pending_ticks = 0;
+
+static void 
+isr_state(volatile int *state, volatile int *ostate) 
+{
+    if (ostate) {
+        *ostate = g_block_isr;
+    }
+
+    if (state) {
+        g_block_isr = *state;
+    }
+}
+
+
+static void 
+sigs_unblock(void)
+{
+    sigprocmask(SIG_UNBLOCK, &g_sigset, NULL);
+}
+
+static void
+sigs_block(void)
+{
+    sigprocmask(SIG_BLOCK, &g_sigset, NULL);
+}
+
+os_stack_t *
+os_arch_task_stack_init(struct os_task *t, os_stack_t *stack_top, int size) 
+{
+    struct os_task *cur_t; 
+    struct stack_frame *sf;
+    os_stack_t *s;
+    void *s_cur;
+    volatile int block_isr_off; 
+    int rc; 
+
+    /* Make sure another task isn't creating this one.  In sim, this causes
+     * corruption of the original task's stack.
+     */
+    assert(!os_started());
+
+    s = (os_stack_t *) ((uint8_t *) stack_top - sizeof(*sf));
+    sf = (struct stack_frame *) s;
+    sf->sf_sigsblocked = 0;
+    sf->sf_func = t->t_func; 
+    sf->sf_arg = t->t_arg;
+
+    block_isr_off = g_block_isr_off;
+
+    /* Save the current stack pointer, and then trick setjmp() 
+     * to store the stackos stack pointer. 
+     */
+    asm("movl %%esp, %0" : "=r" (s_cur)); 
+    asm("movl %0,%%esp" : /* no output */ : "r" (s));
+
+    isr_state(&g_block_isr_on, NULL); 
+
+    rc = sim_setjmp(sf->sf_jb); 
+    if (rc != 0) { 
+        cur_t = os_sched_get_current_task();
+    
+        isr_state(&block_isr_off, NULL);
+
+        if (rc == CTX_SWITCH_ISR) {
+            sigs_unblock();
+        }
+
+        sf = (struct stack_frame *) cur_t->t_stackptr;
+        sf->sf_func(sf->sf_arg);
+
+        /* This should never return */ 
+        assert(0); 
+    } else {
+        /* restore current stack pointer */
+        isr_state(&g_block_isr_off, NULL);
+        asm("movl %0, %%esp" : /* no output */ : "r" (s_cur));
+    }
+
+    return (s);
+}
+
+void
+os_arch_ctx_sw(struct os_task *next_t)  
+{
+    struct os_task *t;
+    struct stack_frame *sf; 
+    int rc;
+
+    t = os_sched_get_current_task();
+    if (t) {
+        sf = (struct stack_frame *) t->t_stackptr;
+
+        rc = sim_setjmp(sf->sf_jb);
+        if (rc != 0) {
+            if (rc == CTX_SWITCH_ISR) { 
+                sigs_unblock();
+            }
+            return;
+        }
+    }
+
+    os_sched_set_current_task(next_t);
+
+    sf = (struct stack_frame *) next_t->t_stackptr;
+    /* block signals if the task we switch to expects them blocked. */
+    if (sf->sf_sigsblocked) {
+        sigs_block();
+        rc = CTX_SWITCH_ISR;
+    } else {
+        rc = CTX_SWITCH_TASK;
+    }
+
+    sim_longjmp(sf->sf_jb, rc);
+}
+
+void
+os_arch_ctx_sw_isr(struct os_task *next_t)
+{
+    struct os_task *t;
+    struct stack_frame *sf;
+    int isr_ctx;
+    volatile int block_isr_off;
+    int rc;
+
+    block_isr_off = g_block_isr_off; 
+
+    t = os_sched_get_current_task();
+    if (t) {
+        sf = (struct stack_frame *) t->t_stackptr;
+        
+        /* block signals coming from an interrupt context */
+        sf->sf_sigsblocked = 1;
+
+        isr_state(&g_block_isr_on, &isr_ctx);
+
+        rc = sim_setjmp(sf->sf_jb);
+        if (rc != 0) {
+            sf->sf_sigsblocked = 0;
+            isr_state(&block_isr_off, NULL);
+            return;
+        }
+    }
+
+    isr_state(&block_isr_off, NULL);
+
+    os_sched_set_current_task(next_t);
+    
+    sf = (struct stack_frame *) next_t->t_stackptr;
+    sim_longjmp(sf->sf_jb, CTX_SWITCH_ISR); 
+}
+
+os_sr_t 
+os_arch_save_sr(void)
+{
+    int isr_ctx;
+
+    isr_state(&g_block_isr_on, &isr_ctx); 
+
+    return (isr_ctx); 
+}
+
+void
+os_arch_restore_sr(int isr_ctx)  
+{
+    if (isr_ctx == ISR_BLOCK_ON) {
+        return;
+    } else {
+        isr_state(&g_block_isr_off, NULL);
+    }
+}
+
+static void timer_handler(int sig);
+
+static void
+initialize_signals(void)
+{
+    struct sigaction sa;
+
+    sigemptyset(&g_sigset);
+    sigaddset(&g_sigset, SIGALRM); 
+    sigaddset(&g_sigset, SIGVTALRM);
+
+    memset(&sa, 0, sizeof sa);
+    sa.sa_handler = timer_handler;
+
+    sigaction(SIGALRM, &sa, NULL);
+    sigaction(SIGVTALRM, &sa, NULL);
+}
+
+
+static void
+timer_handler(int sig)
+{
+    static struct timeval time_last;
+    static int time_inited; 
+    struct timeval time_now, time_diff; 
+    int isr_ctx;
+
+    if (!time_inited) {
+        gettimeofday(&time_last, NULL);
+        time_inited = 1;
+    }
+
+    isr_state(NULL, &isr_ctx); 
+    if (isr_ctx == ISR_BLOCK_ON) {
+        ++g_pending_ticks;
+        return;
+    }
+
+    gettimeofday(&time_now, NULL);
+    timersub(&time_now, &time_last, &time_diff);
+
+    g_pending_ticks = time_diff.tv_usec / 1000;
+
+    while (--g_pending_ticks >= 0) {
+        os_time_tick();
+        os_callout_tick();
+    }
+
+    time_last = time_now;
+    g_pending_ticks = 0;
+
+    os_sched_os_timer_exp();
+    os_sched(NULL, 1); 
+}
+
+static void
+start_timer(void)
+{
+    struct itimerval it; 
+    int rc;
+
+    initialize_signals();
+
+    /* 1 msec OS tick */
+    memset(&it, 0, sizeof(it));
+    it.it_value.tv_sec = 0;
+    it.it_value.tv_usec = 1000;
+    it.it_interval.tv_sec = 0;
+    it.it_interval.tv_usec = 1000;
+
+    rc = setitimer(ITIMER_VIRTUAL, &it, NULL);
+    if (rc != 0) {
+        perror("Cannot set itimer");
+        abort();
+    }
+}
+
+os_error_t 
+os_arch_os_init(void)
+{
+    g_current_task = NULL;
+
+    TAILQ_INIT(&g_os_run_list);
+    TAILQ_INIT(&g_os_sleep_list);
+
+    os_init_idle_task();
+    os_sanity_task_init(); 
+    return OS_OK;
+}
+
+os_error_t
+os_arch_os_start(void)
+{
+    struct stack_frame *sf; 
+    struct os_task *t;
+
+    start_timer();
+
+    t = os_sched_next_task();
+    os_sched_set_current_task(t);
+
+    g_os_started = 1; 
+
+    sf = (struct stack_frame *) t->t_stackptr;
+    sim_longjmp(sf->sf_jb, CTX_SWITCH_TASK); 
+
+    return 0;
+}
+
diff --git a/libs/os/src/os.c b/libs/os/src/os.c
new file mode 100644
index 0000000..3ca3177
--- /dev/null
+++ b/libs/os/src/os.c
@@ -0,0 +1,71 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "os/os.h"
+#include "os/queue.h"
+
+#include <assert.h> 
+
+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;
+/* Default zero.  Set by the architecture specific code when os is started.
+ */
+int g_os_started; 
+
+
+void
+os_idle_task(void *arg)
+{
+    /* For now, idle task simply increments a counter to show it is running. */
+    while (1) {
+        ++g_os_idle_ctr;
+    }
+}
+
+int 
+os_started(void) 
+{
+    return (g_os_started);
+}
+
+
+void
+os_init_idle_task(void)
+{
+    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));
+}
+
+void
+os_init(void)
+{
+    os_error_t err;
+
+    err = os_arch_os_init();
+    assert(err == OS_OK);
+}
+
+void
+os_start(void)
+{
+    os_error_t err;
+
+    err = os_arch_os_start();
+    assert(err == OS_OK);
+}
diff --git a/libs/os/src/os_callout.c b/libs/os/src/os_callout.c
new file mode 100644
index 0000000..3ae9fdd
--- /dev/null
+++ b/libs/os/src/os_callout.c
@@ -0,0 +1,140 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "os/os.h" 
+
+#include <string.h> 
+
+TAILQ_HEAD(, os_callout) g_callout_list = 
+    TAILQ_HEAD_INITIALIZER(g_callout_list); 
+
+void 
+os_callout_init(struct os_callout *c)
+{
+    memset(c, 0, sizeof(*c));
+    c->c_ev.ev_type = OS_EVENT_T_TIMER; 
+}
+
+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_flags &= ~OS_CALLOUT_F_QUEUED;
+    }
+
+    if (c->c_evq) {
+        os_eventq_remove(c->c_evq, &c->c_ev); 
+    }
+
+    OS_EXIT_CRITICAL(sr);
+}
+
+
+int 
+os_callout_reset(struct os_callout *c, int32_t ticks, struct os_eventq *evq, 
+        void *arg) 
+{
+    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; 
+    c->c_flags |= OS_CALLOUT_F_QUEUED; 
+    c->c_evq = evq;
+    c->c_ev.ev_arg = arg;
+
+    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);
+}
+
+int
+os_callout_func_reset(struct os_callout_func *cf, int32_t ticks, 
+        struct os_eventq *evq, os_callout_func_t func, void *arg)
+{
+    int rc; 
+
+    cf->cf_func = func;
+    cf->cf_arg = arg; 
+
+    rc = os_callout_reset(&cf->cf_c, ticks, evq, cf);
+
+    return (rc);
+}
+
+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_flags &= ~OS_CALLOUT_F_QUEUED;
+            } else {
+                c = NULL;
+            }
+        }
+        OS_EXIT_CRITICAL(sr);
+
+        if (c) {
+            os_eventq_put2(c->c_evq, &c->c_ev, 1);
+        } else {
+            break;
+        }
+    }
+}
diff --git a/libs/os/src/os_eventq.c b/libs/os/src/os_eventq.c
new file mode 100644
index 0000000..52770e8
--- /dev/null
+++ b/libs/os/src/os_eventq.c
@@ -0,0 +1,104 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "os/os.h"
+
+#include <string.h>
+
+void
+os_eventq_init(struct os_eventq *evq)
+{
+    memset(evq, 0, sizeof(*evq));
+    TAILQ_INIT(&evq->evq_list);
+}
+
+void
+os_eventq_put2(struct os_eventq *evq, struct os_event *ev, int isr)
+{
+    int resched;
+    os_sr_t sr; 
+
+    OS_ENTER_CRITICAL(sr);
+
+    /* Do not queue if already queued */
+    if (ev->ev_queued) {
+        OS_EXIT_CRITICAL(sr);
+        return;
+    }
+
+    /* Queue the event */
+    ev->ev_queued = 1; 
+    TAILQ_INSERT_TAIL(&evq->evq_list, ev, ev_next);
+
+    /* If task waiting on event, wake it up. */
+    resched = 0;
+    if (evq->evq_task) {
+        os_sched_wakeup(evq->evq_task);
+        resched = 1;
+    }
+
+    OS_EXIT_CRITICAL(sr);
+
+    if (resched) {
+        os_sched(NULL, isr);
+    }
+}
+
+void 
+os_eventq_put(struct os_eventq *evq, struct os_event *ev) 
+{
+    os_eventq_put2(evq, ev, 0);
+}
+
+struct os_event * 
+os_eventq_get(struct os_eventq *evq)
+{
+    struct os_event *ev; 
+    os_sr_t sr; 
+
+    OS_ENTER_CRITICAL(sr);
+pull_one:
+    ev = TAILQ_FIRST(&evq->evq_list);
+    if (ev) {
+        TAILQ_REMOVE(&evq->evq_list, ev, ev_next);
+        ev->ev_queued = 0;
+    } else {
+        evq->evq_task = os_sched_get_current_task();
+        os_sched_sleep(evq->evq_task, OS_TIMEOUT_NEVER);
+        OS_EXIT_CRITICAL(sr);
+
+        os_sched(NULL, 0);
+
+        OS_ENTER_CRITICAL(sr); 
+        evq->evq_task = NULL;
+        goto pull_one;
+    }
+    OS_EXIT_CRITICAL(sr); 
+
+    return (ev);
+}
+
+void
+os_eventq_remove(struct os_eventq *evq, struct os_event *ev)
+{
+    os_sr_t sr;
+
+    OS_ENTER_CRITICAL(sr);
+    TAILQ_REMOVE(&evq->evq_list, ev, ev_next); 
+    ev->ev_queued = 0;
+    OS_EXIT_CRITICAL(sr);
+}
diff --git a/libs/os/src/os_heap.c b/libs/os/src/os_heap.c
new file mode 100644
index 0000000..8198522
--- /dev/null
+++ b/libs/os/src/os_heap.c
@@ -0,0 +1,76 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <assert.h>
+#include "os/os_mutex.h"
+#include "os/os_heap.h"
+
+static struct os_mutex os_malloc_mutex;
+
+static void
+os_malloc_lock(void)
+{
+    int rc;
+
+    if (g_os_started) {
+        rc = os_mutex_pend(&os_malloc_mutex, 0xffffffff);
+        assert(rc == 0);
+    }
+}
+
+static void
+os_malloc_unlock(void)
+{
+    int rc;
+
+    if (g_os_started) {
+        rc = os_mutex_release(&os_malloc_mutex);
+        assert(rc == 0);
+    }
+}
+
+void *
+os_malloc(size_t size)
+{
+    void *ptr;
+
+    os_malloc_lock();
+    ptr = malloc(size);
+    os_malloc_unlock();
+
+    return ptr;
+}
+
+void
+os_free(void *mem)
+{
+    os_malloc_lock();
+    free(mem);
+    os_malloc_unlock();
+}
+
+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;
+}
diff --git a/libs/os/src/os_mbuf.c b/libs/os/src/os_mbuf.c
new file mode 100644
index 0000000..98d327a
--- /dev/null
+++ b/libs/os/src/os_mbuf.c
@@ -0,0 +1,365 @@
+/**
+ * Copyright (c) Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * 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 <string.h>
+
+/**
+ * Initialize a pool of mbufs. 
+ * 
+ * @param omp     The mbuf pool to initialize 
+ * @param mp      The memory pool that will hold this mbuf pool 
+ * @param hdr_len The length of the header, in a header mbuf 
+ * @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 hdr_len, uint16_t buf_len, uint16_t nbufs)
+{
+    omp->omp_hdr_len = hdr_len;
+    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; 
+
+    om = os_memblock_get(omp->omp_pool);
+    if (!om) {
+        goto err;
+    }
+
+    SLIST_NEXT(om, om_next) = NULL;
+    om->om_flags = 0;
+    om->om_len = 0;
+    om->om_data = (&om->om_databuf[0] + leadingspace);
+
+    return (om);
+err:
+    return (NULL);
+}
+
+/**
+ * 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_pool *omp, struct os_mbuf *om) 
+{
+    int rc;
+
+    rc = os_memblock_put(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_pool *omp, struct os_mbuf *om)
+{
+    struct os_mbuf *next;
+    int rc;
+
+    while (om != NULL) {
+        next = SLIST_NEXT(om, om_next);
+
+        rc = os_mbuf_free(omp, 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_pool *omp, struct os_mbuf *new_buf, 
+        struct os_mbuf *old_buf)
+{
+    memcpy(&new_buf->om_databuf[0], &old_buf->om_databuf[0], 
+            sizeof(struct os_mbuf_pkthdr) + omp->omp_hdr_len);
+}
+
+/** 
+ * Append data onto a mbuf 
+ *
+ * @param omp  The mbuf pool this mbuf was allocated out of 
+ * @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_pool *omp, struct os_mbuf *om, void *data,  
+        uint16_t len)
+{
+    struct os_mbuf *last; 
+    struct os_mbuf *new;
+    int remainder;
+    int space;
+    int rc;
+
+    if (omp == NULL || om == NULL) {
+        rc = OS_EINVAL;
+        goto err;
+    }
+
+    /* 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(omp, 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, void *), 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, OS_MBUF_START_OFF(omp)); 
+        if (!new) {
+            break;
+        }
+
+        new->om_len = min(omp->omp_databuf_len, remainder);
+        memcpy(OS_MBUF_DATA(om, 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); 
+}
+
+
+/**
+ * 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_pool *omp, struct os_mbuf *om)
+{
+    struct os_mbuf *head;
+    struct os_mbuf *copy; 
+
+    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(omp, om)); 
+            if (!SLIST_NEXT(copy, om_next)) {
+                os_mbuf_free_chain(omp, head);
+                goto err;
+            }
+
+            copy = SLIST_NEXT(copy, om_next);
+        } else {
+            head = os_mbuf_get(omp, OS_MBUF_LEADINGSPACE(omp, om));
+            if (!head) {
+                goto err;
+            }
+
+            if (om->om_flags & OS_MBUF_F_MASK(OS_MBUF_F_PKTHDR)) {
+                _os_mbuf_copypkthdr(omp, 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);
+}
+
+#if 0
+
+/**
+ * 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_pool *omp, struct os_mbuf *om, uint16_t len)
+{
+    struct os_mbuf *newm;
+
+    if (len > omp->omp_databuf_len) {
+        goto err;
+    }
+
+    /* Is 'n' bytes already contiguous? */
+    if (((uint8_t *) &om->om_databuf[0] + OS_MBUF_END_OFF(omp)) - 
+            OS_MBUF_DATA(om, uint8_t *) >= len) {
+        newm = om;
+        goto done;
+    }
+
+    /* Nope, OK. Allocate a new buffer, and then go through and copy 'n' 
+     * bytes into that buffer.
+     */
+    newm = os_mbuf_get(omp, OS_MBUF_START_OFF(omp));
+    if (!newm) {
+        goto err;
+    }
+
+    written = 0; 
+    while (written < len
+
+
+done:
+    return (newm);
+err:
+    if (om) {
+        os_mbuf_free_chain(om);
+    }
+
+    return (NULL);
+}
+#endif
diff --git a/libs/os/src/os_mempool.c b/libs/os/src/os_mempool.c
new file mode 100644
index 0000000..1fb05df
--- /dev/null
+++ b/libs/os/src/os_mempool.c
@@ -0,0 +1,150 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "os/os.h"
+
+/**
+ * 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) || (!membuf) || (blocks <= 0) || (block_size <= 0)) {
+        return OS_INVALID_PARM;
+    }
+
+    /* 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_ALIGN(block_size, OS_ALIGNMENT);
+
+    /* Initialize the memory pool structure */
+    mp->mp_block_size = block_size;
+    mp->mp_num_free = blocks;
+    mp->mp_num_blocks = blocks;
+    mp->name = name;
+    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;
+        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;
+
+    return OS_OK;
+}
+
+/**
+ * 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);
+
+            /* Set new free list head */
+            SLIST_FIRST(mp) = SLIST_NEXT(block, mb_next);
+
+            /* Decrement number free by 1 */
+            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)
+{
+    struct os_memblock *block;
+    os_sr_t sr;
+
+    /* Make sure parameters are valid */
+    if ((mp == NULL) || (block_addr == NULL)) {
+        return OS_INVALID_PARM;
+    }
+
+    /* 
+     * XXX: we should do boundary checks here! The block had better be within 
+     * the pool. If it fails, do we return an error or assert()? Add this when 
+     * we add the memory debug. 
+     */ 
+    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;
+}
diff --git a/libs/os/src/os_mutex.c b/libs/os/src/os_mutex.c
new file mode 100644
index 0000000..3ad3151
--- /dev/null
+++ b/libs/os/src/os_mutex.c
@@ -0,0 +1,298 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "os/os.h"
+#include <assert.h>
+
+/**
+ * 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;
+    }
+
+    /* Initialize to 0 */
+    mu->mu_prio = 0;
+    mu->mu_level = 0;
+    mu->mu_owner = NULL;
+    SLIST_FIRST(&mu->mu_head) = NULL;
+
+    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);
+
+    /* 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_mutex);
+        rdy->t_mutex = NULL;
+
+        SLIST_REMOVE_HEAD(&mu->mu_head, t_obj_list);
+        SLIST_NEXT(rdy, t_obj_list) = NULL;
+        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;
+
+    /* 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, 0);
+    }
+
+    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;
+        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;
+    }
+
+    /* 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_mutex = mu;
+    os_sched_sleep(current, timeout);
+
+    OS_EXIT_CRITICAL(sr);
+
+    os_sched(NULL, 0);
+
+    /* If we are owner we did not time out. */
+    if (mu->mu_owner == current) {
+        rc = OS_OK; 
+    } else {
+        rc = OS_TIMEOUT;
+    }
+
+    return rc;
+}
+
+/**
+ * os mutex delete
+ * 
+ * Delete a mutex. 
+ *  
+ * @param mu Pointer to mutex to delete
+ * 
+ * @return os_error_t 
+ *      OS_INVALID_PARM     Mutex passed in was NULL.
+ *      OS_OK               no error.
+ */
+os_error_t
+os_mutex_delete(struct os_mutex *mu)
+{
+    os_sr_t sr;
+    struct os_task *current;
+    struct os_task *rdy;
+
+    /* OS must be started to call this function */
+    if (!g_os_started) {
+        return (OS_NOT_STARTED);
+    }
+
+    /* Check for valid mutex */
+    if (!mu) {
+        return OS_INVALID_PARM;
+    }
+
+    /* Get currently running task */
+    current = os_sched_get_current_task();
+
+    OS_ENTER_CRITICAL(sr);
+
+    /* Restore owner task's priority. */
+    if (mu->mu_level != 0) {
+        if (mu->mu_owner->t_prio != mu->mu_prio) {
+            /* We have to resort the ready list if this task is ready */
+            mu->mu_owner->t_prio = mu->mu_prio;
+            os_sched_resort(mu->mu_owner);
+        }
+    }
+
+    /* Now, go through all the tasks waiting on the mutex */
+    while (!SLIST_EMPTY(&mu->mu_head)) {
+        rdy = SLIST_FIRST(&mu->mu_head);
+        assert(rdy->t_mutex);
+        rdy->t_mutex = NULL;
+        SLIST_REMOVE_HEAD(&mu->mu_head, t_obj_list);
+        SLIST_NEXT(rdy, t_obj_list) = NULL;
+        os_sched_wakeup(rdy);
+    }
+
+    /* Is there a task that is ready that is higher priority than us? */
+    rdy = os_sched_next_task();
+    if (rdy != current) {
+        /* Re-schedule */
+        OS_EXIT_CRITICAL(sr);
+        os_sched(rdy, 0);
+    } else {
+        OS_EXIT_CRITICAL(sr);
+    }
+
+    return OS_OK;
+}
+
diff --git a/libs/os/src/os_priv.h b/libs/os/src/os_priv.h
new file mode 100644
index 0000000..db2d7d3
--- /dev/null
+++ b/libs/os/src/os_priv.h
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef H_OS_PRIV_
+#define H_OS_PRIV_
+
+TAILQ_HEAD(os_task_list, os_task);
+
+extern struct os_task_list g_os_run_list;
+extern struct os_task_list g_os_sleep_list;
+extern struct os_task *g_current_task;
+
+#endif
diff --git a/libs/os/src/os_sanity.c b/libs/os/src/os_sanity.c
new file mode 100644
index 0000000..988cc37
--- /dev/null
+++ b/libs/os/src/os_sanity.c
@@ -0,0 +1,227 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <assert.h>
+#include <string.h> 
+
+#include "os/os.h" 
+
+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; 
+
+struct os_task g_os_sanity_task;
+os_stack_t g_os_sanity_task_stack[OS_STACK_ALIGN(OS_SANITY_STACK_SIZE)];
+
+
+/**
+ * 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);
+}
+
+/**
+ * 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);
+}
+
+/**
+ * The main sanity check task loop.  This executes every SANITY_CHECK_NUM_SECS
+ * and goes through to see if any of the registered sanity checks are expired.
+ * If the sanity checks have expired, it restarts the operating system.
+ *
+ * @param arg unused 
+ *
+ * @return never 
+ */
+static void
+os_sanity_task_loop(void *arg)
+{
+    struct os_sanity_check *sc; 
+    int rc; 
+
+    while (1) {
+        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);
+        }
+
+        os_time_delay(OS_TICKS_PER_SEC); 
+    }
+}
+
+/**
+ * Initialize the sanity task and mutex. 
+ *
+ * @return 0 on success, error code on failure
+ */
+int 
+os_sanity_task_init(void)
+{
+    int rc;
+
+    rc = os_mutex_init(&g_os_sanity_check_mu); 
+    if (rc != 0) {
+        goto err;
+    }
+
+    rc = os_task_init(&g_os_sanity_task, "os_sanity", os_sanity_task_loop, 
+            NULL, OS_SANITY_PRIO, OS_WAIT_FOREVER, g_os_sanity_task_stack, 
+            OS_STACK_ALIGN(OS_SANITY_STACK_SIZE));
+    if (rc != OS_OK) {
+        goto err;
+    }
+
+    return (0);
+err:
+    return (rc);
+}
diff --git a/libs/os/src/os_sched.c b/libs/os/src/os_sched.c
new file mode 100644
index 0000000..240bc62
--- /dev/null
+++ b/libs/os/src/os_sched.c
@@ -0,0 +1,290 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "os/os.h"
+#include "os/queue.h"
+
+#include <assert.h>
+
+TAILQ_HEAD(, os_task) g_os_run_list = TAILQ_HEAD_INITIALIZER(g_os_run_list); 
+
+TAILQ_HEAD(, os_task) g_os_sleep_list = TAILQ_HEAD_INITIALIZER(g_os_sleep_list); 
+
+struct os_task *g_current_task; 
+
+/**
+ * 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);
+}
+
+/**
+ * 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
+ * @param isr    Flag denoting whether we are inside an isr (0:no, 1:yes).
+ */
+void
+os_sched(struct os_task *next_t, int isr) 
+{
+    os_sr_t sr;
+
+    OS_ENTER_CRITICAL(sr);
+
+    if (!next_t) {
+        next_t = os_sched_next_task();
+    }
+
+    if (next_t != os_sched_get_current_task()) {
+        OS_EXIT_CRITICAL(sr);
+        if (isr) {
+            os_arch_ctx_sw_isr(next_t);
+        } else {
+            os_arch_ctx_sw(next_t);
+        }
+
+    } else {
+        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); 
+        }
+    }
+
+    return (0);
+}
+
+/**
+ * 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) 
+{
+    /* Remove self from mutex list if waiting on one */
+    if (t->t_mutex) {
+        assert(!SLIST_EMPTY(&t->t_mutex->mu_head));
+        SLIST_REMOVE(&t->t_mutex->mu_head, t, os_task, t_obj_list);
+        SLIST_NEXT(t, t_obj_list) = NULL;
+        t->t_mutex = 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_sched_wakeup(t);
+        } else {
+            break;
+        }
+        t = next;
+    }
+
+    OS_EXIT_CRITICAL(sr); 
+}
+
+/**
+ * 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);
+    }
+}
+
diff --git a/libs/os/src/os_sem.c b/libs/os/src/os_sem.c
new file mode 100644
index 0000000..d3b395c
--- /dev/null
+++ b/libs/os/src/os_sem.c
@@ -0,0 +1,277 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "os/os.h"
+#include <assert.h>
+
+/* 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 create
+ *  
+ * Create a semaphore and initialize it. 
+ * 
+ * @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 */
+        rdy->t_flags &= ~OS_TASK_FLAG_SEM_WAIT;
+
+        /* There is one waiting. Wake it up */
+        SLIST_REMOVE_HEAD(&sem->sem_head, t_obj_list);
+        SLIST_NEXT(rdy, t_obj_list) = NULL;
+        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, 0);
+    }
+
+    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_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, 0);
+        /* 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;
+}
+
+/**
+ * os sem delete
+ * 
+ * Delete a semaphore. 
+ *  
+ * @param mu Pointer to semaphore to delete
+ * 
+ * @return os_error_t 
+ *      OS_INVALID_PARM     Semaphore passed in was NULL.
+ *      OS_OK               no error.
+ */
+os_error_t
+os_sem_delete(struct os_sem *sem)
+{
+    int resched;
+    os_sr_t sr;
+    struct os_task *current;
+    struct os_task *rdy;
+
+    /* OS must be started in order to call this function */
+    if (!g_os_started) {
+        return (OS_NOT_STARTED);
+    }
+
+    /* Check for valid semaphore */
+    if (!sem) {
+        return OS_INVALID_PARM;
+    }
+
+    /* Get currently running task */
+    resched = 0;
+    current = os_sched_get_current_task();
+
+    OS_ENTER_CRITICAL(sr);
+
+    /* Remove all tokens from semaphore */
+    sem->sem_tokens = 0;
+
+    /* Any tasks waiting? */
+    rdy = SLIST_FIRST(&sem->sem_head);
+    if (rdy) {
+        /* If higher priority than current task, we must resched */
+        if (current->t_prio > rdy->t_prio) {
+            resched = 1;
+        }
+
+        /* Now, go through all the tasks waiting on the semaphore */
+        while (rdy != NULL) {
+            SLIST_REMOVE_HEAD(&sem->sem_head, t_obj_list);
+            SLIST_NEXT(rdy, t_obj_list) = NULL;
+            os_sched_wakeup(rdy);
+            rdy = SLIST_FIRST(&sem->sem_head);
+        }
+    }
+
+    OS_EXIT_CRITICAL(sr);
+
+    /* Re-schedule if needed*/
+    if (resched) {
+        os_sched(rdy, 0);
+    }
+
+    return OS_OK;
+}
+
diff --git a/libs/os/src/os_task.c b/libs/os/src/os_task.c
new file mode 100644
index 0000000..f9da560
--- /dev/null
+++ b/libs/os/src/os_task.c
@@ -0,0 +1,118 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "os/os.h"
+
+#include <string.h>
+
+uint8_t g_task_id;
+
+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);
+}
+
+int 
+os_task_sanity_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);
+}
+
+
+
+int 
+os_task_init(struct os_task *t, 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; 
+
+    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_stackptr = os_arch_task_stack_init(t, &stack_bottom[stack_size], 
+            stack_size);
+
+    /* insert this task into the scheduler list */
+    rc = os_sched_insert(t);
+    if (rc != OS_OK) {
+        goto err;
+    }
+
+    return (0);
+err:
+    return (rc);
+}
+
diff --git a/libs/os/src/os_time.c b/libs/os/src/os_time.c
new file mode 100644
index 0000000..cc2e819
--- /dev/null
+++ b/libs/os/src/os_time.c
@@ -0,0 +1,60 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "os/os.h"
+#include "os/queue.h"
+
+static os_time_t g_os_time = 0;
+
+os_time_t  
+os_time_get(void)
+{
+    return (g_os_time);
+}
+
+/**
+ * Called for every single tick by the architecture specific functions.
+ *
+ * Increases the os_time by 1 tick. 
+ */
+void
+os_time_tick(void)
+{
+    os_sr_t sr;
+
+    OS_ENTER_CRITICAL(sr);
+    ++g_os_time;
+    OS_EXIT_CRITICAL(sr);
+}
+
+/**
+ * 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, 0);
+    }
+}
diff --git a/libs/os/src/test/arch/arm/os_test_arch_arm.c b/libs/os/src/test/arch/arm/os_test_arch_arm.c
new file mode 100644
index 0000000..914f43f
--- /dev/null
+++ b/libs/os/src/test/arch/arm/os_test_arch_arm.c
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "testutil/testutil.h"
+#include "os_test_priv.h"
+
+void
+os_test_restart(void)
+{
+    tu_restart();
+}
diff --git a/libs/os/src/test/arch/sim/os_test_arch_sim.c b/libs/os/src/test/arch/sim/os_test_arch_sim.c
new file mode 100644
index 0000000..d28b881
--- /dev/null
+++ b/libs/os/src/test/arch/sim/os_test_arch_sim.c
@@ -0,0 +1,49 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/time.h>
+#include "testutil/testutil.h"
+#include "os/os.h"
+#include "os_test_priv.h"
+
+void
+os_test_restart(void)
+{
+    struct sigaction sa;
+    struct itimerval it;
+    int rc;
+
+    g_os_started = 0;
+
+    memset(&sa, 0, sizeof sa);
+    sa.sa_handler = SIG_IGN;
+
+    sigaction(SIGALRM, &sa, NULL);
+    sigaction(SIGVTALRM, &sa, NULL);
+
+    memset(&it, 0, sizeof(it));
+    rc = setitimer(ITIMER_VIRTUAL, &it, NULL);
+    if (rc != 0) {
+        perror("Cannot set itimer");
+        abort();
+    }
+
+    tu_restart();
+}
diff --git a/libs/os/src/test/mbuf_test.c b/libs/os/src/test/mbuf_test.c
new file mode 100644
index 0000000..6d98452
--- /dev/null
+++ b/libs/os/src/test/mbuf_test.c
@@ -0,0 +1,135 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "testutil/testutil.h"
+#include "os/os.h"
+#include "os_test_priv.h"
+
+#include <string.h>
+
+#define MBUF_TEST_POOL_BUF_SIZE (256)
+#define MBUF_TEST_POOL_BUF_COUNT (10) 
+
+os_membuf_t os_mbuf_membuf[OS_MEMPOOL_SIZE(MBUF_TEST_POOL_BUF_SIZE, 
+        MBUF_TEST_POOL_BUF_COUNT)];
+
+struct os_mbuf_pool os_mbuf_pool; 
+struct os_mempool os_mbuf_mempool; 
+
+static void 
+os_mbuf_test_setup(void)
+{
+    int rc;
+
+    rc = os_mempool_init(&os_mbuf_mempool, MBUF_TEST_POOL_BUF_COUNT, 
+            MBUF_TEST_POOL_BUF_SIZE, &os_mbuf_membuf[0], "mbuf_pool");
+    TEST_ASSERT_FATAL(rc == 0, "Error creating memory pool %d", rc);
+
+    rc = os_mbuf_pool_init(&os_mbuf_pool, &os_mbuf_mempool, 0, 
+            MBUF_TEST_POOL_BUF_SIZE, MBUF_TEST_POOL_BUF_COUNT);
+    TEST_ASSERT_FATAL(rc == 0, "Error creating mbuf pool %d", rc);
+}
+
+
+
+TEST_CASE(os_mbuf_test_case_1)
+{
+    struct os_mbuf *m; 
+    int rc;
+
+    m = os_mbuf_get(&os_mbuf_pool, 0);
+    TEST_ASSERT_FATAL(m != NULL, "Error allocating mbuf");
+
+    rc = os_mbuf_free(&os_mbuf_pool, m);
+    TEST_ASSERT_FATAL(rc == 0, "Error free'ing mbuf %d", rc);
+}
+
+TEST_CASE(os_mbuf_test_case_2) 
+{
+    struct os_mbuf *m;
+    struct os_mbuf *m2;
+    struct os_mbuf *dup;
+    int rc;
+
+    /* Test first allocating and duplicating a single mbuf */
+    m = os_mbuf_get(&os_mbuf_pool, 0);
+    TEST_ASSERT_FATAL(m != NULL, "Error allocating mbuf");
+
+    dup = os_mbuf_dup(&os_mbuf_pool, m);
+    TEST_ASSERT_FATAL(dup != NULL, "NULL mbuf returned from dup");
+    TEST_ASSERT_FATAL(dup != m, "duplicate matches original.");
+
+    rc = os_mbuf_free(&os_mbuf_pool, m);
+    TEST_ASSERT_FATAL(rc == 0, "Error free'ing mbuf m %d", rc);
+    
+    rc = os_mbuf_free(&os_mbuf_pool, dup);
+    TEST_ASSERT_FATAL(rc == 0, "Error free'ing mbuf dup %d", rc);
+
+    m = os_mbuf_get(&os_mbuf_pool, 0);
+    TEST_ASSERT_FATAL(m != NULL, "Error allocating mbuf"); 
+
+    m2 = os_mbuf_get(&os_mbuf_pool, 0);
+    TEST_ASSERT_FATAL(m2 != NULL, "Error allocating mbuf");
+
+    SLIST_NEXT(m, om_next) = m2; 
+
+    dup = os_mbuf_dup(&os_mbuf_pool, m);
+    TEST_ASSERT_FATAL(dup != NULL, "NULL mbuf returned from dup");
+    TEST_ASSERT_FATAL(dup != m, "Duplicate matches original");
+    TEST_ASSERT_FATAL(SLIST_NEXT(dup, om_next) != NULL, 
+            "NULL chained element, duplicate should match original");
+
+    rc = os_mbuf_free_chain(&os_mbuf_pool, m);
+    TEST_ASSERT_FATAL(rc == 0, "Cannot free mbuf chain %d", rc);
+
+    rc = os_mbuf_free_chain(&os_mbuf_pool, dup);
+    TEST_ASSERT_FATAL(rc == 0, "Cannot free mbuf chain %d", rc);
+}
+
+TEST_CASE(os_mbuf_test_case_3) 
+{
+    struct os_mbuf *m; 
+    int rc;
+    uint8_t databuf[] = {0xa, 0xb, 0xc, 0xd};
+    uint8_t cmpbuf[] = {0xff, 0xff, 0xff, 0xff};
+
+    m = os_mbuf_get(&os_mbuf_pool, 0);
+    TEST_ASSERT_FATAL(m != NULL, "Error allocating mbuf");
+
+    rc = os_mbuf_append(&os_mbuf_pool, m, databuf, sizeof(databuf));
+    TEST_ASSERT_FATAL(rc == 0, "Cannot add %d bytes to mbuf", 
+            sizeof(databuf));
+    TEST_ASSERT_FATAL(m->om_len == sizeof(databuf), 
+            "Length doesn't match size appended %d vs %d", m->om_len, 
+            sizeof(databuf));
+
+    memcpy(cmpbuf, OS_MBUF_DATA(m, uint8_t *), m->om_len);
+    TEST_ASSERT_FATAL(memcmp(cmpbuf, databuf, sizeof(databuf)) == 0, 
+            "Databuf doesn't match cmpbuf");
+}
+
+TEST_SUITE(os_mbuf_test_case_4)
+{
+}
+
+TEST_SUITE(os_mbuf_test_suite)
+{
+    os_mbuf_test_setup();
+
+    os_mbuf_test_case_1();
+    os_mbuf_test_case_2();
+    os_mbuf_test_case_3();
+}
diff --git a/libs/os/src/test/mempool_test.c b/libs/os/src/test/mempool_test.c
new file mode 100644
index 0000000..bfe2d46
--- /dev/null
+++ b/libs/os/src/test/mempool_test.c
@@ -0,0 +1,207 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <stdio.h>
+#include <string.h>
+#include "testutil/testutil.h"
+#include "os/os.h"
+#include "os_test_priv.h"
+
+/* Create a memory pool for testing */
+#define NUM_MEM_BLOCKS  (10)
+#define MEM_BLOCK_SIZE  (80)
+
+/* Limit max blocks for testing */
+#define MEMPOOL_TEST_MAX_BLOCKS     (128)
+
+#if OS_CFG_ALIGNMENT == OS_CFG_ALIGN_4
+int alignment = 4;
+#else
+int alignment = 8;
+#endif
+
+/* Test memory pool structure */
+struct os_mempool g_TstMempool;
+
+/* Test memory pool buffer */
+os_membuf_t TstMembuf[OS_MEMPOOL_SIZE(NUM_MEM_BLOCKS, MEM_BLOCK_SIZE)];
+
+/* Array of block pointers. */
+void *block_array[MEMPOOL_TEST_MAX_BLOCKS];
+
+int verbose = 0;
+
+static int
+mempool_test_get_pool_size(int num_blocks, int block_size)
+{
+    int mem_pool_size;
+
+#if OS_CFG_ALIGNMENT == OS_CFG_ALIGN_4
+    mem_pool_size = (num_blocks * ((block_size + 3)/4) * sizeof(os_membuf_t));
+#else
+    mem_pool_size = (num_blocks * ((block_size + 7)/8) * sizeof(os_membuf_t));
+#endif
+
+    return mem_pool_size;
+}
+
+static void
+mempool_test(int num_blocks, int block_size)
+{
+    int cnt;
+    int true_block_size;
+    int mem_pool_size;
+    uint8_t *tstptr;
+    void **free_ptr;
+    void *block;
+    os_error_t rc;
+
+    /* Check for too many blocks */
+    TEST_ASSERT(num_blocks <= MEMPOOL_TEST_MAX_BLOCKS);
+
+    rc = os_mempool_init(&g_TstMempool, num_blocks, MEM_BLOCK_SIZE, 
+                         &TstMembuf[0], "TestMemPool");
+    TEST_ASSERT_FATAL(rc == 0, "Error creating memory pool %d", rc);
+
+    TEST_ASSERT(g_TstMempool.mp_num_free == num_blocks,
+                "Number of free blocks not equal to total blocks!");
+
+    TEST_ASSERT(SLIST_FIRST(&g_TstMempool) == (void *)&TstMembuf[0],
+                "Free list pointer does not point to first block!");
+
+    mem_pool_size = mempool_test_get_pool_size(num_blocks, block_size);
+    TEST_ASSERT(mem_pool_size == sizeof(TstMembuf),
+                "Total memory pool size not correct! (%d vs %lu)",
+                mem_pool_size, (unsigned long)sizeof(TstMembuf));
+
+    /* Get the real block size */
+#if (OS_CFG_ALIGNMENT == OS_CFG_ALIGN_4)
+    true_block_size = (g_TstMempool.mp_block_size + 3) & ~3;
+#else
+    true_block_size = (g_TstMempool.mp_block_size + 7) & ~7;
+#endif
+
+    /* Traverse free list. Better add up to number of blocks! */
+    cnt = 0;
+    free_ptr = (void **)&TstMembuf;
+    tstptr = (uint8_t *)&TstMembuf;
+    while (1) {
+        /* Increment # of elements by 1 */
+        ++cnt;
+
+        /* If the free list is NULL, leave */
+        if (*free_ptr == NULL) {
+            break;
+        }
+
+        TEST_ASSERT(((uint8_t *)*free_ptr - (uint8_t *)free_ptr) ==
+                        true_block_size,
+                    "Free pointers are more than one block apart!");
+
+        /* Move to next memory block */
+        tstptr += true_block_size;
+
+        TEST_ASSERT(*free_ptr == (void *)tstptr,
+                    "Error: free_ptr=%p testptr=%p\n", *free_ptr, tstptr);
+
+        free_ptr = *free_ptr;
+    }
+
+    /* Last one in list better be NULL */
+    TEST_ASSERT(cnt == g_TstMempool.mp_num_blocks,
+                "Free list contains too many elements (%u)", cnt);
+
+    /* Get a block */
+    block = os_memblock_get(&g_TstMempool);
+    TEST_ASSERT(block != NULL,
+                "Error: get block fails when pool should have elements");
+
+    TEST_ASSERT(g_TstMempool.mp_num_free == (num_blocks-1),
+                "Number of free blocks incorrect (%u vs %u)",
+                g_TstMempool.mp_num_free, (num_blocks-1));
+
+    /* Put back the block */
+    rc = os_memblock_put(&g_TstMempool, block);
+    TEST_ASSERT(rc == 0, "Put block fails with error code=%d\n", rc);
+
+    TEST_ASSERT(g_TstMempool.mp_num_free == num_blocks,
+                "Number of free blocks incorrect (%u vs %u)",
+                g_TstMempool.mp_num_free, num_blocks);
+
+    /* remove all the blocks. Make sure we get count. */
+    memset(block_array, 0, sizeof(block_array));
+    cnt = 0;
+    while (1) {
+        block = os_memblock_get(&g_TstMempool);
+        if (block == NULL) {
+            break;
+        }
+        block_array[cnt] = block;
+        ++cnt;
+        if (cnt == MEMPOOL_TEST_MAX_BLOCKS) {
+            break;
+        }
+    }
+
+    TEST_ASSERT((cnt == g_TstMempool.mp_num_blocks) && 
+                (cnt != MEMPOOL_TEST_MAX_BLOCKS),
+                "Got more blocks than mempool contains (%d vs %d)",
+                cnt, g_TstMempool.mp_num_blocks);
+
+    /* Better be no free blocks left! */
+    TEST_ASSERT(g_TstMempool.mp_num_free == 0,
+                "Got all blocks but number free not zero! (%d)",
+                g_TstMempool.mp_num_free);
+
+    /* Now put them all back */
+    for (cnt = 0; cnt < g_TstMempool.mp_num_blocks; ++cnt) {
+        rc = os_memblock_put(&g_TstMempool, block_array[cnt]);
+        TEST_ASSERT(rc == 0,
+                    "Error putting back block %p (cnt=%d err=%d)", 
+                    block_array[cnt], cnt, rc);
+    }
+
+    /* Better be no free blocks left! */
+    TEST_ASSERT(g_TstMempool.mp_num_free == g_TstMempool.mp_num_blocks,
+                "Put all blocks but number free not equal to total!");
+
+    /* Better get error when we try these things! */
+    rc = os_memblock_put(NULL, block_array[0]);
+    TEST_ASSERT(rc != 0,
+                "Should have got an error trying to put to null pool");
+
+    rc = os_memblock_put(&g_TstMempool, NULL);
+    TEST_ASSERT(rc != 0, "No error trying to put to NULL block");
+
+    TEST_ASSERT(os_memblock_get(NULL) == NULL,
+                "No error trying to get a block from NULL pool");
+}
+
+/**
+ * os mempool test 
+ *  
+ * Main test loop for memory pool testing. 
+ * 
+ * @return int 
+ */
+TEST_CASE(os_mempool_test_case)
+{
+    mempool_test(NUM_MEM_BLOCKS, MEM_BLOCK_SIZE);
+}
+
+TEST_SUITE(os_mempool_test_suite)
+{
+    os_mempool_test_case();
+}
diff --git a/libs/os/src/test/mutex_test.c b/libs/os/src/test/mutex_test.c
new file mode 100644
index 0000000..6d34244
--- /dev/null
+++ b/libs/os/src/test/mutex_test.c
@@ -0,0 +1,397 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/time.h>
+#include "testutil/testutil.h"
+#include "os/os.h"
+#include "os/os_test.h"
+#include "os/os_cfg.h"
+#include "os/os_mutex.h"
+#include "os_test_priv.h"
+
+#if ARCH == sim 
+#define MUTEX_TEST_STACK_SIZE   1024
+#else
+#define MUTEX_TEST_STACK_SIZE   256
+#endif
+
+struct os_task task14;
+os_stack_t stack14[OS_STACK_ALIGN(MUTEX_TEST_STACK_SIZE)];
+
+struct os_task task15;
+os_stack_t stack15[OS_STACK_ALIGN(MUTEX_TEST_STACK_SIZE)];
+
+struct os_task task16;
+os_stack_t stack16[OS_STACK_ALIGN(MUTEX_TEST_STACK_SIZE)];
+
+struct os_task task17;
+os_stack_t stack17[OS_STACK_ALIGN(MUTEX_TEST_STACK_SIZE)];
+
+#define TASK14_PRIO (4)
+#define TASK15_PRIO (5)
+#define TASK16_PRIO (6)
+#define TASK17_PRIO (7)
+
+volatile int g_task14_val;
+volatile int g_task15_val;
+volatile int g_task16_val;
+volatile int g_task17_val;
+struct os_mutex g_mutex1;
+struct os_mutex g_mutex2;
+
+static volatile int g_mutex_test;
+
+/**
+ * mutex test basic 
+ *  
+ * Basic mutex tests
+ * 
+ * @return int 
+ */
+static void
+mutex_test_basic_handler(void *arg)
+{
+    struct os_mutex *mu;
+    struct os_task *t;
+    os_error_t err;
+
+    mu = &g_mutex1;
+    t = os_sched_get_current_task();
+
+    /* Test some error cases */
+    TEST_ASSERT(os_mutex_init(NULL)     == OS_INVALID_PARM);
+    TEST_ASSERT(os_mutex_delete(NULL)   == OS_INVALID_PARM);
+    TEST_ASSERT(os_mutex_release(NULL)  == OS_INVALID_PARM);
+    TEST_ASSERT(os_mutex_pend(NULL, 0)  == OS_INVALID_PARM);
+
+    /* Get the mutex */
+    err = os_mutex_pend(mu, 0);
+    TEST_ASSERT(err == 0,
+                "Did not get free mutex immediately (err=%d)", err);
+
+    /* Check mutex internals */
+    TEST_ASSERT(mu->mu_owner == t && mu->mu_level == 1 &&
+                mu->mu_prio == t->t_prio && SLIST_EMPTY(&mu->mu_head),
+                "Mutex internals not correct after getting mutex\n"
+                "Mutex: owner=%p prio=%u level=%u head=%p\n"
+                "Task: task=%p prio=%u",
+                mu->mu_owner, mu->mu_prio, mu->mu_level, 
+                SLIST_FIRST(&mu->mu_head),
+                t, t->t_prio);
+
+    /* Get the mutex again; should be level 2 */
+    err = os_mutex_pend(mu, 0);
+    TEST_ASSERT(err == 0, "Did not get my mutex immediately (err=%d)", err);
+
+    /* Check mutex internals */
+    TEST_ASSERT(mu->mu_owner == t && mu->mu_level == 2 &&
+                mu->mu_prio == t->t_prio && SLIST_EMPTY(&mu->mu_head),
+                "Mutex internals not correct after getting mutex\n"
+                "Mutex: owner=%p prio=%u level=%u head=%p\n"
+                "Task: task=%p prio=%u",
+                mu->mu_owner, mu->mu_prio, mu->mu_level, 
+                SLIST_FIRST(&mu->mu_head), t, t->t_prio);
+
+    /* Release mutex */
+    err = os_mutex_release(mu);
+    TEST_ASSERT(err == 0, "Could not release mutex I own (err=%d)", err);
+
+    /* Check mutex internals */
+    TEST_ASSERT(mu->mu_owner == t && mu->mu_level == 1 &&
+                mu->mu_prio == t->t_prio && SLIST_EMPTY(&mu->mu_head),
+                "Error: mutex internals not correct after getting mutex\n"
+                "Mutex: owner=%p prio=%u level=%u head=%p\n"
+                "Task: task=%p prio=%u",
+                mu->mu_owner, mu->mu_prio, mu->mu_level, 
+                SLIST_FIRST(&mu->mu_head), t, t->t_prio);
+
+    /* Release it again */
+    err = os_mutex_release(mu);
+    TEST_ASSERT(err == 0, "Could not release mutex I own (err=%d)", err);
+
+    /* Check mutex internals */
+    TEST_ASSERT(mu->mu_owner == NULL && mu->mu_level == 0 &&
+                mu->mu_prio == t->t_prio && SLIST_EMPTY(&mu->mu_head),
+                "Mutex internals not correct after getting mutex\n"
+                "Mutex: owner=%p prio=%u level=%u head=%p\n"
+                "Task: task=%p prio=%u",
+                mu->mu_owner, mu->mu_prio, mu->mu_level, 
+                SLIST_FIRST(&mu->mu_head), t, t->t_prio);
+
+    os_test_restart();
+}
+
+static void 
+mutex_test1_task14_handler(void *arg)
+{
+    os_error_t err;
+    struct os_task *t;
+    int iters;
+
+    t = os_sched_get_current_task();
+    TEST_ASSERT(t->t_func == mutex_test1_task14_handler);
+
+    for (iters = 0; iters < 3; iters++) {
+        os_time_delay(100);
+
+        g_task14_val = 1;
+
+        err = os_mutex_pend(&g_mutex1, 100);
+        TEST_ASSERT(err == OS_OK);
+        TEST_ASSERT(g_task16_val == 1);
+
+        os_time_delay(100);
+    }
+
+    os_test_restart();
+}
+
+static void 
+mutex_test2_task14_handler(void *arg)
+{
+    os_error_t err;
+    struct os_task *t;
+    int iters;
+
+    t = os_sched_get_current_task();
+    TEST_ASSERT(t->t_func == mutex_test2_task14_handler);
+
+    for (iters = 0; iters < 3; iters++) {
+        err = os_mutex_pend(&g_mutex1, 0);
+        TEST_ASSERT(err == OS_OK, "err=%d", err);
+
+        g_task14_val = 1;
+        os_time_delay(100);
+
+        if (g_mutex_test == 4) {
+            os_mutex_delete(&g_mutex1);
+            os_time_delay(150);
+        }
+
+        os_mutex_release(&g_mutex1);
+        os_time_delay(100);
+    }
+
+    os_test_restart();
+}
+
+static void 
+task15_handler(void *arg) 
+{
+    os_error_t err;
+    struct os_task *t;
+
+    if (g_mutex_test == 1) {
+        while (1) {
+            t = os_sched_get_current_task();
+            TEST_ASSERT(t->t_func == task15_handler);
+
+            os_time_delay(50);
+            while (1) {
+                /* Wait here forever */
+            }
+        }
+    } else {
+        if (g_mutex_test == 2) {
+            /* Sleep for 3 seconds */
+            t = os_sched_get_current_task();
+            os_time_delay(500);
+        } else if (g_mutex_test == 3) {
+            /* Sleep for 3 seconds */
+            t = os_sched_get_current_task();
+            os_time_delay(30);
+        }
+
+        while (1) {
+            t = os_sched_get_current_task();
+            TEST_ASSERT(t->t_func == task15_handler);
+
+            err = os_mutex_pend(&g_mutex1, 10000);
+            if (g_mutex_test == 4) {
+                TEST_ASSERT(err == OS_TIMEOUT);
+            } else {
+                TEST_ASSERT(err == OS_OK);
+            }
+
+            os_time_delay(100);
+        }
+    }
+}
+
+static void 
+task16_handler(void *arg) 
+{
+    os_error_t err;
+    struct os_task *t;
+
+    if (g_mutex_test == 1) {
+        while (1) {
+            t = os_sched_get_current_task();
+            TEST_ASSERT(t->t_func == task16_handler);
+
+            /* Get mutex 1 */
+            err = os_mutex_pend(&g_mutex1, 0xFFFFFFFF);
+            TEST_ASSERT(err == OS_OK);
+
+            while (g_task14_val != 1) {
+                /* Wait till task 1 wakes up and sets val. */
+            }
+
+            g_task16_val = 1;
+
+            err = os_mutex_release(&g_mutex1);
+            TEST_ASSERT(err == OS_OK);
+        }
+    } else {
+        if (g_mutex_test == 2) {
+            /* Sleep for 3 seconds */
+            t = os_sched_get_current_task();
+            os_time_delay(30);
+        } else if (g_mutex_test == 3) {
+            /* Sleep for 3 seconds */
+            t = os_sched_get_current_task();
+            os_time_delay(50);
+        }
+
+        while (1) {
+            t = os_sched_get_current_task();
+            TEST_ASSERT(t->t_func == task16_handler);
+
+            err = os_mutex_pend(&g_mutex1, 10000);
+            if (g_mutex_test == 4) {
+                TEST_ASSERT(err == OS_TIMEOUT);
+            } else {
+                TEST_ASSERT(err == OS_OK);
+            }
+
+            if (err == OS_OK) {
+                err = os_mutex_release(&g_mutex1);
+                TEST_ASSERT(err == OS_OK);
+            }
+
+            os_time_delay(10000);
+        }
+    }
+}
+
+static void 
+task17_handler(void *arg)
+{
+    os_error_t err;
+    struct os_task *t;
+
+    while (1) {
+        t = os_sched_get_current_task();
+        TEST_ASSERT(t->t_func == task17_handler);
+
+        if (g_mutex_test == 5) {
+            err = os_mutex_pend(&g_mutex1, 10);
+        } else {
+            err = os_mutex_pend(&g_mutex1, 10000);
+        }
+
+        if (g_mutex_test == 4 || g_mutex_test == 5) {
+            TEST_ASSERT(err == OS_TIMEOUT);
+        } else {
+            TEST_ASSERT(err == OS_OK);
+        }
+
+        if (err == OS_OK) {
+            err = os_mutex_release(&g_mutex1);
+            TEST_ASSERT(err == OS_OK);
+        }
+
+        os_time_delay(10000);
+    }
+}
+
+TEST_CASE(os_mutex_test_basic)
+{
+    os_init();
+
+    os_mutex_init(&g_mutex1);
+
+    os_task_init(&task14, "task14", mutex_test_basic_handler, NULL,
+                 TASK14_PRIO, OS_WAIT_FOREVER, stack14,
+                 OS_STACK_ALIGN(MUTEX_TEST_STACK_SIZE));
+
+    os_start();
+}
+
+TEST_CASE(os_mutex_test_case_1)
+{
+    int rc;
+
+    os_init();
+
+    g_mutex_test = 1;
+    g_task14_val = 0;
+    g_task15_val = 0;
+    g_task16_val = 0;
+
+    rc = os_mutex_init(&g_mutex1);
+    TEST_ASSERT(rc == 0);
+    rc = os_mutex_init(&g_mutex2);
+    TEST_ASSERT(rc == 0);
+
+    os_task_init(&task14, "task14", mutex_test1_task14_handler, NULL,
+                 TASK14_PRIO, OS_WAIT_FOREVER, stack14,
+                 OS_STACK_ALIGN(MUTEX_TEST_STACK_SIZE));
+
+    os_task_init(&task15, "task15", task15_handler, NULL, TASK15_PRIO, 
+            OS_WAIT_FOREVER, stack15, OS_STACK_ALIGN(MUTEX_TEST_STACK_SIZE));
+
+    os_task_init(&task16, "task16", task16_handler, NULL, TASK16_PRIO, 
+            OS_WAIT_FOREVER, stack16, OS_STACK_ALIGN(MUTEX_TEST_STACK_SIZE));
+
+    os_start();
+}
+
+TEST_CASE(os_mutex_test_case_2)
+{
+    os_init();
+
+    g_mutex_test = 2;
+    g_task14_val = 0;
+    g_task15_val = 0;
+    g_task16_val = 0;
+    os_mutex_init(&g_mutex1);
+    os_mutex_init(&g_mutex2);
+
+    os_task_init(&task14, "task14", mutex_test2_task14_handler, NULL,
+                 TASK14_PRIO, OS_WAIT_FOREVER, stack14,
+                 OS_STACK_ALIGN(MUTEX_TEST_STACK_SIZE));
+
+    os_task_init(&task15, "task15", task15_handler, NULL, TASK15_PRIO, 
+            OS_WAIT_FOREVER, stack15, OS_STACK_ALIGN(MUTEX_TEST_STACK_SIZE));
+
+    os_task_init(&task16, "task16", task16_handler, NULL, TASK16_PRIO, 
+            OS_WAIT_FOREVER, stack16, OS_STACK_ALIGN(MUTEX_TEST_STACK_SIZE));
+
+    os_task_init(&task17, "task17", task17_handler, NULL, TASK17_PRIO, 
+            OS_WAIT_FOREVER, stack17, OS_STACK_ALIGN(MUTEX_TEST_STACK_SIZE));
+ 
+    os_start();
+}
+
+TEST_SUITE(os_mutex_test_suite)
+{
+    os_mutex_test_basic();
+    os_mutex_test_case_1();
+    os_mutex_test_case_2();
+}
diff --git a/libs/os/src/test/os_test.c b/libs/os/src/test/os_test.c
new file mode 100644
index 0000000..2534707
--- /dev/null
+++ b/libs/os/src/test/os_test.c
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include "testutil/testutil.h"
+#include "os/os_test.h"
+#include "os_test_priv.h"
+
+int
+os_test_all(void)
+{
+    os_mempool_test_suite();
+    os_mutex_test_suite();
+    os_sem_test_suite();
+    os_mbuf_test_suite();
+
+    return tu_case_failed;
+}
+
+#ifdef PKG_TEST
+
+int
+main(int argc, char **argv)
+{
+    tu_config.tc_print_results = 1;
+    tu_init();
+
+    os_test_all();
+
+    return tu_any_failed;
+}
+
+#endif
diff --git a/libs/os/src/test/os_test_priv.h b/libs/os/src/test/os_test_priv.h
new file mode 100644
index 0000000..1486c98
--- /dev/null
+++ b/libs/os/src/test/os_test_priv.h
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef H_OS_TEST_PRIV_
+#define H_OS_TEST_PRIV_
+
+void os_test_restart(void);
+
+int os_mempool_test_suite(void);
+int os_mbuf_test_suite(void);
+int os_mutex_test_suite(void);
+int os_sem_test_suite(void);
+
+#endif
diff --git a/libs/os/src/test/sem_test.c b/libs/os/src/test/sem_test.c
new file mode 100644
index 0000000..a27fc95
--- /dev/null
+++ b/libs/os/src/test/sem_test.c
@@ -0,0 +1,411 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <stdio.h>
+#include <string.h>
+#include "testutil/testutil.h"
+#include "os/os.h"
+#include "os/os_cfg.h"
+#include "os/os_sem.h"
+#include "os_test_priv.h"
+
+#if ARCH == sim
+#define SEM_TEST_STACK_SIZE     1024
+#else 
+#define SEM_TEST_STACK_SIZE     512
+#endif
+
+struct os_task task1;
+os_stack_t stack1[OS_STACK_ALIGN(SEM_TEST_STACK_SIZE)];
+
+struct os_task task2;
+os_stack_t stack2[OS_STACK_ALIGN(SEM_TEST_STACK_SIZE)];
+
+struct os_task task3;
+os_stack_t stack3[OS_STACK_ALIGN(SEM_TEST_STACK_SIZE)];
+
+struct os_task task4;
+os_stack_t stack4[OS_STACK_ALIGN(SEM_TEST_STACK_SIZE)];
+
+#define TASK1_PRIO (1) 
+#define TASK2_PRIO (2) 
+#define TASK3_PRIO (3) 
+#define TASK4_PRIO (4) 
+
+struct os_sem g_sem1;
+
+/* 
+ * TEST NUMBERS:
+ *  10: In this test we have the highest priority task getting the semaphore
+ *  then sleeping. Two lower priority tasks then wake up and attempt to get
+ *  the semaphore. They are blocked until the higher priority task releases
+ *  the semaphore, at which point the lower priority tasks should wake up in
+ *  order, get the semaphore, then release it and go back to sleep.
+ * 
+ */
+
+/**
+ * sem test disp sem
+ *  
+ * Display semaphore contents 
+ * 
+ * @param sem 
+ */
+static const char *
+sem_test_sem_to_s(const struct os_sem *sem)
+{
+    static char buf[128];
+
+    snprintf(buf, sizeof buf, "\tSemaphore: tokens=%u head=%p",
+             sem->sem_tokens, SLIST_FIRST(&sem->sem_head));
+
+    return buf;
+}
+
+static void 
+sem_test_sleep_task_handler(void *arg)
+{
+    struct os_task *t;
+
+    t = os_sched_get_current_task();
+    TEST_ASSERT(t->t_func == sem_test_sleep_task_handler);
+
+    os_time_delay(2000);
+    os_test_restart();
+}
+
+static void
+sem_test_pend_release_loop(int delay, int timeout, int itvl)
+{
+    os_error_t err;
+
+    os_time_delay(delay);
+
+    while (1) {
+        err = os_sem_pend(&g_sem1, timeout);
+        TEST_ASSERT(err == OS_OK);
+
+        err = os_sem_release(&g_sem1);
+        TEST_ASSERT(err == OS_OK);
+
+        os_time_delay(itvl);
+    }
+}
+
+/**
+ * sem test basic 
+ *  
+ * Basic semaphore tests
+ * 
+ * @return int 
+ */
+static void 
+sem_test_basic_handler(void *arg)
+{
+    struct os_task *t;
+    struct os_sem *sem;
+    os_error_t err;
+
+    sem = &g_sem1;
+    t = os_sched_get_current_task();
+
+    /* Test some error cases */
+    TEST_ASSERT(os_sem_init(NULL, 1)    == OS_INVALID_PARM);
+    TEST_ASSERT(os_sem_delete(NULL)     == OS_INVALID_PARM);
+    TEST_ASSERT(os_sem_release(NULL)    == OS_INVALID_PARM);
+    TEST_ASSERT(os_sem_pend(NULL, 1)    == OS_INVALID_PARM);
+
+    /* Get the semaphore */
+    err = os_sem_pend(sem, 0);
+    TEST_ASSERT(err == 0,
+                "Did not get free semaphore immediately (err=%d)", err);
+
+    /* Check semaphore internals */
+    TEST_ASSERT(sem->sem_tokens == 0 && SLIST_EMPTY(&sem->sem_head),
+                "Semaphore internals wrong after getting semaphore\n"
+                "%s\n"
+                "Task: task=%p prio=%u", sem_test_sem_to_s(sem), t, t->t_prio);
+
+    /* Get the semaphore again; should fail */
+    err = os_sem_pend(sem, 0);
+    TEST_ASSERT(err == OS_TIMEOUT,
+                "Did not time out waiting for semaphore (err=%d)", err);
+
+    /* Check semaphore internals */
+    TEST_ASSERT(sem->sem_tokens == 0 && SLIST_EMPTY(&sem->sem_head),
+                "Semaphore internals wrong after getting semaphore\n"
+                "%s\n"
+                "Task: task=%p prio=%u\n", sem_test_sem_to_s(sem), t,
+                t->t_prio);
+
+    /* Release semaphore */
+    err = os_sem_release(sem);
+    TEST_ASSERT(err == 0,
+                "Could not release semaphore I own (err=%d)", err);
+
+    /* Check semaphore internals */
+    TEST_ASSERT(sem->sem_tokens == 1 && SLIST_EMPTY(&sem->sem_head),
+                "Semaphore internals wrong after releasing semaphore\n"
+                "%s\n"
+                "Task: task=%p prio=%u\n", sem_test_sem_to_s(sem), t,
+                t->t_prio);
+
+    /* Release it again */
+    err = os_sem_release(sem);
+    TEST_ASSERT(err == 0,
+                "Could not release semaphore again (err=%d)\n", err);
+
+    /* Check semaphore internals */
+    TEST_ASSERT(sem->sem_tokens == 2 && SLIST_EMPTY(&sem->sem_head),
+                "Semaphore internals wrong after releasing semaphore\n"
+                "%s\n"
+                "Task: task=%p prio=%u\n", sem_test_sem_to_s(sem), t,
+                t->t_prio);
+
+    /* "Delete" it */
+    err = os_sem_delete(sem);
+    TEST_ASSERT(err == 0,
+                "Could not delete semaphore (err=%d)", err);
+
+    /* Check semaphore internals */
+    TEST_ASSERT(sem->sem_tokens == 0 && SLIST_EMPTY(&sem->sem_head),
+                "Semaphore internals wrong after deleting semaphore\n"
+                "%s\n"
+                "Task: task=%p prio=%u\n", sem_test_sem_to_s(sem), t,
+                t->t_prio);
+
+    os_test_restart();
+}
+
+static void 
+sem_test_1_task1_handler(void *arg)
+{
+    os_error_t err;
+    struct os_task *t;
+    int i;;
+
+    for (i = 0; i < 3; i++) {
+        t = os_sched_get_current_task();
+        TEST_ASSERT(t->t_func == sem_test_1_task1_handler);
+
+
+        err = os_sem_pend(&g_sem1, 0);
+        TEST_ASSERT(err == OS_OK);
+
+        /* Sleep to let other tasks run */
+        os_time_delay(100);
+
+        /* Release the semaphore */
+        err = os_sem_release(&g_sem1);
+        TEST_ASSERT(err == OS_OK);
+
+        /* Sleep to let other tasks run */
+        os_time_delay(100);
+    }
+
+    os_test_restart();
+}
+
+TEST_CASE(os_sem_test_basic)
+{
+    os_error_t err;
+
+    os_init();
+
+    err = os_sem_init(&g_sem1, 1);
+    TEST_ASSERT(err == OS_OK);
+
+    os_task_init(&task1, "task1", sem_test_basic_handler, NULL, TASK1_PRIO, 
+            OS_WAIT_FOREVER, stack1, OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+    os_start();
+}
+
+static void 
+sem_test_1_task2_handler(void *arg) 
+{
+    sem_test_pend_release_loop(0, 100, 100);
+}
+
+static void 
+sem_test_1_task3_handler(void *arg) 
+{
+    sem_test_pend_release_loop(0, OS_TIMEOUT_NEVER, 2000);
+}
+
+TEST_CASE(os_sem_test_case_1)
+{
+    os_error_t err;
+
+    os_init();
+
+    err = os_sem_init(&g_sem1, 1);
+    TEST_ASSERT(err == OS_OK);
+
+    os_task_init(&task1, "task1", sem_test_1_task1_handler, NULL,
+                 TASK1_PRIO, OS_WAIT_FOREVER, stack1,
+                 OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+    os_task_init(&task2, "task2", sem_test_1_task2_handler, NULL,
+                 TASK2_PRIO, OS_WAIT_FOREVER, stack2,
+                 OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+    os_task_init(&task3, "task3", sem_test_1_task3_handler, NULL, TASK3_PRIO, 
+                 OS_WAIT_FOREVER, stack3, OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+    os_start();
+}
+
+static void 
+sem_test_2_task2_handler(void *arg) 
+{
+    sem_test_pend_release_loop(0, 2000, 2000);
+}
+
+static void 
+sem_test_2_task3_handler(void *arg) 
+{
+    sem_test_pend_release_loop(0, OS_TIMEOUT_NEVER, 2000);
+}
+
+static void 
+sem_test_2_task4_handler(void *arg) 
+{
+    sem_test_pend_release_loop(0, 2000, 2000);
+}
+
+TEST_CASE(os_sem_test_case_2)
+{
+    os_error_t err;
+
+    os_init();
+
+    err = os_sem_init(&g_sem1, 1);
+    TEST_ASSERT(err == OS_OK);
+
+    os_task_init(&task1, "task1", sem_test_sleep_task_handler, NULL,
+                 TASK1_PRIO, OS_WAIT_FOREVER, stack1,
+                 OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+    os_task_init(&task2, "task2", sem_test_2_task2_handler, NULL,
+                 TASK2_PRIO, OS_WAIT_FOREVER, stack2,
+                 OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+    os_task_init(&task3, "task3", sem_test_2_task3_handler, NULL, TASK3_PRIO,
+            OS_WAIT_FOREVER, stack3, OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+    os_task_init(&task4, "task4", sem_test_2_task4_handler, NULL, TASK4_PRIO,
+            OS_WAIT_FOREVER, stack4, OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+    os_start();
+}
+
+static void 
+sem_test_3_task2_handler(void *arg) 
+{
+    sem_test_pend_release_loop(100, 2000, 2000);
+}
+
+static void 
+sem_test_3_task3_handler(void *arg) 
+{
+    sem_test_pend_release_loop(150, 2000, 2000);
+}
+
+static void 
+sem_test_3_task4_handler(void *arg) 
+{
+    sem_test_pend_release_loop(0, 2000, 2000);
+}
+
+TEST_CASE(os_sem_test_case_3)
+{
+    os_error_t err;
+
+    os_init();
+
+    err = os_sem_init(&g_sem1, 1);
+    TEST_ASSERT(err == OS_OK);
+
+    os_task_init(&task1, "task1", sem_test_sleep_task_handler, NULL,
+                 TASK1_PRIO, OS_WAIT_FOREVER, stack1,
+                 OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+    os_task_init(&task2, "task2", sem_test_3_task2_handler, NULL,
+                 TASK2_PRIO, OS_WAIT_FOREVER, stack2,
+                 OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+    os_task_init(&task3, "task3", sem_test_3_task3_handler, NULL, TASK3_PRIO,
+            OS_WAIT_FOREVER, stack3, OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+    os_task_init(&task4, "task4", sem_test_3_task4_handler, NULL, TASK4_PRIO,
+            OS_WAIT_FOREVER, stack4, OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+    os_start();
+}
+
+static void 
+sem_test_4_task2_handler(void *arg) 
+{
+    sem_test_pend_release_loop(60, 2000, 2000);
+}
+
+static void 
+sem_test_4_task3_handler(void *arg) 
+{
+    sem_test_pend_release_loop(60, 2000, 2000);
+}
+
+static void 
+sem_test_4_task4_handler(void *arg) 
+{
+    sem_test_pend_release_loop(0, 2000, 2000);
+}
+
+
+TEST_CASE(os_sem_test_case_4)
+{
+    os_error_t err;
+
+    os_init();
+
+    err = os_sem_init(&g_sem1, 1);
+    TEST_ASSERT(err == OS_OK);
+
+    os_task_init(&task1, "task1", sem_test_sleep_task_handler, NULL,
+                 TASK1_PRIO, OS_WAIT_FOREVER, stack1,
+                 OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+    os_task_init(&task2, "task2", sem_test_4_task2_handler, NULL,
+                 TASK2_PRIO, OS_WAIT_FOREVER, stack2,
+                 OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+    os_task_init(&task3, "task3", sem_test_4_task3_handler, NULL, TASK3_PRIO,
+                 OS_WAIT_FOREVER, stack3, OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+    os_task_init(&task4, "task4", sem_test_4_task4_handler, NULL, TASK4_PRIO,
+                 OS_WAIT_FOREVER, stack4, OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+    os_start();
+}
+
+TEST_SUITE(os_sem_test_suite)
+{
+    os_sem_test_basic();
+    os_sem_test_case_1();
+    os_sem_test_case_2();
+    os_sem_test_case_3();
+    os_sem_test_case_4();
+}
diff --git a/repo.yml b/repo.yml
new file mode 100644
index 0000000..356ff6e
--- /dev/null
+++ b/repo.yml
@@ -0,0 +1 @@
+repo.name: "tadpole"