Repository: nasa/fprime (language: python)

Issue:
Refactor Os::SystemResources into CMake Selection
| | |
|:---|:---|
|**_F´ Version_**| |
|**_Affected Component_**|  |
---
## Feature Description

- [ ] Refactor Os::Log into the Interface, Os::Log, and Implementation classes (following pattern of Os::File)
- [ ] Implement Posix implementation
- [ ] Implement Stub implementation
- [ ] Implement Test stub implementation
- [ ] Build common rules-based tests
- [ ] Build specific posix tests
- [ ] Build stub interface tests
- [ ] Setup default posix implementation for Posix platforms
- [ ] Document

Refactor Os::SystemResources into CMake Selection
| | |
|:---|:---|
|**_F´ Version_**| |
|**_Affected Component_**|  |
---
## Feature Description

- [ ] Refactor Os::Log into the Interface, Os::Log, and Implementation classes (following pattern of Os::File)
- [ ] Implement Posix implementation
- [ ] Implement Stub implementation
- [ ] Implement Test stub implementation
- [ ] Build common rules-based tests
- [ ] Build specific posix tests
- [ ] Build stub interface tests
- [ ] Setup default posix implementation for Posix platforms
- [ ] Document



Discussion / hints:
Note: 
-> use singleton pattern in the "face" class (`class SystemResources final : public SystemResourcesInterface {` to which the static methods delegate to the singleton
@kevin-f-ortega reassigning this to me. 
Note: 
-> use singleton pattern in the "face" class (`class SystemResources final : public SystemResourcesInterface {` to which the static methods delegate to the singleton
@kevin-f-ortega reassigning this to me. 

Fix patch:
diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt
index bbfd7efaa7..1484ddc04d 100644
--- a/.github/actions/spelling/expect.txt
+++ b/.github/actions/spelling/expect.txt
@@ -686,6 +686,7 @@ notchars
 NOTYPE
 Nowicki
 nproc
+NPROCESSORS
 npx
 NSHUFF
 NSPACES
@@ -707,6 +708,7 @@ oldeol
 OLDINCLUDEDIR
 OMG
 onlinepubs
+ONLN
 OPCODEBASE
 opengroup
 openmct
@@ -758,6 +760,7 @@ pcmake
 pcomp
 pdflatex
 Peet
+penv
 PERLMOD
 PINGSEND
 pinit
@@ -954,6 +957,7 @@ Shenker
 showinitializer
 sideeffect
 sighandler
+Signedness
 SIMPLEQUEUEREGISTRY
 sinc
 Sinha
@@ -1095,6 +1099,7 @@ TIMERVAL
 timetag
 timeval
 timothycanham
+Tinternal
 tions
 tjh
 TKC
diff --git a/CMakePresets.json b/CMakePresets.json
new file mode 100644
index 0000000000..93f1aed6aa
--- /dev/null
+++ b/CMakePresets.json
@@ -0,0 +1,60 @@
+{
+    "version": 4,
+    "configurePresets": [
+    {
+      "name": "fprime",
+      "displayName": "F´ Release Preset",
+      "description": "F´ release build using local fprime-venv",
+      "binaryDir": "${sourceDir}/build-fprime-automatic-native",
+      "environment": {
+        "VIRTUAL_ENV": "${fileDir}/fprime-venv",
+        "PATH": "$env{VIRTUAL_ENV}/bin:$penv{PATH}"
+      },
+      "cacheVariables": {
+          "CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
+          "CMAKE_BUILD_TYPE": "Release"
+      }
+    },
+    {
+      "name": "fprime-debug",
+      "inherits": "fprime",
+      "displayName": "F´ Debug Preset",
+      "description": "F´ debug build using local fprime-venv",
+      "cacheVariables": {
+          "CMAKE_BUILD_TYPE": "Debug"
+      }
+    },
+    {
+      "name": "fprime-ut",
+      "inherits": "fprime-debug",
+      "displayName": "F´ Unit Test Preset",
+      "description": "F´ debug build including unit tests using local fprime-venv",
+      "binaryDir": "${sourceDir}/build-fprime-automatic-native-ut",
+      "cacheVariables": {
+          "BUILD_TESTING": "ON"
+      }
+    },
+      {
+        "name": "fprime-ninja",
+        "inherits": "fprime",
+        "displayName": "F´ Release (Ninja) Preset",
+        "description": "F´ release build using ninja and local fprime-venv",
+        "generator": "Ninja"
+      },
+      {
+        "name": "fprime-debug-ninja",
+        "inherits": "fprime-debug",
+        "displayName": "F´ Debug (Ninja) Preset",
+        "description": "F´ debug build using ninja and local fprime-venv",
+        "generator": "Ninja"
+      },
+      {
+        "name": "fprime-ut-ninja",
+        "inherits": "fprime-ut",
+        "displayName": "F´ Unit Test (Ninja) Preset",
+        "description": "F´ debug build including unit tests using ninja and local fprime-venv",
+        "binaryDir": "${sourceDir}/build-fprime-automatic-native-ut",
+        "generator": "Ninja"
+      }
+    ]
+}
diff --git a/Fw/Types/CMakeLists.txt b/Fw/Types/CMakeLists.txt
index a187ffa660..0d1fc3c273 100644
--- a/Fw/Types/CMakeLists.txt
+++ b/Fw/Types/CMakeLists.txt
@@ -16,6 +16,7 @@ set(SOURCE_FILES
   "${CMAKE_CURRENT_LIST_DIR}/Serializable.cpp"
   "${CMAKE_CURRENT_LIST_DIR}/StringBase.cpp"
   "${CMAKE_CURRENT_LIST_DIR}/StringUtils.cpp"
+  "${CMAKE_CURRENT_LIST_DIR}/StringToNumber.cpp"
   "${CMAKE_CURRENT_LIST_DIR}/Types.fpp"
 )
 set(MOD_DEPS
diff --git a/Fw/Types/StringToNumber.cpp b/Fw/Types/StringToNumber.cpp
new file mode 100644
index 0000000000..92a996a361
--- /dev/null
+++ b/Fw/Types/StringToNumber.cpp
@@ -0,0 +1,124 @@
+#include <Fw/Types/StringUtils.hpp>
+#include <cstdlib>
+#include <cerrno>
+
+Fw::StringUtils::StringToNumberStatus string_to_helper_input_check(const CHAR* input, FwSizeType buffer_size, U8 base) {
+    Fw::StringUtils::StringToNumberStatus status = Fw::StringUtils::StringToNumberStatus::SUCCESSFUL_CONVERSION;
+    // Check for null input string
+    if (input == nullptr) {
+        status = Fw::StringUtils::NULL_INPUT;
+    }
+    // Invalid base e.g. not 0, 2-36
+    else if (base == 1 || base > 36) {
+        status = Fw::StringUtils::INVALID_BASE;
+    } else {
+        // Check the string is bounded within the specified length
+        FwSizeType length = Fw::StringUtils::string_length(input, buffer_size);
+        if (length == buffer_size) {
+            status = Fw::StringUtils::INVALID_STRING;
+        }
+    }
+    errno = 0;
+    return status;
+}
+
+Fw::StringUtils::StringToNumberStatus string_to_helper_output_check(Fw::StringUtils::StringToNumberStatus status, const char* original_input, char*& internal_next, char** external_next) {
+    // Check range, if error then
+    if (errno == ERANGE) {
+        status = Fw::StringUtils::INVALID_RANGE;
+    }
+    // Invalid number conversion
+    else if ((internal_next == original_input) || (internal_next == nullptr)) {
+        internal_next = nullptr;
+        status = Fw::StringUtils::INVALID_NUMBER;
+    }
+    // Set output pointer in all cases
+    if (external_next != nullptr) {
+        *external_next = internal_next;
+    }
+    errno = 0;
+    return status;
+}
+
+// Template for internal implementation only
+// \tparam T: input type (U8, I8, U64, I64)
+// \tparam Tinternal: function api type
+// \tparam F: conversion function to use
+template <typename T, typename Tinternal, Tinternal (*F)(const char*, char**, int)>
+Fw::StringUtils::StringToNumberStatus string_to_number_as_template(const CHAR* input, FwSizeType buffer_size, T& output, char** next, U8 base) {
+    static_assert(std::numeric_limits<T>::is_integer, "Type must be integer");
+    static_assert(std::numeric_limits<Tinternal>::is_integer, "Type must be integer");
+    static_assert(std::numeric_limits<T>::is_signed == std::numeric_limits<Tinternal>::is_signed, "Signedness must match");
+    static_assert(std::numeric_limits<T>::max() <= std::numeric_limits<Tinternal>::max(), "Invalid internal type chosen");
+    static_assert(std::numeric_limits<T>::min() >= std::numeric_limits<Tinternal>::min(), "Invalid internal type chosen");
+
+    char* output_next = nullptr;
+    Fw::StringUtils::StringToNumberStatus status = string_to_helper_input_check(input, buffer_size, base);
+    if (status == Fw::StringUtils::SUCCESSFUL_CONVERSION) {
+        Tinternal output_api = F(input, &output_next, base);
+        if (output_api > std::numeric_limits<T>::max()) {
+            status = Fw::StringUtils::StringToNumberStatus::INVALID_RANGE;
+            output_api = std::numeric_limits<T>::max();
+        }
+        if (output_api < std::numeric_limits<T>::min()) {
+            status = Fw::StringUtils::StringToNumberStatus::INVALID_RANGE;
+            output_api = std::numeric_limits<T>::min();
+        }
+        output = static_cast<T>(output_api);
+    }
+    status = string_to_helper_output_check(status, input, output_next, next);
+    return status;
+}
+
+#if FW_HAS_64_BIT
+Fw::StringUtils::StringToNumberStatus Fw::StringUtils::string_to_number(const CHAR* input, FwSizeType buffer_size, U64& output, char** next, U8 base) {
+    return string_to_number_as_template<U64, unsigned long long, strtoull>(input, buffer_size, output, next, base);
+}
+
+Fw::StringUtils::StringToNumberStatus Fw::StringUtils::string_to_number(const CHAR* input, FwSizeType buffer_size, I64& output, char** next, U8 base) {
+    return string_to_number_as_template<I64, long long, strtoll>(input, buffer_size, output, next, base);
+}
+#endif
+#if FW_HAS_32_BIT
+Fw::StringUtils::StringToNumberStatus Fw::StringUtils::string_to_number(const CHAR* input, FwSizeType buffer_size, U32& output, char** next, U8 base) {
+    return string_to_number_as_template<U32, unsigned long long, strtoull>(input, buffer_size, output, next, base);
+}
+
+
+Fw::StringUtils::StringToNumberStatus Fw::StringUtils::string_to_number(const CHAR* input, FwSizeType buffer_size, I32& output, char** next, U8 base) {
+    return string_to_number_as_template<I32, long long, strtoll>(input, buffer_size, output, next, base);
+}
+#endif
+#if FW_HAS_16_BIT
+Fw::StringUtils::StringToNumberStatus Fw::StringUtils::string_to_number(const CHAR* input, FwSizeType buffer_size, U16& output, char** next, U8 base) {
+    return string_to_number_as_template<U16, unsigned long long, strtoull>(input, buffer_size, output, next, base);
+}
+Fw::StringUtils::StringToNumberStatus Fw::StringUtils::string_to_number(const CHAR* input, FwSizeType buffer_size, I16& output, char** next, U8 base) {
+    return string_to_number_as_template<I16, long long, strtoll>(input, buffer_size, output, next, base);
+}
+#endif
+Fw::StringUtils::StringToNumberStatus Fw::StringUtils::string_to_number(const CHAR* input, FwSizeType buffer_size, U8& output, char** next, U8 base) {
+    return string_to_number_as_template<U8, unsigned long long, strtoull>(input, buffer_size, output, next, base);
+}
+Fw::StringUtils::StringToNumberStatus Fw::StringUtils::string_to_number(const CHAR* input, FwSizeType buffer_size, I8& output, char** next, U8 base) {
+    return string_to_number_as_template<I8, long long, strtoll>(input, buffer_size, output, next, base);
+}
+Fw::StringUtils::StringToNumberStatus Fw::StringUtils::string_to_number(const CHAR* input, FwSizeType buffer_size, F64& output, char** next) {
+    char* output_next = nullptr;
+    Fw::StringUtils::StringToNumberStatus status = string_to_helper_input_check(input, buffer_size, 0);
+    if (status == SUCCESSFUL_CONVERSION) {
+        output = strtod(input, &output_next);
+    }
+    status = string_to_helper_output_check(status, input, output_next, next);
+    return status;
+}
+
+Fw::StringUtils::StringToNumberStatus Fw::StringUtils::string_to_number(const CHAR* input, FwSizeType buffer_size, F32& output, char** next) {
+    char* output_next = nullptr;
+    Fw::StringUtils::StringToNumberStatus status = string_to_helper_input_check(input, buffer_size, 0);
+    if (status == SUCCESSFUL_CONVERSION) {
+        output = strtof(input, &output_next);
+    }
+    status = string_to_helper_output_check(status, input, output_next, next);
+    return status;
+}
diff --git a/Fw/Types/StringUtils.cpp b/Fw/Types/StringUtils.cpp
index 0ca16c265d..714b9d4a05 100644
--- a/Fw/Types/StringUtils.cpp
+++ b/Fw/Types/StringUtils.cpp
@@ -20,10 +20,10 @@ char* Fw::StringUtils::string_copy(char* destination, const char* source, FwSize
     return returned;
 }
 
-FwSizeType Fw::StringUtils::string_length(const CHAR* source, FwSizeType max_len) {
+FwSizeType Fw::StringUtils::string_length(const CHAR* source, FwSizeType buffer_size) {
     FwSizeType length = 0;
     FW_ASSERT(source != nullptr);
-    for (length = 0; length < max_len; length++) {
+    for (length = 0; length < buffer_size; length++) {
         if (source[length] == '\0') {
             break;
         }
diff --git a/Fw/Types/StringUtils.hpp b/Fw/Types/StringUtils.hpp
index 04b167faac..ea369cbd16 100644
--- a/Fw/Types/StringUtils.hpp
+++ b/Fw/Types/StringUtils.hpp
@@ -22,14 +22,16 @@ namespace StringUtils {
 char* string_copy(char* destination, const char* source, FwSizeType num);
 
 /**
- * \brief get the length of the source string or max_len if the string is
- * longer than max_len.
+ * \brief get the length of the source string
+ *
+ * If no string termination character is detected within buffer_size number of characters then buffer_size is returned.
+ * When buffer_size is returned, it can be assumed that the source string is invalid within a bound of buffer_size.
  *
  * \param source: string to calculate the length
- * \param max_len: the maximum length of the source string
- * \return length of the source string or max_len
+ * \param buffer_size: the size of the buffer containing source string.
+ * \return length of the source string or buffer_size if no \0 is found within buffer_size characters.
  */
-FwSizeType string_length(const CHAR* source, FwSizeType max_len);
+FwSizeType string_length(const CHAR* source, FwSizeType buffer_size);
 
 /**
  * \brief find the first occurrence of a substring
@@ -42,6 +44,174 @@ FwSizeType string_length(const CHAR* source, FwSizeType max_len);
  */
 FwSignedSizeType substring_find(const CHAR* source_string, FwSizeType source_size, const CHAR* sub_string, FwSizeType sub_size);
 
+enum StringToNumberStatus {
+    SUCCESSFUL_CONVERSION, //!< Output should be valid
+    NULL_INPUT,     //!< A null string was supplied
+    INVALID_STRING, //!< No \0 detected within the supplied length
+    INVALID_BASE,   //!< Base was not supplied as 0, or 2-36
+    INVALID_NUMBER, //!< String did not contain a valid number matching supplied base
+    INVALID_RANGE,  //!<
+};
+
+#if FW_HAS_64_BIT
+/**
+ * \brief converts a string to a U64
+ *
+ * Function to convert a string to a U64. String is provided via the input parameter and output is set in the output
+ * reference parameter. If no \0 is found within buffer_size, then this function will return an error, while setting
+ * output to 0.  If next is non-null, then a pointer to the character after the end of the number will be returned upon
+ * successful conversion.  Otherwise next will be set to null pointer.
+ *
+ * If base is 0, then the numerical base of the number is inferred from the string itself via the prefix (e.g 0x) and
+ * lacking a prefix is assumed to be decimal (base 10). Otherwise, base may be 2-36.
+ *
+ * If the converted number does not fit within the range of the type of output, output is set to min or max
+ * appropriately and INVALID_RANGE is returned.
+ *
+ * It is an error to supply a null input string.
+ * It is an error to supply a string that does not terminate with a \0 within buffer_size characters
+ * The numerical conversion may also return errors.
+ *
+ * \param input: input string
+ * \param buffer_size: maximum length of string bounding the conversion
+ * \param base: base of the number. 0 to detect decimal, octal, hexadecimal. 2-36 to use specified base.
+ * \param output: (output) will contain the converted number or 0 on error
+ * \param next: (output) will contain a pointer to the next character after the number and null pointer on error
+ * \return SUCCESSFUL_CONVERSION when output is valid, something else on error.
+ */
+StringToNumberStatus string_to_number(const CHAR* input, FwSizeType buffer_size, U64& output, char** next, U8 base=0);
+
+/**
+ * \brief converts a string to a I64
+ *
+ * See string_to_number (above) for full explanation.
+ *
+ * \param input: input string
+ * \param buffer_size: maximum length of string bounding the conversion
+ * \param base: base of the number. 0 to detect decimal, octal, hexadecimal. 2-36 to use specified base.
+ * \param output: (output) will contain the converted number or 0 on error
+ * \param next: (output) will contain a pointer to the next character after the number and null pointer on error
+ * \return SUCCESSFUL_CONVERSION when output is valid, something else on error.
+ */
+StringToNumberStatus string_to_number(const CHAR* input, FwSizeType buffer_size, I64& output, char** next, U8 base=0);
+#endif
+#if FW_HAS_32_BIT
+/**
+ * \brief converts a string to a U32
+ *
+ * See string_to_number (above) for full explanation.
+ *
+ * \param input: input string
+ * \param buffer_size: maximum length of string bounding the conversion
+ * \param base: base of the number. 0 to detect decimal, octal, hexadecimal. 2-36 to use specified base.
+ * \param output: (output) will contain the converted number or 0 on error
+ * \param next: (output) will contain a pointer to the next character after the number and null pointer on error
+ * \return SUCCESSFUL_CONVERSION when output is valid, something else on error.
+ */
+StringToNumberStatus string_to_number(const CHAR* input, FwSizeType buffer_size, U32& output, char** next, U8 base=0);
+
+/**
+ * \brief converts a string to a I32
+ *
+ * See string_to_number (above) for full explanation.
+ *
+ * \param input: input string
+ * \param buffer_size: maximum length of string bounding the conversion
+ * \param base: base of the number. 0 to detect decimal, octal, hexadecimal. 2-36 to use specified base.
+ * \param output: (output) will contain the converted number or 0 on error
+ * \param next: (output) will contain a pointer to the next character after the number and null pointer on error
+ * \return SUCCESSFUL_CONVERSION when output is valid, something else on error.
+ */
+StringToNumberStatus string_to_number(const CHAR* input, FwSizeType buffer_size, I32& output, char** next, U8 base=0);
+#endif
+#if FW_HAS_16_BIT
+/**
+ * \brief converts a string to a U16
+ *
+ * See string_to_number (above) for full explanation.
+ *
+ * \param input: input string
+ * \param buffer_size: maximum length of string bounding the conversion
+ * \param base: base of the number. 0 to detect decimal, octal, hexadecimal. 2-36 to use specified base.
+ * \param output: (output) will contain the converted number or 0 on error
+ * \param next: (output) will contain a pointer to the next character after the number and null pointer on error
+ * \return SUCCESSFUL_CONVERSION when output is valid, something else on error.
+ */
+StringToNumberStatus string_to_number(const CHAR* input, FwSizeType buffer_size, U16& output, char** next, U8 base=0);
+
+/**
+ * \brief converts a string to a I16
+ *
+ * See string_to_number (above) for full explanation.
+ *
+ * \param input: input string
+ * \param buffer_size: maximum length of string bounding the conversion
+ * \param base: base of the number. 0 to detect decimal, octal, hexadecimal. 2-36 to use specified base.
+ * \param output: (output) will contain the converted number or 0 on error
+ * \param next: (output) will contain a pointer to the next character after the number and null pointer on error
+ * \return SUCCESSFUL_CONVERSION when output is valid, something else on error.
+ */
+StringToNumberStatus string_to_number(const CHAR* input, FwSizeType buffer_size, I16& output, char** next, U8 base=0);
+#endif
+
+/**
+ * \brief converts a string to a U8
+ *
+ * See string_to_number (above) for full explanation.
+ *
+ * \param input: input string
+ * \param buffer_size: maximum length of string bounding the conversion
+ * \param base: base of the number. 0 to detect decimal, octal, hexadecimal. 2-36 to use specified base.
+ * \param output: (output) will contain the converted number or 0 on error
+ * \param next: (output) will contain a pointer to the next character after the number and null pointer on error
+ * \return SUCCESSFUL_CONVERSION when output is valid, something else on error.
+ */
+StringToNumberStatus string_to_number(const CHAR* input, FwSizeType buffer_size, U8& output, char** next, U8 base=0);
+
+/**
+ * \brief converts a string to a I8
+ *
+ * See string_to_number (above) for full explanation.
+ *
+ * \param input: input string
+ * \param buffer_size: maximum length of string bounding the conversion
+ * \param base: base of the number. 0 to detect decimal, octal, hexadecimal. 2-36 to use specified base.
+ * \param output: (output) will contain the converted number or 0 on error
+ * \param next: (output) will contain a pointer to the next character after the number and null pointer on error
+ * \return SUCCESSFUL_CONVERSION when output is valid, something else on error.
+ */
+StringToNumberStatus string_to_number(const CHAR* input, FwSizeType buffer_size, I8& output, char** next, U8 base=0);
+
+/**
+ * \brief converts a string to a F32
+ *
+ * See string_to_number (above) for full explanation. `base` is not supported on floating point conversions.
+ *
+ * \param input: input string
+ * \param buffer_size: maximum length of string bounding the conversion
+ * \param base: base of the number. 0 to detect decimal, octal, hexadecimal. 2-36 to use specified base.
+ * \param output: (output) will contain the converted number or 0 on error
+ * \param next: (output) will contain a pointer to the next character after the number and null pointer on error
+ * \return SUCCESSFUL_CONVERSION when output is valid, something else on error.
+ */
+StringToNumberStatus string_to_number(const CHAR* input, FwSizeType buffer_size, F32& output, char** next);
+
+/**
+ * \brief converts a string to a F64
+ *
+ * See string_to_number (above) for full explanation. `base` is not supported on floating point conversions.
+ *
+ * \param input: input string
+ * \param buffer_size: maximum length of string bounding the conversion
+ * \param base: base of the number. 0 to detect decimal, octal, hexadecimal. 2-36 to use specified base.
+ * \param output: (output) will contain the converted number or 0 on error
+ * \param next: (output) will contain a pointer to the next character after the number and null pointer on error
+ * \return SUCCESSFUL_CONVERSION when output is valid, something else on error.
+ */
+StringToNumberStatus string_to_number(const CHAR* input, FwSizeType buffer_size, F64& output, char** next);
+
+
+
 
 }  // namespace StringUtils
 }  // namespace Fw
diff --git a/Os/CMakeLists.txt b/Os/CMakeLists.txt
index fa220cb0fd..c03627645b 100644
--- a/Os/CMakeLists.txt
+++ b/Os/CMakeLists.txt
@@ -9,6 +9,8 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Models")
 add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Stub")
 add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Posix")
 add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Generic")
+add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Linux")
+add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Darwin")
 
 set(SOURCE_FILES
     "${CMAKE_CURRENT_LIST_DIR}/test/ut/file/SyntheticFileSystem.cpp"
@@ -25,15 +27,21 @@ set(MOD_DEPS
   Fw/Logger
   Utils/Hash
 )
+if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
+    list(APPEND MOD_DEPS -lrt)
+endif()
+
 # Basic source files used in every OSAL layer.  Contains common code and helpers.
 set(SOURCE_FILES
     "${CMAKE_CURRENT_LIST_DIR}/IntervalTimerCommon.cpp"
-    "${CMAKE_CURRENT_LIST_DIR}/MemCommon.cpp"
+    "${CMAKE_CURRENT_LIST_DIR}/Posix/IntervalTimer.cpp"
+
     "${CMAKE_CURRENT_LIST_DIR}/ValidateFileCommon.cpp"
     "${CMAKE_CURRENT_LIST_DIR}/ValidatedFile.cpp"
 
     # Refactored common files
     "${CMAKE_CURRENT_LIST_DIR}/Os.cpp"
+    "${CMAKE_CURRENT_LIST_DIR}/Console.cpp"
     "${CMAKE_CURRENT_LIST_DIR}/File.cpp"
     "${CMAKE_CURRENT_LIST_DIR}/Task.cpp"
     "${CMAKE_CURRENT_LIST_DIR}/Mutex.cpp"
@@ -41,6 +49,8 @@ set(SOURCE_FILES
     "${CMAKE_CURRENT_LIST_DIR}/Directory.cpp"
     "${CMAKE_CURRENT_LIST_DIR}/Condition.cpp"
     "${CMAKE_CURRENT_LIST_DIR}/Queue.cpp"
+    "${CMAKE_CURRENT_LIST_DIR}/Cpu.cpp"
+    "${CMAKE_CURRENT_LIST_DIR}/Memory.cpp"
 )
 # Check for default logger
 if (NOT FPRIME_DISABLE_DEFAULT_LOGGER)
@@ -48,56 +58,17 @@ if (NOT FPRIME_DISABLE_DEFAULT_LOGGER)
         "${CMAKE_CURRENT_LIST_DIR}/LogDefault.cpp"
     )
 endif()
-# Posix systems typically share these
-if (FPRIME_USE_POSIX)
-    list(APPEND SOURCE_FILES
-        "${CMAKE_CURRENT_LIST_DIR}/Console.cpp"
-        "${CMAKE_CURRENT_LIST_DIR}/Linux/InterruptLock.cpp"
-        "${CMAKE_CURRENT_LIST_DIR}/Linux/WatchdogTimer.cpp"
-        "${CMAKE_CURRENT_LIST_DIR}/Posix/IntervalTimer.cpp"
-    )
-endif()
-# Darwin IPC queue implementation
-if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
-  list(APPEND SOURCE_FILES
-#    "${CMAKE_CURRENT_LIST_DIR}/MacOs/IPCQueueStub.cpp"
-    "${CMAKE_CURRENT_LIST_DIR}/MacOs/SystemResources.cpp"
-  )
-# Linux IPC queues implementation
-elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
-  list(APPEND SOURCE_FILES
-	"${CMAKE_CURRENT_LIST_DIR}/Linux/SystemResources.cpp"
-  )
-  # Shared libraries need an -rt dependency for mq libs
-  if (BUILD_SHARED_LIBS)
-      list(APPEND MOD_DEPS "-lrt")
-  endif()
-endif()
-
-
-# If baremetal scheduler is set, remove the previous task files and add in the Baremetal variant
-if (FPRIME_USE_BAREMETAL_SCHEDULER)
-    add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Baremetal/TaskRunner/")
-    foreach (ITER_ITEM IN LISTS SOURCE_FILES)
-        if (ITER_ITEM MATCHES "Task\\.cpp$")
-            list(REMOVE_ITEM SOURCE_FILES "${ITER_ITEM}")
-        endif()
-    endforeach()
-    list(APPEND SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/Baremetal/FileSystem.cpp")
-    list(APPEND SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/Baremetal/IntervalTimer.cpp")
-    list(APPEND SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/Baremetal/Mutex.cpp")
-    list(APPEND SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/Baremetal/Queue.cpp")
-    list(APPEND SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/Baremetal/SystemResources.cpp")
-endif()
 register_fprime_module()
 
 require_fprime_implementation(Os/File)
 require_fprime_implementation(Os/FileSystem)
 require_fprime_implementation(Os/Directory)
 require_fprime_implementation(Os/Mutex)
-# require_fprime_implementation(Os/Task) # should be added in
-# require_fprime_implementation(Os/Console) # should be added in
+#require_fprime_implementation(Os/Task)
+require_fprime_implementation(Os/Console)
 require_fprime_implementation(Os/Queue)
+require_fprime_implementation(Os/Cpu)
+require_fprime_implementation(Os/Memory)
 
 
 ### UTS ### Note: 3 separate UTs registered here.
@@ -105,7 +76,6 @@ set(UT_SOURCE_FILES
   "${CMAKE_CURRENT_LIST_DIR}/test/ut/OsTestMain.cpp"
   "${CMAKE_CURRENT_LIST_DIR}/test/ut/IntervalTimerTest.cpp"
   "${CMAKE_CURRENT_LIST_DIR}/test/ut/OsValidateFileTest.cpp"
-  "${CMAKE_CURRENT_LIST_DIR}/test/ut/OsSystemResourcesTest.cpp"
   "${CMAKE_CURRENT_LIST_DIR}/test/ut/OsMutexBasicLockableTest.cpp"
 )
 register_fprime_ut()
diff --git a/Os/Cpu.cpp b/Os/Cpu.cpp
new file mode 100644
index 0000000000..5b4e3a5703
--- /dev/null
+++ b/Os/Cpu.cpp
@@ -0,0 +1,47 @@
+// ======================================================================
+// \title Os/Cpu.hpp
+// \brief common function implementations for Os::Cpu
+// ======================================================================
+#include "Os/Cpu.hpp"
+#include "Fw/Types/Assert.hpp"
+
+namespace Os {
+
+Cpu::Cpu() : m_delegate(*CpuInterface::getDelegate(m_handle_storage)) {}
+
+Cpu::~Cpu() {
+    m_delegate.~CpuInterface();
+}
+
+void Cpu::init() {
+    (void) Cpu::getSingleton();
+}
+
+Cpu& Cpu::getSingleton() {
+    static Cpu _singleton;
+    return _singleton;
+}
+
+Cpu::Status Cpu::_getCount(FwSizeType& cpu_count) {
+    FW_ASSERT(&this->m_delegate == reinterpret_cast<CpuInterface*>(&this->m_handle_storage[0]));
+    return this->m_delegate._getCount(cpu_count);
+}
+
+Cpu::Status Cpu::_getTicks(Ticks& ticks, FwSizeType cpu_index) {
+    FW_ASSERT(&this->m_delegate == reinterpret_cast<CpuInterface*>(&this->m_handle_storage[0]));
+    return this->m_delegate._getTicks(ticks, cpu_index);
+}
+
+CpuHandle* Cpu::getHandle() {
+    FW_ASSERT(&this->m_delegate == reinterpret_cast<CpuInterface*>(&this->m_handle_storage[0]));
+    return this->m_delegate.getHandle();
+}
+
+Cpu::Status Cpu::getCount(FwSizeType& cpu_count) {
+    return Cpu::getSingleton()._getCount(cpu_count);
+}
+
+Cpu::Status Cpu::getTicks(Ticks& ticks, FwSizeType cpu_index) {
+    return Cpu::getSingleton()._getTicks(ticks, cpu_index);
+}
+}
diff --git a/Os/Cpu.hpp b/Os/Cpu.hpp
new file mode 100644
index 0000000000..4db967dbb6
--- /dev/null
+++ b/Os/Cpu.hpp
@@ -0,0 +1,152 @@
+// ======================================================================
+// \title Os/Cpu.hpp
+// \brief common function definitions for Os::Cpu
+// ======================================================================
+#include "Os/Os.hpp"
+
+#ifndef OS_CPU_HPP_
+#define OS_CPU_HPP_
+
+namespace Os {
+
+//! \brief Cpu variable handle parent
+class CpuHandle {};
+
+//! \brief interface for cpu implementation
+class CpuInterface {
+  public:
+    using Status = Os::Generic::Status;
+    using Ticks = Os::Generic::UsedTotal;
+
+    //! Default constructor
+    CpuInterface() = default;
+    //! Default destructor
+    virtual ~CpuInterface() = default;
+
+    //! \brief copy constructor is forbidden
+    CpuInterface(const CpuInterface& other) = delete;
+
+    //! \brief assignment operator is forbidden
+    virtual CpuInterface& operator=(const CpuInterface& other) = delete;
+
+    //! \brief Request the count of the CPUs detected by the system
+    //!
+    //! \param cpu_count: (output) filled with CPU count on system
+    //! \return: OP_OK with valid CPU count, ERROR when error occurs
+    //!
+    virtual Status _getCount(FwSizeType & cpu_count) = 0;
+
+    //! \brief Get the CPU tick information for a given CPU
+    //!
+    //! CPU ticks represent a small time slice of processor time. This will retrieve the used CPU ticks and total
+    //! ticks for a given CPU. This information in a running accumulation and thus a sample-to-sample
+    //! differencing is needed to see the 'realtime' changing load. This shall be done by the caller.
+    //!
+    //! \param ticks: (output) filled with the tick information for the given CPU
+    //! \param cpu_index: index for CPU to read. Default: 0
+    //! \return:  ERROR when error occurs, OK otherwise.
+    //!
+    virtual Status _getTicks(Ticks& ticks, FwSizeType cpu_index) = 0;
+
+    //! \brief return the underlying cpu handle (implementation specific).
+    //! \return internal task handle representation
+    virtual CpuHandle* getHandle() = 0;
+
+    //! \brief provide a pointer to a Mutex delegate object
+    static CpuInterface* getDelegate(CpuHandleStorage& aligned_new_memory);
+};
+
+//! \brief cpu implementation
+class Cpu final : public CpuInterface {
+  public:
+    //! \brief default constructor
+    Cpu();
+
+    //! \brief default virtual destructor
+    ~Cpu() final;
+
+    //! \brief copy constructor is forbidden
+    Cpu(const CpuInterface& other) = delete;
+
+    //! \brief copy constructor is forbidden
+    Cpu(const CpuInterface* other) = delete;
+
+    //! \brief assignment operator is forbidden
+    CpuInterface& operator=(const CpuInterface& other) override = delete;
+
+    //-----------------------------------------------------------------------------
+    // Interface methods
+    //-----------------------------------------------------------------------------
+
+    //! \brief initialize the singleton
+    void init();
+
+    //! \brief return singleton
+    static Cpu& getSingleton();
+
+    //-----------------------------------------------------------------------------
+    // Delegating methods
+    //-----------------------------------------------------------------------------
+
+    //! \brief Request the count of the CPUs detected by the system
+    //!
+    //! This method wraps delegates to the underlying implementation.
+    //!
+    //! \param cpu_count: (output) filled with CPU count on system
+    //! \return: OP_OK with valid CPU count, ERROR when error occurs
+    //!
+    Status _getCount(FwSizeType& cpu_count) override;
+
+    //! \brief Get the CPU tick information for a given CPU
+    //!
+    //! CPU ticks represent a small time slice of processor time. This will retrieve the used CPU ticks and total
+    //! ticks for a given CPU. This information in a running accumulation and thus a sample-to-sample
+    //! differencing is needed to see the 'realtime' changing load. This shall be done by the caller. This method wraps
+    //! delegates to the underlying implementation.
+    //!
+    //! \param ticks: (output) filled with the tick information for the given CPU
+    //! \param cpu_index: index for CPU to read. Default: 0
+    //! \return:  ERROR when error occurs, OK otherwise.
+    //!
+    Status _getTicks(Ticks& ticks, FwSizeType cpu_index) override;
+
+    //! \brief return the underlying cpu handle (implementation specific).
+    //! \return internal task handle representation
+    CpuHandle* getHandle() override;
+
+    //-----------------------------------------------------------------------------
+    // Static interface (singleton) methods
+    //-----------------------------------------------------------------------------
+
+    //! \brief Request the count of the CPUs detected by the system
+    //!
+    //! This method wraps a singleton implementation.
+    //!
+    //! \param cpu_count: (output) filled with CPU count on system
+    //! \return: OP_OK with valid CPU count, ERROR when error occurs
+    //!
+    static  Status getCount(FwSizeType& cpu_count);
+
+    //! \brief Get the CPU tick information for a given CPU
+    //!
+    //! CPU ticks represent a small time slice of processor time. This will retrieve the used CPU ticks and total
+    //! ticks for a given CPU. This information in a running accumulation and thus a sample-to-sample
+    //! differencing is needed to see the 'realtime' changing load. This shall be done by the caller. This method wraps
+    //! a singleton implementation.
+    //!
+    //! \param ticks: (output) filled with the tick information for the given CPU
+    //! \param cpu_index: index for CPU to read. Default: 0
+    //! \return:  ERROR when error occurs, OK otherwise.
+    //!
+    static Status getTicks(Ticks& ticks, FwSizeType cpu_index);
+
+  private:
+
+    // This section is used to store the implementation-defined file handle. To Os::File and fprime, this type is
+    // opaque and thus normal allocation cannot be done. Instead, we allow the implementor to store then handle in
+    // the byte-array here and set `handle` to that address for storage.
+    alignas(FW_HANDLE_ALIGNMENT) CpuHandleStorage m_handle_storage; //!< Storage for aligned data
+    CpuInterface& m_delegate;                                       //!< Delegate for the real implementation
+};
+}
+#endif //OS_CONDITION_HPP_
diff --git a/Os/Darwin/CMakeLists.txt b/Os/Darwin/CMakeLists.txt
new file mode 100644
index 0000000000..1cd1dc1395
--- /dev/null
+++ b/Os/Darwin/CMakeLists.txt
@@ -0,0 +1,56 @@
+####
+# F prime CMakeLists.txt:
+#
+# SOURCE_FILES: combined list of source and autocoding files
+# MOD_DEPS: (optional) module dependencies
+#
+####
+restrict_platforms(Darwin)
+add_custom_target("${FPRIME_CURRENT_MODULE}")
+
+# -----------------------------------------
+### Os/Darwin/Cpu Section
+# -----------------------------------------
+set(SOURCE_FILES
+    "${CMAKE_CURRENT_LIST_DIR}/Cpu.cpp"
+)
+set(HEADER_FILES
+    "${CMAKE_CURRENT_LIST_DIR}/Cpu.hpp"
+)
+set(MOD_DEPS)
+register_fprime_module(Os_Cpu_Darwin)
+register_fprime_implementation(Os/Cpu Os_Cpu_Darwin "${CMAKE_CURRENT_LIST_DIR}/DefaultCpu.cpp")
+
+set(UT_SOURCE_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/../test/ut/cpu/CommonCpuTests.cpp"
+        "${CMAKE_CURRENT_LIST_DIR}/test/ut/DarwinCpuTests.cpp"
+)
+set(UT_MOD_DEPS
+        STest
+)
+choose_fprime_implementation(Os/Cpu Os_Cpu_Darwin)
+register_fprime_ut(DarwinCpuTest)
+
+
+# -----------------------------------------
+### Os/Darwin/Memory Section
+# -----------------------------------------
+set(SOURCE_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/Memory.cpp"
+)
+set(HEADER_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/Memory.hpp"
+)
+set(MOD_DEPS)
+register_fprime_module(Os_Memory_Darwin)
+register_fprime_implementation(Os/Memory Os_Memory_Darwin "${CMAKE_CURRENT_LIST_DIR}/DefaultMemory.cpp")
+
+set(UT_SOURCE_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/../test/ut/memory/CommonMemoryTests.cpp"
+        "${CMAKE_CURRENT_LIST_DIR}/test/ut/DarwinMemoryTests.cpp"
+)
+set(UT_MOD_DEPS
+        STest
+)
+choose_fprime_implementation(Os/Memory Os_Memory_Darwin)
+register_fprime_ut(DarwinMemoryTest)
diff --git a/Os/Darwin/Cpu.cpp b/Os/Darwin/Cpu.cpp
new file mode 100644
index 0000000000..fcdcec7606
--- /dev/null
+++ b/Os/Darwin/Cpu.cpp
@@ -0,0 +1,93 @@
+// ======================================================================
+// \title Os/Darwin/Cpu.cpp
+// \brief Darwin implementation for Os::Cpu
+// ======================================================================
+#include <Os/Darwin/Cpu.hpp>
+#include <Fw/Types/Assert.hpp>
+#include <mach/mach_error.h>
+#include <mach/mach_host.h>
+#include <mach/mach_init.h>
+#include <mach/mach_types.h>
+#include <mach/message.h>
+
+namespace Os {
+namespace Darwin {
+namespace Cpu {
+
+//! \brief helper around raw CPU capture API
+//!
+//! Calls for the CPU information from the machine, improving readability in cpu_by_index
+//!
+//! \param cpu_load_info: filled with CPU data
+//! \param cpu_count: filled with CPU count
+//!
+//! \return success/failure using kern_return_t
+kern_return_t cpu_data_helper(processor_cpu_load_info_t& cpu_load_info, FwSizeType& cpu_count) {
+    static_assert(std::numeric_limits<FwSizeType>::max() >= std::numeric_limits<natural_t>::max(),
+                  "FwSizeType cannot hold natural_t values");
+    natural_t cpu_count_natural;
+    mach_msg_type_number_t processor_msg_count;
+    kern_return_t stat = host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &cpu_count_natural,
+                                             reinterpret_cast<processor_info_array_t*>(&cpu_load_info), &processor_msg_count);
+    cpu_count = cpu_count_natural;
+    return stat;
+}
+
+//! \brief Query for a single CPU's ticks information
+//!
+//! Queries all CPU information but only deals with a single CPU's output. This is done because the load average is
+//! tracked sample to sample and the call pattern is cpu0, cpu1, ..., cpu last, wait for sample window, cpu0, ... and
+//! thus each call should update one CPU's sample or only the last cpu will have the benefit of the sampling window.
+//!
+//! \param cpu_index: index of current CPU being queried
+//! \param used: filled with CPU's used ticks count
+//! \param total: filled with CPU's total ticks
+//!
+//! \return success/failure using kern_return_t
+kern_return_t cpu_by_index(FwSizeType cpu_index, FwSizeType& used, FwSizeType& total) {
+    processor_cpu_load_info_t cpu_load_info;
+    FwSizeType cpu_count = 0;
+    kern_return_t status = cpu_data_helper(cpu_load_info, cpu_count);
+
+    // Failure for CPU index
+    if (cpu_count <= cpu_index) {
+        status = KERN_FAILURE;
+    } else if (KERN_SUCCESS == status) {
+        processor_cpu_load_info per_cpu_info = cpu_load_info[cpu_index];
+
+        // Total the ticks across the different states: idle, system, user, etc...
+        total = 0;
+        for (FwSizeType i = 0; i < CPU_STATE_MAX; i++) {
+            total += per_cpu_info.cpu_ticks[i];
+        }
+        used = total - per_cpu_info.cpu_ticks[CPU_STATE_IDLE];
+    }
+    return status;
+}
+
+CpuInterface::Status DarwinCpu::_getCount(FwSizeType& cpu_count) {
+    processor_cpu_load_info_t cpu_load_info;
+    if (KERN_SUCCESS == cpu_data_helper(cpu_load_info, cpu_count)) {
+        return Status::OP_OK;
+    }
+    cpu_count = 0;
+    return Status::ERROR;
+}
+
+CpuInterface::Status DarwinCpu::_getTicks(Os::Cpu::Ticks& ticks, FwSizeType cpu_index) {
+    kern_return_t status = cpu_by_index(cpu_index, ticks.used, ticks.total);
+    if (KERN_SUCCESS == status) {
+        return Status::OP_OK;
+    }
+    ticks.total = 1;
+    ticks.used = 1;
+    return Status::ERROR;
+}
+
+CpuHandle* DarwinCpu::getHandle() {
+    return &this->m_handle;
+}
+
+} // namespace Cpu
+} // namespace Darwin
+} // namespace Os
diff --git a/Os/Darwin/Cpu.hpp b/Os/Darwin/Cpu.hpp
new file mode 100644
index 0000000000..46e48ccfa0
--- /dev/null
+++ b/Os/Darwin/Cpu.hpp
@@ -0,0 +1,81 @@
+// ======================================================================
+// \title Os/Darwin/Cpu.hpp
+// \brief Darwin implementation for Os::Cpu, header and test definitions
+// ======================================================================
+#include <Os/Cpu.hpp>
+#ifndef OS_Darwin_Cpu_HPP
+#define OS_Darwin_Cpu_HPP
+
+namespace Os {
+namespace Darwin {
+namespace Cpu {
+
+//! CpuHandle class definition for stub implementations.
+//!
+struct DarwinCpuHandle : public CpuHandle {
+};
+
+//! \brief stub implementation of Os::CpuInterface
+//!
+//! Darwin implementation of `CpuInterface` for use as a delegate class handling stub console operations.
+//!
+class DarwinCpu : public CpuInterface {
+  public:
+    //! \brief constructor
+    //!
+    DarwinCpu() = default;
+
+    //! \brief copy constructor
+    DarwinCpu(const DarwinCpu& other) = delete;
+
+    //! \brief default copy assignment
+    CpuInterface& operator=(const CpuInterface& other) override = delete;
+
+    //! \brief destructor
+    //!
+    ~DarwinCpu() override = default;
+
+    // ------------------------------------
+    // Functions overrides
+    // ------------------------------------
+  public:
+
+    //! \brief Request the count of the CPUs detected by the system
+    //!
+    //! This method wraps delegates to the underlying implementation.
+    //!
+    //! \param cpu_count: (output) filled with CPU count on system
+    //! \return: OP_OK with valid CPU count, ERROR when error occurs
+    //!
+    Status _getCount(FwSizeType& cpu_count) override;
+
+    //! \brief Get the CPU tick information for a given CPU
+    //!
+    //! CPU ticks represent a small time slice of processor time. This will retrieve the used CPU ticks and total
+    //! ticks for a given CPU. This information in a running accumulation and thus a sample-to-sample
+    //! differencing is needed to see the 'realtime' changing load. This shall be done by the caller. This method wraps
+    //! delegates to the underlying implementation.
+    //!
+    //! \param ticks: (output) filled with the tick information for the given CPU
+    //! \param cpu_index: index for CPU to read. Default: 0
+    //! \return:  ERROR when error occurs, OK otherwise.
+    //!
+    Status _getTicks(Os::Cpu::Ticks& ticks, FwSizeType cpu_index) override;
+
+    //! \brief returns the raw console handle
+    //!
+    //! Gets the raw console handle from the implementation. Note: users must include the implementation specific
+    //! header to make any real use of this handle. Otherwise it will be as an opaque type.
+    //!
+    //! \return raw console handle
+    //!
+    CpuHandle *getHandle() override;
+  private:
+    //! File handle for PosixFile
+    DarwinCpuHandle m_handle;
+};
+} // namespace Cpu
+} // namespace Darwin
+} // namespace Os
+
+#endif // OS_Darwin_Cpu_HPP
diff --git a/Os/Darwin/DefaultCpu.cpp b/Os/Darwin/DefaultCpu.cpp
new file mode 100644
index 0000000000..f94559df0a
--- /dev/null
+++ b/Os/Darwin/DefaultCpu.cpp
@@ -0,0 +1,13 @@
+// ======================================================================
+// \title Os/Darwin/DefaultCpu.cpp
+// \brief sets default Os::Cpu to Darwin implementation via linker
+// ======================================================================
+#include "Os/Cpu.hpp"
+#include "Os/Darwin/Cpu.hpp"
+#include "Os/Delegate.hpp"
+
+namespace Os {
+CpuInterface* CpuInterface::getDelegate(CpuHandleStorage& aligned_new_memory) {
+    return Os::Delegate::makeDelegate<CpuInterface, Os::Darwin::Cpu::DarwinCpu>(aligned_new_memory);
+}
+}
diff --git a/Os/Darwin/DefaultMemory.cpp b/Os/Darwin/DefaultMemory.cpp
new file mode 100644
index 0000000000..e152a34795
--- /dev/null
+++ b/Os/Darwin/DefaultMemory.cpp
@@ -0,0 +1,13 @@
+// ======================================================================
+// \title Os/Darwin/DefaultMemory.cpp
+// \brief sets default Os::Memory to Darwin implementation via linker
+// ======================================================================
+#include "Os/Memory.hpp"
+#include "Os/Darwin/Memory.hpp"
+#include "Os/Delegate.hpp"
+
+namespace Os {
+MemoryInterface* MemoryInterface::getDelegate(MemoryHandleStorage& aligned_new_memory) {
+    return Os::Delegate::makeDelegate<MemoryInterface, Os::Darwin::Memory::DarwinMemory>(aligned_new_memory);
+}
+}
diff --git a/Os/Darwin/Memory.cpp b/Os/Darwin/Memory.cpp
new file mode 100644
index 0000000000..4b6008b0a4
--- /dev/null
+++ b/Os/Darwin/Memory.cpp
@@ -0,0 +1,66 @@
+// ======================================================================
+// \title Os/Darwin/Memory.cpp
+// \brief Darwin implementation for Os::Memory
+// ======================================================================
+#include <Os/Darwin/Memory.hpp>
+#include <mach/mach_error.h>
+#include <mach/mach_host.h>
+#include <mach/mach_init.h>
+#include <mach/mach_types.h>
+#include <mach/message.h>
+
+namespace Os {
+namespace Darwin {
+namespace Memory {
+
+/**
+ * \brief reads macOS virtual memory statistics for memory calculation
+ *
+ * Queries the macOS kernel for virtual memory information. These items are returned in units of page-size and are
+ * then converted back into bytes.
+ *
+ * Thanks to: https://stackoverflow.com/questions/8782228/retrieve-ram-info-on-a-mac
+ *
+ * \param used: used memory in bytes
+ * \param total: total memory in bytes
+ * \return: kern_return_t with success/failure straight from the kernel
+ */
+kern_return_t vm_stat_helper(FwSizeType& used, FwSizeType& total) {
+    mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
+    vm_statistics_data_t vmstat;
+    vm_size_t vmsize;
+
+    kern_return_t status1 = host_statistics(mach_host_self(), HOST_VM_INFO, reinterpret_cast<host_info_t>(&vmstat), &count);
+    kern_return_t status2 = host_page_size(mach_host_self(), &vmsize);
+
+    if (KERN_SUCCESS == status1 and KERN_SUCCESS == status2) {
+        // Wired (permanently in RAM), active (recently used), and inactive (not recently used) pages
+        used = vmstat.wire_count + vmstat.active_count + vmstat.inactive_count;
+        total = used + vmstat.free_count;
+
+        // Pages to totals
+        used *= vmsize;
+        total *= vmsize;
+    }
+    return (status1 == KERN_SUCCESS) ? status2 : status1;
+}
+
+
+MemoryInterface::Status DarwinMemory::_getUsage(Os::Memory::Usage& memory_usage) {
+    // Call out VM helper
+    if (KERN_SUCCESS == vm_stat_helper(memory_usage.used, memory_usage.total)) {
+        return Status::OP_OK;
+    }
+    // Force something sensible, while preventing divide by zero
+    memory_usage.total = 1;
+    memory_usage.used = 1;
+    return Status::ERROR;
+}
+
+MemoryHandle* DarwinMemory::getHandle() {
+    return &this->m_handle;
+}
+
+} // namespace Memory
+} // namespace Darwin
+} // namespace Os
diff --git a/Os/Darwin/Memory.hpp b/Os/Darwin/Memory.hpp
new file mode 100644
index 0000000000..ad9cafc723
--- /dev/null
+++ b/Os/Darwin/Memory.hpp
@@ -0,0 +1,67 @@
+// ======================================================================
+// \title Os/Darwin/Memory.hpp
+// \brief Darwin implementation for Os::Memory, header and test definitions
+// ======================================================================
+#include <Os/Memory.hpp>
+#ifndef OS_Darwin_Memory_HPP
+#define OS_Darwin_Memory_HPP
+
+namespace Os {
+namespace Darwin {
+namespace Memory {
+
+//! MemoryHandle class definition for stub implementations.
+//!
+struct DarwinMemoryHandle : public MemoryHandle {
+};
+
+//! \brief stub implementation of Os::MemoryInterface
+//!
+//! Darwin implementation of `MemoryInterface` for use as a delegate class handling stub console operations.
+//!
+class DarwinMemory : public MemoryInterface {
+  public:
+    //! \brief constructor
+    //!
+    DarwinMemory() = default;
+
+    //! \brief copy constructor
+    DarwinMemory(const DarwinMemory& other) = delete;
+
+    //! \brief default copy assignment
+    MemoryInterface& operator=(const MemoryInterface& other) override = delete;
+
+    //! \brief destructor
+    //!
+    ~DarwinMemory() override = default;
+
+    // ------------------------------------
+    // Functions overrides
+    // ------------------------------------
+  public:
+
+    //! \brief get system memory usage
+    //!
+    //! This method delegates to the underlying implementation.
+    //!
+    //! \param memory_usage: (output) data structure used to store memory usage
+    //! \return:  ERROR when error occurs, OK otherwise.
+    Status _getUsage(Os::Memory::Usage& memory_usage) override;
+
+    //! \brief returns the raw console handle
+    //!
+    //! Gets the raw console handle from the implementation. Note: users must include the implementation specific
+    //! header to make any real use of this handle. Otherwise it will be as an opaque type.
+    //!
+    //! \return raw console handle
+    //!
+    MemoryHandle *getHandle() override;
+  private:
+    //! File handle for PosixFile
+    DarwinMemoryHandle m_handle;
+};
+} // namespace Memory
+} // namespace Darwin
+} // namespace Os
+
+#endif // OS_Darwin_Memory_HPP
diff --git a/Os/File.cpp b/Os/File.cpp
index 26e3a27f73..4c243f1c81 100644
--- a/Os/File.cpp
+++ b/Os/File.cpp
@@ -233,5 +233,56 @@ File::Status File::finalizeCrc(U32 &crc) {
     this->m_crc = File::INITIAL_CRC;
     return status;
 }
+
+File::Status File::readline(U8* buffer, FwSignedSizeType &size, File::WaitType wait) {
+    const FwSignedSizeType requested_size = size;
+    FW_ASSERT(&this->m_delegate == reinterpret_cast<FileInterface*>(&this->m_handle_storage[0]));
+    FW_ASSERT(buffer != nullptr);
+    FW_ASSERT(size >= 0);
+    FW_ASSERT(this->m_mode < Mode::MAX_OPEN_MODE);
+    // Check that the file is open before attempting operation
+    if (OPEN_NO_MODE == this->m_mode) {
+        size = 0;
+        return File::Status::NOT_OPENED;
+    } else if (OPEN_READ != this->m_mode) {
+        size = 0;
+        return File::Status::INVALID_MODE;
+    }
+    FwSignedSizeType original_location;
+    File::Status status = this->position(original_location);
+    if (status != Os::File::Status::OP_OK) {
+        size = 0;
+        return status;
+    }
+    FwSignedSizeType read = 0;
+    // Loop reading chunk by chunk
+    for (FwSignedSizeType i = 0; i < size; i += read) {
+        FwSignedSizeType current_chunk_size = FW_MIN(size - i, FW_FILE_CHUNK_SIZE);
+        read = current_chunk_size;
+        status = this->read(buffer + i, read, wait);
+        if (status != File::Status::OP_OK) {
+            (void) this->seek(original_location, File::SeekType::ABSOLUTE);
+            return status;
+        }
+        // EOF break out now
+        if (read == 0) {
+            size = i;
+            return Os::File::Status::OP_OK;
+        }
+        // Loop from i to i + current_chunk_size looking for `\n`
+        for (FwSignedSizeType j = i; j < (i + read); j++) {
+            // Newline seek back to after it, return the size read
+            if (buffer[j] == '\n') {
+                size = j + 1;
+                // Ensure that the computation worked
+                FW_ASSERT(size <= requested_size);
+                (void) this->seek(original_location + j + 1, File::SeekType::ABSOLUTE);
+                return Os::File::Status::OP_OK;
+            }
+        }
+    }
+    // Failed to find newline within data available
+    return Os::File::Status::OTHER_ERROR;
+}
 } // Os
 
diff --git a/Os/File.hpp b/Os/File.hpp
index b189446d0f..4fb0cc1b71 100644
--- a/Os/File.hpp
+++ b/Os/File.hpp
@@ -382,10 +382,28 @@ namespace Os {
         //! \param buffer: memory location to store data read from file
         //! \param size: size of data to read
         //! \param wait: `WAIT` to wait for data, `NO_WAIT` to return what is currently available
-        //! \return OP_OK on success otherwise error status
+
         //!
         Status read(U8* buffer, FwSignedSizeType &size, WaitType wait) override;
 
+        //! \brief read a line from the file using `\n` as the delimiter
+        //!
+        //! Reads a single line from the file including the terminating '\n'. This will return an error if no line is
+        //! found within the specified buffer size. In the case of EOF, the line is read without the terminating '\n'.
+        //!
+        //! In the case of an error, this function will seek to the original location in the file. Otherwise, the
+        //! pointer will point to the first character after the `\n` or EOF in the case of no `\n`.
+        //!
+        //! It is invalid to send a null buffer.
+        //! It is invalid to send a size less than 0.
+        //! It is an error if the file is not opened for reading.
+        //!
+        //! \param buffer: memory location to store data read from file
+        //! \param size: maximum size of buffer to store the new line
+        //! \param wait: `WAIT` to wait for data, `NO_WAIT` to return what is currently available
+        //! \return OP_OK on success otherwise error status
+        Status readline(U8* buffer, FwSignedSizeType &size, WaitType wait);
+
         //! \brief read data from this file into supplied buffer bounded by size
         //!
         //! Write data to this file up to the `size` from the `buffer`.  When `wait` is set to `WAIT`, this
diff --git a/Os/Linux/CMakeLists.txt b/Os/Linux/CMakeLists.txt
new file mode 100644
index 0000000000..be3d3802ff
--- /dev/null
+++ b/Os/Linux/CMakeLists.txt
@@ -0,0 +1,58 @@
+####
+# F prime CMakeLists.txt:
+#
+# SOURCE_FILES: combined list of source and autocoding files
+# MOD_DEPS: (optional) module dependencies
+#
+####
+restrict_platforms(Linux)
+add_custom_target("${FPRIME_CURRENT_MODULE}")
+
+# -----------------------------------------
+### Os/Linux/Cpu Section
+# -----------------------------------------
+set(SOURCE_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/Cpu.cpp"
+)
+set(HEADER_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/Cpu.hpp"
+)
+set(MOD_DEPS
+    Fw_Types
+)
+register_fprime_module(Os_Cpu_Linux)
+register_fprime_implementation(Os/Cpu Os_Cpu_Linux "${CMAKE_CURRENT_LIST_DIR}/DefaultCpu.cpp")
+
+set(UT_SOURCE_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/../test/ut/cpu/CommonCpuTests.cpp"
+        "${CMAKE_CURRENT_LIST_DIR}/test/ut/LinuxCpuTests.cpp"
+)
+set(UT_MOD_DEPS
+        STest
+)
+choose_fprime_implementation(Os/Cpu Os_Cpu_Linux)
+register_fprime_ut(LinuxCpuTest)
+
+
+# -----------------------------------------
+### Os/Linux/Memory Section
+# -----------------------------------------
+set(SOURCE_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/Memory.cpp"
+)
+set(HEADER_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/Memory.hpp"
+)
+set(MOD_DEPS)
+register_fprime_module(Os_Memory_Linux)
+register_fprime_implementation(Os/Memory Os_Memory_Linux "${CMAKE_CURRENT_LIST_DIR}/DefaultMemory.cpp")
+
+set(UT_SOURCE_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/../test/ut/memory/CommonMemoryTests.cpp"
+        "${CMAKE_CURRENT_LIST_DIR}/test/ut/LinuxMemoryTests.cpp"
+)
+set(UT_MOD_DEPS
+        STest
+)
+choose_fprime_implementation(Os/Memory Os_Memory_Linux)
+register_fprime_ut(LinuxMemoryTest)
diff --git a/Os/Linux/Cpu.cpp b/Os/Linux/Cpu.cpp
new file mode 100644
index 0000000000..90436b8c30
--- /dev/null
+++ b/Os/Linux/Cpu.cpp
@@ -0,0 +1,111 @@
+// ======================================================================
+// \title Os/Linux/Cpu.cpp
+// \brief Linux implementation for Os::Cpu
+// ======================================================================
+#include <Os/Linux/Cpu.hpp>
+#include <Fw/Types/Assert.hpp>
+#include <Fw/Types/StringUtils.hpp>
+#include <Os/File.hpp>
+#include <unistd.h>
+#include <cstring>
+namespace Os {
+namespace Linux {
+namespace Cpu {
+
+// Proc FS /proc/stat file format example:
+//
+// cpu  270288 1598 88660 8470416 15185 9775 2990 867 0 0
+// cpu0 67462 108 22104 2118172 3779 2540 648 287 0 0
+// cpu1 74237 650 24059 2109680 2995 2447 667 93 0 0
+// cpu2 69388 630 22033 2115177 4428 2424 649 378 0 0
+// cpu3 59199 209 20462 2127387 3981 2363 1024 108 0 0
+// ...
+
+// Needed format, and compliant with kernel < 2.5
+enum ProcCpuMeasures {
+    CPU_NUMBER = 0,
+    USER = 1,
+    NICE = 2,
+    SYSTEM = 3,
+    IDLE = 4,
+    MAX_CPU_TICK_TYPES = 8
+};
+
+
+using ProcCpuData = FwSizeType[ProcCpuMeasures::MAX_CPU_TICK_TYPES];
+constexpr FwSizeType LINE_SIZE = 255; // log10(max(U64)) * 11 fields (kernel 2.6.33) = 220. Round to 256 - 1 (\0)
+
+CpuInterface::Status getCpuData(FwSizeType cpu_index, ProcCpuData data) {
+    Os::File file;
+    // Open the procfs file
+    constexpr char PROC_STAT_PATH[] = "/proc/stat";
+    if (file.open(PROC_STAT_PATH, Os::File::Mode::OPEN_READ) != Os::File::Status::OP_OK) {
+
+        return CpuInterface::Status::ERROR;
+    }
+    char proc_stat_line[LINE_SIZE + 1];
+    // File starts with cpu line, then individual CPUs.
+    for (FwSizeType i = 0; i < cpu_index + 2; i++) {
+        FwSignedSizeType read_size = sizeof proc_stat_line - 1;
+        Os::File::Status file_status = file.readline(reinterpret_cast<U8*>(proc_stat_line), read_size,
+                                                     Os::File::WaitType::NO_WAIT);
+        proc_stat_line[read_size + 1] = '\0'; // Null terminate
+        if (file_status != Os::File::Status::OP_OK) {
+            return CpuInterface::Status::ERROR;
+        }
+        // Make sure we've not strayed passed the cpu section
+        if (::strncmp(proc_stat_line, "cpu", 3) != 0) {
+            return CpuInterface::Status::ERROR;
+        }
+    }
+    char* token_start = proc_stat_line + 3; // Length of "cpu"
+    for (FwSizeType i = 0; i < ProcCpuMeasures::MAX_CPU_TICK_TYPES; i++) {
+        FwSizeType token = 0;
+        Fw::StringUtils::StringToNumberStatus status = Fw::StringUtils::string_to_number(
+            token_start, static_cast<FwSizeType>(sizeof proc_stat_line) - static_cast<FwSizeType>(token_start - proc_stat_line), token, &token_start);
+        // Check conversion success
+        if (status != Fw::StringUtils::StringToNumberStatus::SUCCESSFUL_CONVERSION) {
+            return CpuInterface::Status::ERROR;
+        }
+        data[i] = token;
+        // Check cpu index is correct
+        if (i == ProcCpuMeasures::CPU_NUMBER and data[i] != cpu_index) {
+            return CpuInterface::Status::ERROR;
+        }
+    }
+    return CpuInterface::Status::OP_OK;
+}
+
+CpuInterface::Status LinuxCpu::_getCount(FwSizeType& cpu_count) {
+    long cpus = sysconf(_SC_NPROCESSORS_ONLN);
+    if ((cpus > 0) && (static_cast<FwSizeType>(cpus) < std::numeric_limits<FwSizeType>::max())) {
+        cpu_count = static_cast<FwSizeType>(cpus);
+        return Status::OP_OK;
+    }
+    cpu_count = 0;
+    return Status::ERROR;
+}
+
+CpuInterface::Status LinuxCpu::_getTicks(Os::Cpu::Ticks& ticks, FwSizeType cpu_index) {
+    FwSizeType count = 0;
+    CpuInterface::Status status = this->_getCount(count);
+    if (status != CpuInterface::Status::OP_OK) {
+        return status;
+    } else if (cpu_index >= count) {
+        return CpuInterface::Status::ERROR;
+    }
+    ProcCpuData cpu_data = {0, 0, 0, 0, 0, 0, 0, 0};
+    status = getCpuData(cpu_index, cpu_data);
+    ticks.used = cpu_data[ProcCpuMeasures::USER] + cpu_data[ProcCpuMeasures::NICE] + cpu_data[ProcCpuMeasures::SYSTEM];
+    ticks.total = ticks.used + cpu_data[ProcCpuMeasures::IDLE];
+
+    return status;
+}
+
+CpuHandle* LinuxCpu::getHandle() {
+    return &this->m_handle;
+}
+
+} // namespace Cpu
+} // namespace Linux
+} // namespace Os
diff --git a/Os/Linux/Cpu.hpp b/Os/Linux/Cpu.hpp
new file mode 100644
index 0000000000..d32e084ac1
--- /dev/null
+++ b/Os/Linux/Cpu.hpp
@@ -0,0 +1,81 @@
+// ======================================================================
+// \title Os/Linux/Cpu.hpp
+// \brief Linux implementation for Os::Cpu, header and test definitions
+// ======================================================================
+#include <Os/Cpu.hpp>
+#include <Os/File.hpp>
+#ifndef OS_Linux_Cpu_HPP
+#define OS_Linux_Cpu_HPP
+
+namespace Os {
+namespace Linux {
+namespace Cpu {
+
+//! CpuHandle class definition for stub implementations.
+//!
+struct LinuxCpuHandle : public CpuHandle {};
+
+//! \brief stub implementation of Os::CpuInterface
+//!
+//! Linux implementation of `CpuInterface` for use as a delegate class handling stub console operations.
+//!
+class LinuxCpu : public CpuInterface {
+  public:
+    //! \brief constructor
+    //!
+    LinuxCpu() = default;
+
+    //! \brief copy constructor
+    LinuxCpu(const LinuxCpu& other) = delete;
+
+    //! \brief default copy assignment
+    CpuInterface& operator=(const CpuInterface& other) override = delete;
+
+    //! \brief destructor
+    //!
+    ~LinuxCpu() override = default;
+
+    // ------------------------------------
+    // Functions overrides
+    // ------------------------------------
+  public:
+
+    //! \brief Request the count of the CPUs detected by the system
+    //!
+    //! This method wraps delegates to the underlying implementation.
+    //!
+    //! \param cpu_count: (output) filled with CPU count on system
+    //! \return: OP_OK with valid CPU count, ERROR when error occurs
+    //!
+    Status _getCount(FwSizeType& cpu_count) override;
+
+    //! \brief Get the CPU tick information for a given CPU
+    //!
+    //! CPU ticks represent a small time slice of processor time. This will retrieve the used CPU ticks and total
+    //! ticks for a given CPU. This information in a running accumulation and thus a sample-to-sample
+    //! differencing is needed to see the 'realtime' changing load. This shall be done by the caller. This method wraps
+    //! delegates to the underlying implementation.
+    //!
+    //! \param ticks: (output) filled with the tick information for the given CPU
+    //! \param cpu_index: index for CPU to read. Default: 0
+    //! \return:  ERROR when error occurs, OK otherwise.
+    //!
+    Status _getTicks(Os::Cpu::Ticks& ticks, FwSizeType cpu_index) override;
+
+    //! \brief returns the raw console handle
+    //!
+    //! Gets the raw console handle from the implementation. Note: users must include the implementation specific
+    //! header to make any real use of this handle. Otherwise it will be as an opaque type.
+    //!
+    //! \return raw console handle
+    //!
+    CpuHandle *getHandle() override;
+  private:
+    //! File handle for PosixFile
+    LinuxCpuHandle m_handle;
+};
+} // namespace Cpu
+} // namespace Linux
+} // namespace Os
+
+#endif // OS_Linux_Cpu_HPP
diff --git a/Os/Linux/DefaultCpu.cpp b/Os/Linux/DefaultCpu.cpp
new file mode 100644
index 0000000000..529379f791
--- /dev/null
+++ b/Os/Linux/DefaultCpu.cpp
@@ -0,0 +1,13 @@
+// ======================================================================
+// \title Os/Linux/DefaultCpu.cpp
+// \brief sets default Os::Cpu to Linux implementation via linker
+// ======================================================================
+#include "Os/Cpu.hpp"
+#include "Os/Linux/Cpu.hpp"
+#include "Os/Delegate.hpp"
+
+namespace Os {
+CpuInterface* CpuInterface::getDelegate(CpuHandleStorage& aligned_new_memory) {
+    return Os::Delegate::makeDelegate<CpuInterface, Os::Linux::Cpu::LinuxCpu>(aligned_new_memory);
+}
+}
diff --git a/Os/Linux/DefaultMemory.cpp b/Os/Linux/DefaultMemory.cpp
new file mode 100644
index 0000000000..ee37737b81
--- /dev/null
+++ b/Os/Linux/DefaultMemory.cpp
@@ -0,0 +1,13 @@
+// ======================================================================
+// \title Os/Linux/DefaultMemory.cpp
+// \brief sets default Os::Memory to Linux implementation via linker
+// ======================================================================
+#include "Os/Memory.hpp"
+#include "Os/Linux/Memory.hpp"
+#include "Os/Delegate.hpp"
+
+namespace Os {
+MemoryInterface* MemoryInterface::getDelegate(MemoryHandleStorage& aligned_new_memory) {
+    return Os::Delegate::makeDelegate<MemoryInterface, Os::Linux::Memory::LinuxMemory>(aligned_new_memory);
+}
+}
diff --git a/Os/Linux/Memory.cpp b/Os/Linux/Memory.cpp
new file mode 100644
index 0000000000..f2bc9370a6
--- /dev/null
+++ b/Os/Linux/Memory.cpp
@@ -0,0 +1,36 @@
+// ======================================================================
+// \title Os/Linux/Memory.cpp
+// \brief Linux implementation for Os::Memory
+// ======================================================================
+#include <Os/Linux/Memory.hpp>
+#include <Fw/Types/Assert.hpp>
+#include <sys/sysinfo.h>
+#include <limits>
+#include <cstdio>
+namespace Os {
+namespace Linux {
+namespace Memory {
+
+MemoryInterface::Status LinuxMemory::_getUsage(Os::Memory::Usage& memory_usage) {
+    struct sysinfo info;
+    // Only error in sysinfo call is invalid address
+    FW_ASSERT(sysinfo(&info) == 0);
+    const FwSizeType MAX_MEASURABLE_RAM_UNITS =  std::numeric_limits<FwSizeType>::max() / info.mem_unit;
+    if ((MAX_MEASURABLE_RAM_UNITS < info.totalram) || (MAX_MEASURABLE_RAM_UNITS < info.freeram)) {
+        memory_usage.total = 1;
+        memory_usage.used = 1;
+        return Status::ERROR;
+    }
+
+    memory_usage.total = info.totalram * info.mem_unit;
+    memory_usage.used = info.freeram * info.mem_unit;
+    return Status::OP_OK;
+}
+
+MemoryHandle* LinuxMemory::getHandle() {
+    return &this->m_handle;
+}
+
+} // namespace Memory
+} // namespace Linux
+} // namespace Os
diff --git a/Os/Linux/Memory.hpp b/Os/Linux/Memory.hpp
new file mode 100644
index 0000000000..e932a6c82a
--- /dev/null
+++ b/Os/Linux/Memory.hpp
@@ -0,0 +1,67 @@
+// ======================================================================
+// \title Os/Linux/Memory.hpp
+// \brief Linux implementation for Os::Memory, header and test definitions
+// ======================================================================
+#include <Os/Memory.hpp>
+#ifndef OS_Linux_Memory_HPP
+#define OS_Linux_Memory_HPP
+
+namespace Os {
+namespace Linux {
+namespace Memory {
+
+//! MemoryHandle class definition for stub implementations.
+//!
+struct LinuxMemoryHandle : public MemoryHandle {
+};
+
+//! \brief stub implementation of Os::MemoryInterface
+//!
+//! Linux implementation of `MemoryInterface` for use as a delegate class handling stub console operations.
+//!
+class LinuxMemory : public MemoryInterface {
+  public:
+    //! \brief constructor
+    //!
+    LinuxMemory() = default;
+
+    //! \brief copy constructor
+    LinuxMemory(const LinuxMemory& other) = delete;
+
+    //! \brief default copy assignment
+    MemoryInterface& operator=(const MemoryInterface& other) override = delete;
+
+    //! \brief destructor
+    //!
+    ~LinuxMemory() override = default;
+
+    // ------------------------------------
+    // Functions overrides
+    // ------------------------------------
+  public:
+
+    //! \brief get system memory usage
+    //!
+    //! This method delegates to the underlying implementation.
+    //!
+    //! \param memory_usage: (output) data structure used to store memory usage
+    //! \return:  ERROR when error occurs, OK otherwise.
+    Status _getUsage(Os::Memory::Usage& memory_usage) override;
+
+    //! \brief returns the raw console handle
+    //!
+    //! Gets the raw console handle from the implementation. Note: users must include the implementation specific
+    //! header to make any real use of this handle. Otherwise it will be as an opaque type.
+    //!
+    //! \return raw console handle
+    //!
+    MemoryHandle *getHandle() override;
+  private:
+    //! File handle for PosixFile
+    LinuxMemoryHandle m_handle;
+};
+} // namespace Memory
+} // namespace Linux
+} // namespace Os
+
+#endif // OS_Linux_Memory_HPP
diff --git a/Os/Linux/SystemResources.cpp b/Os/Linux/SystemResources.cpp
index 439bc37c94..44c8683859 100644
--- a/Os/Linux/SystemResources.cpp
+++ b/Os/Linux/SystemResources.cpp
@@ -22,11 +22,6 @@ char proc_stat_line[LINE_SIZE];
 
 namespace Os {
 
-    SystemResources::SystemResourcesStatus SystemResources::getCpuCount(U32& cpuCount) {
-        cpuCount = static_cast<U32>(get_nprocs());
-        return SYSTEM_RESOURCES_OK;
-    }
-
     U64 getCpuUsed(U32 cpu_data[4]) {
         return cpu_data[0] + cpu_data[1] + cpu_data[2];
     }
diff --git a/Os/Memory.cpp b/Os/Memory.cpp
new file mode 100644
index 0000000000..6961491997
--- /dev/null
+++ b/Os/Memory.cpp
@@ -0,0 +1,38 @@
+// ======================================================================
+// \title Os/Memory.hpp
+// \brief common function implementations for Os::Memory
+// ======================================================================
+#include "Os/Memory.hpp"
+#include "Fw/Types/Assert.hpp"
+
+namespace Os {
+
+Memory::Memory() : m_delegate(*MemoryInterface::getDelegate(m_handle_storage)) {}
+
+Memory::~Memory() {
+    m_delegate.~MemoryInterface();
+}
+
+void Memory::init() {
+    (void) Memory::getSingleton();
+}
+
+Memory& Memory::getSingleton() {
+    static Memory _singleton;
+    return _singleton;
+}
+
+Memory::Status Memory::_getUsage(Os::Memory::Usage& memory_usage) {
+    FW_ASSERT(&this->m_delegate == reinterpret_cast<MemoryInterface*>(&this->m_handle_storage[0]));
+    return this->m_delegate._getUsage(memory_usage);
+}
+
+Memory::Status Memory::getUsage(Os::Memory::Usage& memory_usage) {
+    return Memory::getSingleton()._getUsage(memory_usage);
+}
+
+MemoryHandle* Memory::getHandle() {
+    FW_ASSERT(&this->m_delegate == reinterpret_cast<MemoryInterface*>(&this->m_handle_storage[0]));
+    return this->m_delegate.getHandle();
+}
+}
diff --git a/Os/Memory.hpp b/Os/Memory.hpp
new file mode 100644
index 0000000000..0d42b08fb5
--- /dev/null
+++ b/Os/Memory.hpp
@@ -0,0 +1,113 @@
+// ======================================================================
+// \title Os/Memory.hpp
+// \brief common function definitions for Os::Memory
+// ======================================================================
+#include "Os/Os.hpp"
+
+#ifndef OS_MEMORY_HPP_
+#define OS_MEMORY_HPP_
+
+namespace Os {
+
+//! \brief Memory variable handle parent
+class MemoryHandle {};
+
+//! \brief interface for memory implementation
+class MemoryInterface {
+  public:
+    using Status = Os::Generic::Status;
+    using Usage = Os::Generic::UsedTotal;
+
+    //! Default constructor
+    MemoryInterface() = default;
+    //! Default destructor
+    virtual ~MemoryInterface() = default;
+
+    //! \brief copy constructor is forbidden
+    MemoryInterface(const MemoryInterface& other) = delete;
+
+    //! \brief assignment operator is forbidden
+    virtual MemoryInterface& operator=(const MemoryInterface& other) = delete;
+
+    //! \brief get system memory usage
+    //!
+    //! \param memory_usage: (output) data structure used to store memory usage
+    //! \return: ERROR when error occurs, OK otherwise.
+    virtual Status _getUsage(Usage& memory_usage) = 0;
+
+    //! \brief return the underlying memory handle (implementation specific).
+    //! \return internal task handle representation
+    virtual MemoryHandle* getHandle() = 0;
+
+    //! \brief provide a pointer to a Mutex delegate object
+    static MemoryInterface* getDelegate(MemoryHandleStorage& aligned_new_memory);
+};
+
+//! \brief memory implementation
+class Memory final : public MemoryInterface {
+  public:
+    //! \brief default constructor
+    Memory();
+
+    //! \brief default virtual destructor
+    ~Memory() final;
+
+    //! \brief copy constructor is forbidden
+    Memory(const MemoryInterface& other) = delete;
+
+    //! \brief copy constructor is forbidden
+    Memory(const MemoryInterface* other) = delete;
+
+    //! \brief assignment operator is forbidden
+    MemoryInterface& operator=(const MemoryInterface& other) override = delete;
+
+    //-----------------------------------------------------------------------------
+    // Interface methods
+    //-----------------------------------------------------------------------------
+  public:
+
+    //! \brief initialize the singleton
+    void init();
+
+    //! \brief return singleton
+    static Memory& getSingleton();
+
+    //-----------------------------------------------------------------------------
+    // Delegating methods
+    //-----------------------------------------------------------------------------
+
+    //! \brief get system memory usage
+    //!
+    //! This method delegates to the underlying implementation.
+    //!
+    //! \param memory_usage: (output) data structure used to store memory usage
+    //! \return:  ERROR when error occurs, OK otherwise.
+    Status _getUsage(Usage& memory_usage) override;
+
+
+    //! \brief return the underlying memory handle (implementation specific).
+    //! \return internal task handle representation
+    MemoryHandle* getHandle() override;
+
+    //-----------------------------------------------------------------------------
+    // Static interface (singleton) methods
+    //-----------------------------------------------------------------------------
+
+    //! \brief get system memory usage
+    //!
+    //! This method wraps delegates to the underlying implementation.
+    //!
+    //! \param memory_usage: (output) data structure used to store memory usage
+    //! \return: ERROR when error occurs, OK otherwise.
+    static Status getUsage(Usage& memory);
+
+  private:
+
+    // This section is used to store the implementation-defined file handle. To Os::File and fprime, this type is
+    // opaque and thus normal allocation cannot be done. Instead, we allow the implementor to store then handle in
+    // the byte-array here and set `handle` to that address for storage.
+    alignas(FW_HANDLE_ALIGNMENT) MemoryHandleStorage m_handle_storage; //!< Storage for aligned data
+    MemoryInterface& m_delegate;                                       //!< Delegate for the real implementation
+};
+}
+#endif //OS_CONDITION_HPP_
diff --git a/Os/Models/CMakeLists.txt b/Os/Models/CMakeLists.txt
index 1d3d0a408e..4cfb1fe0c6 100644
--- a/Os/Models/CMakeLists.txt
+++ b/Os/Models/CMakeLists.txt
@@ -12,5 +12,7 @@ set(SOURCE_FILES
     "${CMAKE_CURRENT_LIST_DIR}/Mutex.fpp"
     "${CMAKE_CURRENT_LIST_DIR}/Directory.fpp"
     "${CMAKE_CURRENT_LIST_DIR}/FileSystem.fpp"
+    "${CMAKE_CURRENT_LIST_DIR}/Generic.fpp"
+    "${CMAKE_CURRENT_LIST_DIR}/Models.cpp"
 )
 register_fprime_module()
diff --git a/Os/Models/Generic.fpp b/Os/Models/Generic.fpp
new file mode 100644
index 0000000000..da4d28239d
--- /dev/null
+++ b/Os/Models/Generic.fpp
@@ -0,0 +1,13 @@
+# ======================================================================
+# \title Os/Models/Generic.fpp
+# \brief FPP type definitions for Os/Os.hpp concepts
+# ======================================================================
+
+module Os {
+@ FPP shadow-enum representing Os::Generic::Status
+enum GenericStatus {
+    OP_OK, @< operation okay
+    ERROR, @< error return value
+}
+}
+
diff --git a/Os/Models/Models.hpp b/Os/Models/Models.cpp
similarity index 96%
rename from Os/Models/Models.hpp
rename to Os/Models/Models.cpp
index c3741da482..5748e8c3be 100644
--- a/Os/Models/Models.hpp
+++ b/Os/Models/Models.cpp
@@ -1,11 +1,7 @@
 // ======================================================================
-// \title Os/Models/Models.hpp
-// \brief header used to validate Os/Models before use
+// \title Os/Models/Models.cpp
+// \brief test used to validate Os/Models before use
 // ======================================================================
-
-#ifndef OS_MODELS_MODELS_HPP
-#define OS_MODELS_MODELS_HPP
-
 #include "Os/Models/FileStatusEnumAc.hpp"
 #include "Os/Models/FileModeEnumAc.hpp"
 #include "Os/Models/TaskStatusEnumAc.hpp"
@@ -13,11 +9,13 @@
 #include "Os/Models/DirectoryStatusEnumAc.hpp"
 #include "Os/Models/DirectoryOpenModeEnumAc.hpp"
 #include "Os/Models/FileSystemStatusEnumAc.hpp"
+#include "Os/Models/GenericStatusEnumAc.hpp"
 #include "Os/File.hpp"
 #include "Os/Task.hpp"
 #include "Os/Mutex.hpp"
 #include "Os/Directory.hpp"
 #include "Os/FileSystem.hpp"
+#include "Os/Os.hpp"
 
 // Check consistency of every constant in the Os::File::Status enum
 static_assert(static_cast<FwIndexType>(Os::File::Status::MAX_STATUS) ==
@@ -169,5 +167,8 @@ static_assert(static_cast<Os::FileSystemStatus::T>(Os::FileSystem::Status::NOT_S
 static_assert(static_cast<Os::FileSystemStatus::T>(Os::FileSystem::Status::OTHER_ERROR) == Os::FileSystemStatus::T::OTHER_ERROR,
               "FileSystem status and FPP shadow enum do not match");
 
-
-#endif // OS_MODELS_MODELS_HPP
+// Check Generic mappings
+static_assert(static_cast<Os::GenericStatus::T>(Os::Generic::Status::OP_OK) == Os::GenericStatus::T::OP_OK,
+              "Generic status enums do not match");
+static_assert(static_cast<Os::GenericStatus::T>(Os::Generic::Status::ERROR) == Os::GenericStatus::T::ERROR,
+              "Generic status enums do not match");
diff --git a/Os/Os.hpp b/Os/Os.hpp
index feee9aaf7f..d839d00e88 100644
--- a/Os/Os.hpp
+++ b/Os/Os.hpp
@@ -12,8 +12,24 @@ typedef U8 HandleStorage[FW_HANDLE_MAX_SIZE];
 typedef U8 DirectoryHandleStorage[FW_DIRECTORY_HANDLE_MAX_SIZE];
 typedef U8 FileSystemHandleStorage[FW_FILESYSTEM_HANDLE_MAX_SIZE];
 typedef U8 ConditionVariableHandleStorage[FW_CONDITION_VARIABLE_HANDLE_MAX_SIZE];
+typedef U8 CpuHandleStorage[FW_CPU_HANDLE_MAX_SIZE];
+typedef U8 MemoryHandleStorage[FW_MEMORY_HANDLE_MAX_SIZE];
 
 namespace Os {
+namespace Generic {
+//! Generic OK/ERROR status
+enum Status {
+    OP_OK, //!< Operation succeeded
+    ERROR, //!< Operation failed
+};
+
+//! Generic used/total struct
+struct UsedTotal {
+    FwSizeType used; //!< Used amount
+    FwSizeType total; //!< Total amount
+};
+
+}
 
 //! \brief Initialization function for the OSAL layer
 void init();
diff --git a/Os/Posix/CMakeLists.txt b/Os/Posix/CMakeLists.txt
index 954a215e21..00533eecd7 100644
--- a/Os/Posix/CMakeLists.txt
+++ b/Os/Posix/CMakeLists.txt
@@ -83,7 +83,7 @@ set(HEADER_FILES
     "${CMAKE_CURRENT_LIST_DIR}/Task.hpp"
 )
 
-set(MOD_DEPS Os_Posix_Shared Fw/Time Os) # Os needs to be removed here?
+set(MOD_DEPS Os_Posix_Shared Fw/Time Os)
 register_fprime_module(Os_Task_Posix)
 register_fprime_implementation(Os/Task Os_Task_Posix "${CMAKE_CURRENT_LIST_DIR}/DefaultTask.cpp")
 
diff --git a/Os/Stub/CMakeLists.txt b/Os/Stub/CMakeLists.txt
index 89d1789bfa..15c23e3507 100644
--- a/Os/Stub/CMakeLists.txt
+++ b/Os/Stub/CMakeLists.txt
@@ -10,11 +10,10 @@ add_custom_target("${FPRIME_CURRENT_MODULE}")
 ######## File Stub ########
 set(SOURCE_FILES
     "${CMAKE_CURRENT_LIST_DIR}/File.cpp"
-    "${CMAKE_CURRENT_LIST_DIR}/DefaultFile.cpp"
 )
 set(MOD_DEPS config)
 register_fprime_module(Os_File_Stub)
-register_fprime_implementation(Os/File Os_File_Stub)
+register_fprime_implementation(Os/File Os_File_Stub "${CMAKE_CURRENT_LIST_DIR}/DefaultFile.cpp")
 
 ######## Mutex Stub ########
 set(SOURCE_FILES
@@ -74,6 +73,28 @@ set(MOD_DEPS config)
 register_fprime_module(Os_Directory_Stub)
 register_fprime_implementation(Os/Directory Os_Directory_Stub "${CMAKE_CURRENT_LIST_DIR}/DefaultDirectory.cpp")
 
+#### Cpu Stub ####
+set(SOURCE_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/Cpu.cpp"
+)
+set(HEADER_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/Cpu.hpp"
+)
+set(MOD_DEPS)
+register_fprime_module(Os_Stub_Cpu)
+register_fprime_implementation(Os/Cpu Os_Stub_Cpu "${CMAKE_CURRENT_LIST_DIR}/DefaultCpu.cpp")
+
+#### Memory Stub ####
+set(SOURCE_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/Memory.cpp"
+)
+set(HEADER_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/Memory.hpp"
+)
+set(MOD_DEPS)
+register_fprime_module(Os_Stub_Memory)
+register_fprime_implementation(Os/Memory Os_Stub_Memory "${CMAKE_CURRENT_LIST_DIR}/DefaultMemory.cpp")
+
 # Remainder of file is specific to UTs
 if (NOT BUILD_TESTING)
     return()
@@ -82,10 +103,9 @@ endif ()
 #### File Stub Testing ####
 set(SOURCE_FILES
     "${CMAKE_CURRENT_LIST_DIR}/test/File.cpp"
-    "${CMAKE_CURRENT_LIST_DIR}/test/DefaultFile.cpp"
 )
 register_fprime_module(Os_File_Test_Stub)
-register_fprime_implementation(Os/File Os_File_Test_Stub)
+register_fprime_implementation(Os/File Os_File_Test_Stub "${CMAKE_CURRENT_LIST_DIR}/test/DefaultFile.cpp")
 
 set(UT_SOURCE_FILES
     "${CMAKE_CURRENT_LIST_DIR}/test/ut/StubFileTests.cpp"
@@ -113,9 +133,44 @@ set(UT_SOURCE_FILES
         "${CMAKE_CURRENT_LIST_DIR}/test/ut/StubConsoleTests.cpp"
 )
 set(UT_MOD_DEPS)
+choose_fprime_implementation(Os/File Os_File_Stub)
 choose_fprime_implementation(Os/Console Os_Console_Test_Stub)
 register_fprime_ut(StubConsoleTest)
 
+#### Cpu Stub Testing ####
+set(SOURCE_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/test/Cpu.cpp"
+)
+set(MOD_DEPS)
+register_fprime_module(Os_Cpu_Test_Stub)
+register_fprime_implementation(Os/Cpu Os_Cpu_Test_Stub "${CMAKE_CURRENT_LIST_DIR}/test/DefaultCpu.cpp")
+
+set(UT_SOURCE_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/test/ut/StubCpuTests.cpp"
+)
+set(UT_MOD_DEPS
+    STest
+)
+choose_fprime_implementation(Os/Cpu Os_Cpu_Test_Stub)
+register_fprime_ut(StubCpuTest)
+
+#### Memory Stub Testing ####
+set(SOURCE_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/test/Memory.cpp"
+)
+set(MOD_DEPS)
+register_fprime_module(Os_Memory_Test_Stub)
+register_fprime_implementation(Os/Cpu Os_Memory_Test_Stub "${CMAKE_CURRENT_LIST_DIR}/test/DefaultMemory.cpp")
+
+set(UT_SOURCE_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/test/ut/StubMemoryTests.cpp"
+)
+set(UT_MOD_DEPS
+        STest
+)
+choose_fprime_implementation(Os/Memory Os_Memory_Test_Stub)
+register_fprime_ut(StubMemoryTest)
+
 
 #### Queue Stub Testing ####
 set(SOURCE_FILES
@@ -247,4 +302,6 @@ choose_fprime_implementation(Os/File Os_File_Stub)
 choose_fprime_implementation(Os/Console Os_Console_Stub)
 choose_fprime_implementation(Os/FileSystem Os_FileSystem_Stub)
 choose_fprime_implementation(Os/Directory Os_Directory_Stub)
+choose_fprime_implementation(Os/Cpu Os_Stub_Cpu)
+choose_fprime_implementation(Os/Memory Os_Stub_Memory)
 register_fprime_ut(StubTest)
diff --git a/Os/Stub/ConditionVariable.hpp b/Os/Stub/ConditionVariable.hpp
index a35623802a..22390cc484 100644
--- a/Os/Stub/ConditionVariable.hpp
+++ b/Os/Stub/ConditionVariable.hpp
@@ -25,6 +25,9 @@ class StubConditionVariable : public ConditionVariableInterface {
     //! \brief destructor
     //!
     ~StubConditionVariable() override = default;
+    
+    //! \brief assignment operator is forbidden
+    ConditionVariableInterface& operator=(const ConditionVariableInterface& other) override = delete;
 
     //! \brief wait releasing mutex
     void wait(Os::Mutex& mutex) override;
@@ -38,9 +41,6 @@ class StubConditionVariable : public ConditionVariableInterface {
     //! \brief get handle
     ConditionVariableHandle* getHandle() override;
 
-    //! \brief assignment operator is forbidden
-    virtual ConditionVariableInterface& operator=(const ConditionVariableInterface& other) override = delete;
-
   private:
     //! Handle for PosixMutex
     StubConditionVariableHandle m_handle;
diff --git a/Os/Stub/Cpu.cpp b/Os/Stub/Cpu.cpp
new file mode 100644
index 0000000000..e78f541d1f
--- /dev/null
+++ b/Os/Stub/Cpu.cpp
@@ -0,0 +1,28 @@
+// ======================================================================
+// \title Os/Stub/Cpu.cpp
+// \brief stub implementation for Os::Cpu
+// ======================================================================
+#include <Os/Stub/Cpu.hpp>
+
+namespace Os {
+namespace Stub {
+namespace Cpu {
+
+CpuInterface::Status StubCpu::_getCount(FwSizeType& cpu_count) {
+    cpu_count = 0;
+    return Status::ERROR;
+}
+
+CpuInterface::Status StubCpu::_getTicks(Os::Cpu::Ticks& ticks, FwSizeType cpu_index) {
+    ticks.total = 1;
+    ticks.used = 1;
+    return Status::ERROR;
+}
+
+CpuHandle* StubCpu::getHandle() {
+    return &this->m_handle;
+}
+
+} // namespace Cpu
+} // namespace Stub
+} // namespace Os
diff --git a/Os/Stub/Cpu.hpp b/Os/Stub/Cpu.hpp
new file mode 100644
index 0000000000..469a0d9e25
--- /dev/null
+++ b/Os/Stub/Cpu.hpp
@@ -0,0 +1,82 @@
+// ======================================================================
+// \title Os/Stub/Cpu.hpp
+// \brief stub implementation for Os::Cpu, header and test definitions
+// ======================================================================
+#include <cstdio>
+#include <Os/Cpu.hpp>
+#ifndef OS_Stub_Cpu_HPP
+#define OS_Stub_Cpu_HPP
+
+namespace Os {
+namespace Stub {
+namespace Cpu {
+
+//! CpuHandle class definition for stub implementations.
+//!
+struct StubCpuHandle : public CpuHandle {
+};
+
+//! \brief stub implementation of Os::CpuInterface
+//!
+//! Stub implementation of `CpuInterface` for use as a delegate class handling stub console operations.
+//!
+class StubCpu : public CpuInterface {
+  public:
+    //! \brief constructor
+    //!
+    StubCpu() = default;
+
+    //! \brief copy constructor
+    StubCpu(const StubCpu& other) = delete;
+
+    //! \brief default copy assignment
+    CpuInterface& operator=(const CpuInterface& other) override = delete;
+
+    //! \brief destructor
+    //!
+    ~StubCpu() override = default;
+
+    // ------------------------------------
+    // Functions overrides
+    // ------------------------------------
+  public:
+
+    //! \brief Request the count of the CPUs detected by the system
+    //!
+    //! This method wraps delegates to the underlying implementation.
+    //!
+    //! \param cpu_count: (output) filled with CPU count on system
+    //! \return: OP_OK with valid CPU count, ERROR when error occurs
+    //!
+    Status _getCount(FwSizeType& cpu_count) override;
+
+    //! \brief Get the CPU tick information for a given CPU
+    //!
+    //! CPU ticks represent a small time slice of processor time. This will retrieve the used CPU ticks and total
+    //! ticks for a given CPU. This information in a running accumulation and thus a sample-to-sample
+    //! differencing is needed to see the 'realtime' changing load. This shall be done by the caller. This method wraps
+    //! delegates to the underlying implementation.
+    //!
+    //! \param ticks: (output) filled with the tick information for the given CPU
+    //! \param cpu_index: index for CPU to read. Default: 0
+    //! \return:  ERROR when error occurs, OK otherwise.
+    //!
+    Status _getTicks(Ticks& ticks, FwSizeType cpu_index) override;
+
+    //! \brief returns the raw console handle
+    //!
+    //! Gets the raw console handle from the implementation. Note: users must include the implementation specific
+    //! header to make any real use of this handle. Otherwise it will be as an opaque type.
+    //!
+    //! \return raw console handle
+    //!
+    CpuHandle *getHandle() override;
+  private:
+    //! File handle for PosixFile
+    StubCpuHandle m_handle;
+};
+} // namespace Cpu
+} // namespace Stub
+} // namespace Os
+
+#endif // OS_Stub_Cpu_HPP
diff --git a/Os/Stub/DefaultCpu.cpp b/Os/Stub/DefaultCpu.cpp
new file mode 100644
index 0000000000..59d8c27221
--- /dev/null
+++ b/Os/Stub/DefaultCpu.cpp
@@ -0,0 +1,13 @@
+// ======================================================================
+// \title Os/Stub/DefaultCpu.cpp
+// \brief sets default Os::Cpu to stub implementation via linker
+// ======================================================================
+#include "Os/Cpu.hpp"
+#include "Os/Stub/Cpu.hpp"
+#include "Os/Delegate.hpp"
+
+namespace Os {
+CpuInterface* CpuInterface::getDelegate(CpuHandleStorage& aligned_new_memory) {
+    return Os::Delegate::makeDelegate<CpuInterface, Os::Stub::Cpu::StubCpu>(aligned_new_memory);
+}
+}
diff --git a/Os/Stub/DefaultMemory.cpp b/Os/Stub/DefaultMemory.cpp
new file mode 100644
index 0000000000..7ec0467306
--- /dev/null
+++ b/Os/Stub/DefaultMemory.cpp
@@ -0,0 +1,13 @@
+// ======================================================================
+// \title Os/Stub/DefaultMemory.cpp
+// \brief sets default Os::Memory to stub implementation via linker
+// ======================================================================
+#include "Os/Memory.hpp"
+#include "Os/Stub/Memory.hpp"
+#include "Os/Delegate.hpp"
+
+namespace Os {
+MemoryInterface* MemoryInterface::getDelegate(MemoryHandleStorage& aligned_new_memory) {
+    return Os::Delegate::makeDelegate<MemoryInterface, Os::Stub::Memory::StubMemory>(aligned_new_memory);
+}
+}
diff --git a/Os/Stub/Memory.cpp b/Os/Stub/Memory.cpp
new file mode 100644
index 0000000000..791dcb4ce7
--- /dev/null
+++ b/Os/Stub/Memory.cpp
@@ -0,0 +1,24 @@
+// ======================================================================
+// \title Os/Stub/Memory.cpp
+// \brief stub implementation for Os::Memory
+// ======================================================================
+#include <Os/Stub/Memory.hpp>
+
+namespace Os {
+namespace Stub {
+namespace Memory {
+
+MemoryInterface::Status StubMemory::_getUsage(Os::Memory::Usage& memory_usage) {
+    memory_usage.used = 0;
+    memory_usage.total = 0;
+    return Status::ERROR;
+}
+
+
+MemoryHandle* StubMemory::getHandle() {
+    return &this->m_handle;
+}
+
+} // namespace Memory
+} // namespace Stub
+} // namespace Os
diff --git a/Os/Stub/Memory.hpp b/Os/Stub/Memory.hpp
new file mode 100644
index 0000000000..81a4eeb615
--- /dev/null
+++ b/Os/Stub/Memory.hpp
@@ -0,0 +1,67 @@
+// ======================================================================
+// \title Os/Stub/Memory.hpp
+// \brief stub implementation for Os::Memory, header and test definitions
+// ======================================================================
+#include <cstdio>
+#include <Os/Memory.hpp>
+#ifndef OS_Stub_Memory_HPP
+#define OS_Stub_Memory_HPP
+
+namespace Os {
+namespace Stub {
+namespace Memory {
+
+//! MemoryHandle class definition for stub implementations.
+//!
+struct StubMemoryHandle : public MemoryHandle {
+};
+
+//! \brief stub implementation of Os::MemoryInterface
+//!
+//! Stub implementation of `MemoryInterface` for use as a delegate class handling stub console operations.
+//!
+class StubMemory : public MemoryInterface {
+  public:
+    //! \brief constructor
+    //!
+    StubMemory() = default;
+
+    //! \brief copy constructor
+    StubMemory(const StubMemory& other) = delete;
+
+    //! \brief default copy assignment
+    MemoryInterface& operator=(const MemoryInterface& other) override = delete;
+
+    //! \brief destructor
+    //!
+    ~StubMemory() override = default;
+
+    // ------------------------------------
+    // Functions overrides
+    // ------------------------------------
+
+    //! \brief get system memory usage
+    //!
+    //! This method delegates to the underlying implementation.
+    //!
+    //! \param memory_usage: (output) data structure used to store memory usage
+    //! \return:  ERROR when error occurs, OK otherwise.
+    Status _getUsage(Usage& memory_usage) override;
+
+    //! \brief returns the raw console handle
+    //!
+    //! Gets the raw console handle from the implementation. Note: users must include the implementation specific
+    //! header to make any real use of this handle. Otherwise it will be as an opaque type.
+    //!
+    //! \return raw console handle
+    //!
+    MemoryHandle *getHandle() override;
+  private:
+    //! File handle for PosixFile
+    StubMemoryHandle m_handle;
+};
+} // namespace Memory
+} // namespace Stub
+} // namespace Os
+
+#endif // OS_Stub_Memory_HPP
diff --git a/Svc/SystemResources/SystemResources.cpp b/Svc/SystemResources/SystemResources.cpp
index b833792074..e8f5a2becb 100644
--- a/Svc/SystemResources/SystemResources.cpp
+++ b/Svc/SystemResources/SystemResources.cpp
@@ -33,7 +33,7 @@ SystemResources ::SystemResources(const char* const compName)
         m_cpu_prev[i].total = 0;
     }
 
-    if (Os::SystemResources::getCpuCount(m_cpu_count) == Os::SystemResources::SYSTEM_RESOURCES_ERROR) {
+    if (Os::Cpu::getCount(m_cpu_count) == Os::Generic::ERROR) {
         m_cpu_count = 0;
     }
 
@@ -82,7 +82,7 @@ void SystemResources ::ENABLE_cmdHandler(const FwOpcodeType opCode,
     this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
 }
 
-F32 SystemResources::compCpuUtil(Os::SystemResources::CpuTicks current, Os::SystemResources::CpuTicks previous) {
+F32 SystemResources::compCpuUtil(Os::Cpu::Ticks current, Os::Cpu::Ticks previous) {
     F32 util = 100.0f;
     // Prevent divide by zero on fast-sample
     if ((current.total - previous.total) != 0) {
@@ -99,9 +99,9 @@ void SystemResources::Cpu() {
     F32 cpuAvg = 0;
 
     for (U32 i = 0; i < m_cpu_count && i < CPU_COUNT; i++) {
-        Os::SystemResources::SystemResourcesStatus status = Os::SystemResources::getCpuTicks(m_cpu[i], i);
+        Os::Cpu::Status status = Os::Cpu::getTicks(m_cpu[i], i);
         // Best-effort calculations and telemetry
-        if (status == Os::SystemResources::SYSTEM_RESOURCES_OK) {
+        if (status == Os::Generic::OP_OK) {
             F32 cpuUtil = compCpuUtil(m_cpu[i], m_cpu_prev[i]);
             cpuAvg += cpuUtil;
 
@@ -120,7 +120,7 @@ void SystemResources::Cpu() {
 }
 
 void SystemResources::Mem() {
-    if (Os::SystemResources::getMemUtil(m_mem) == Os::SystemResources::SYSTEM_RESOURCES_OK) {
+    if (Os::Memory::getUsage(m_mem) == Os::Generic::OP_OK) {
         this->tlmWrite_MEMORY_TOTAL(m_mem.total / 1024);
         this->tlmWrite_MEMORY_USED(m_mem.used / 1024);
     }
diff --git a/Svc/SystemResources/SystemResources.hpp b/Svc/SystemResources/SystemResources.hpp
index 44485943db..7d0e47e153 100644
--- a/Svc/SystemResources/SystemResources.hpp
+++ b/Svc/SystemResources/SystemResources.hpp
@@ -14,7 +14,8 @@
 #define SystemResources_HPP
 
 #include "Svc/SystemResources/SystemResourcesComponentAc.hpp"
-#include "Os/SystemResources.hpp"
+#include "Os/Cpu.hpp"
+#include "Os/Memory.hpp"
 #include "Os/FileSystem.hpp"
 
 namespace Svc {
@@ -67,17 +68,17 @@ class SystemResources : public SystemResourcesComponentBase {
     void Cpu();
     void Mem();
     void PhysMem();
-    F32 compCpuUtil(Os::SystemResources::CpuTicks current, Os::SystemResources::CpuTicks previous);
+    F32 compCpuUtil(Os::Cpu::Ticks current, Os::Cpu::Ticks previous);
 
 
     static const U32 CPU_COUNT = 16; /*!< Maximum number of CPUs to report as telemetry */
 
     cpuTlmFunc m_cpu_tlm_functions[CPU_COUNT];       /*!< Function pointer to specific CPU telemetry */
-    U32 m_cpu_count;                                     /*!< Number of CPUs used by the system */
-    Os::SystemResources::MemUtil m_mem;                  /*!< RAM memory information */
-    Os::SystemResources::CpuTicks m_cpu[CPU_COUNT];      /*!< CPU information for each CPU on the system */
-    Os::SystemResources::CpuTicks m_cpu_prev[CPU_COUNT]; /*!< Previous iteration CPU information */
-    bool m_enable;                                       /*!< Send telemetry when TRUE.  Don't send when FALSE */
+    FwSizeType m_cpu_count;                          /*!< Number of CPUs used by the system */
+    Os::Memory::Usage m_mem;                         /*!< RAM memory information */
+    Os::Cpu::Ticks m_cpu[CPU_COUNT];                 /*!< CPU information for each CPU on the system */
+    Os::Cpu::Ticks m_cpu_prev[CPU_COUNT];            /*!< Previous iteration CPU information */
+    bool m_enable;                                   /*!< Send telemetry when TRUE.  Don't send when FALSE */
 };
 
 }  // end namespace Svc
diff --git a/cmake/API.cmake b/cmake/API.cmake
index 72e0ec677d..7b1741d959 100644
--- a/cmake/API.cmake
+++ b/cmake/API.cmake
@@ -237,6 +237,9 @@ function(register_fprime_module)
     endif()
     # Explicit call to module register
     generate_library("${MODULE_NAME}" "${SOURCE_FILES}" "${MOD_DEPS}")
+    if (TARGET "${MODULE_NAME}")
+        add_dependencies("${MODULE_NAME}" config)
+    endif()
 endfunction(register_fprime_module)
 
 ####
diff --git a/cmake/platform/Darwin.cmake b/cmake/platform/Darwin.cmake
index e31696aa1c..52425e9a8b 100644
--- a/cmake/platform/Darwin.cmake
+++ b/cmake/platform/Darwin.cmake
@@ -26,5 +26,8 @@ choose_fprime_implementation(Os/Task Os/Task/Posix)
 choose_fprime_implementation(Os/Mutex Os/Mutex/Posix)
 choose_fprime_implementation(Os/Queue Os/Generic/PriorityQueue)
 
+choose_fprime_implementation(Os/Cpu Os/Cpu/Darwin)
+choose_fprime_implementation(Os/Memory Os/Memory/Darwin)
+
 # Add linux include path which is compatible with Darwin for PlatformTypes.hpp
 include_directories(SYSTEM "${CMAKE_CURRENT_LIST_DIR}/types")
diff --git a/cmake/platform/Linux.cmake b/cmake/platform/Linux.cmake
index ddffd42699..99009e2d96 100644
--- a/cmake/platform/Linux.cmake
+++ b/cmake/platform/Linux.cmake
@@ -17,6 +17,9 @@ choose_fprime_implementation(Os/Task Os/Task/Posix)
 choose_fprime_implementation(Os/Mutex Os/Mutex/Posix)
 choose_fprime_implementation(Os/Queue Os/Generic/PriorityQueue)
 
+choose_fprime_implementation(Os/Cpu Os/Cpu/Linux)
+choose_fprime_implementation(Os/Memory Os/Memory/Linux)
+
 # Use common linux setup
 add_definitions(-DTGT_OS_TYPE_LINUX)
 set(FPRIME_USE_POSIX ON)
diff --git a/config/FpConfig.h b/config/FpConfig.h
index f30bb30043..31e42665a4 100644
--- a/config/FpConfig.h
+++ b/config/FpConfig.h
@@ -405,6 +405,14 @@ typedef FwIndexType FwQueueSizeType;
 #define FW_CONDITION_VARIABLE_HANDLE_MAX_SIZE 56  //!< Maximum size of a handle for OS condition variables
 #endif
 
+#ifndef FW_CPU_HANDLE_MAX_SIZE
+#define FW_CPU_HANDLE_MAX_SIZE 16  //!< Maximum size of a handle for OS cpu
+#endif
+
+#ifndef FW_MEMORY_HANDLE_MAX_SIZE
+#define FW_MEMORY_HANDLE_MAX_SIZE 16  //!< Maximum size of a handle for OS memory
+#endif
+
 #ifndef FW_HANDLE_ALIGNMENT
 #define FW_HANDLE_ALIGNMENT 8  //!< Alignment of handle storage
 #endif


Test patch:
diff --git a/Fw/Types/test/ut/TypesTest.cpp b/Fw/Types/test/ut/TypesTest.cpp
index 20b801306a..406dcf3154 100644
--- a/Fw/Types/test/ut/TypesTest.cpp
+++ b/Fw/Types/test/ut/TypesTest.cpp
@@ -657,9 +657,6 @@ TEST(PerformanceTest, SerPerfTest) {
     MySerializable out;
     SerializeTestBuffer buff;
 
-    Os::InterruptLock intLock;
-
-    intLock.lock();
     timer.start();
 
     I32 iterations = 1000000;
@@ -669,7 +666,6 @@ TEST(PerformanceTest, SerPerfTest) {
     }
 
     timer.stop();
-    intLock.unLock();
 
     printf("%d iterations took %d us (%f each).\n", iterations, timer.getDiffUsec(),
            static_cast<F32>(timer.getDiffUsec()) / static_cast<F32>(iterations));
@@ -679,10 +675,8 @@ TEST(PerformanceTest, StructCopyTest) {
     char buff[sizeof(TestStruct)];
     TestStruct ts;
 
-    Os::InterruptLock intLock;
     Os::IntervalTimer timer;
 
-    intLock.lock();
     timer.start();
 
     I32 iterations = 1000000;
@@ -699,7 +693,6 @@ TEST(PerformanceTest, StructCopyTest) {
     }
 
     timer.stop();
-    intLock.unLock();
 
     printf("%d iterations took %d us (%f each).\n", iterations, timer.getDiffUsec(),
            static_cast<F32>(timer.getDiffUsec()) / static_cast<F32>(iterations));
@@ -709,10 +702,8 @@ TEST(PerformanceTest, ClassCopyTest) {
     char buff[sizeof(MySerializable)];
     MySerializable ms;
 
-    Os::InterruptLock intLock;
     Os::IntervalTimer timer;
 
-    intLock.lock();
     timer.start();
 
     I32 iterations = 1000000;
@@ -722,7 +713,6 @@ TEST(PerformanceTest, ClassCopyTest) {
     }
 
     timer.stop();
-    intLock.unLock();
 
     printf("%d iterations took %d us (%f each).\n", iterations, timer.getDiffUsec(),
            static_cast<F32>(timer.getDiffUsec()) / static_cast<F32>(iterations));
diff --git a/Os/Darwin/test/ut/DarwinCpuTests.cpp b/Os/Darwin/test/ut/DarwinCpuTests.cpp
new file mode 100644
index 0000000000..702f07b0b7
--- /dev/null
+++ b/Os/Darwin/test/ut/DarwinCpuTests.cpp
@@ -0,0 +1,10 @@
+// ======================================================================
+// \title Os/Darwin/test/ut/DarwinCpuTests.cpp
+// \brief tests using Darwin implementation for Os::Cpu interface testing
+// ======================================================================
+#include <gtest/gtest.h>
+
+int main(int argc, char **argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/Os/Darwin/test/ut/DarwinMemoryTests.cpp b/Os/Darwin/test/ut/DarwinMemoryTests.cpp
new file mode 100644
index 0000000000..be06473e4a
--- /dev/null
+++ b/Os/Darwin/test/ut/DarwinMemoryTests.cpp
@@ -0,0 +1,10 @@
+// ======================================================================
+// \title Os/Darwin/test/ut/DarwinMemoryTests.cpp
+// \brief tests using Darwin implementation for Os::Memory interface testing
+// ======================================================================
+#include <gtest/gtest.h>
+
+int main(int argc, char **argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/Os/Linux/test/ut/LinuxCpuTests.cpp b/Os/Linux/test/ut/LinuxCpuTests.cpp
new file mode 100644
index 0000000000..54af8012c0
--- /dev/null
+++ b/Os/Linux/test/ut/LinuxCpuTests.cpp
@@ -0,0 +1,10 @@
+// ======================================================================
+// \title Os/Linux/test/ut/LinuxCpuTests.cpp
+// \brief tests using Linux implementation for Os::Cpu interface testing
+// ======================================================================
+#include <gtest/gtest.h>
+
+int main(int argc, char **argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/Os/Linux/test/ut/LinuxMemoryTests.cpp b/Os/Linux/test/ut/LinuxMemoryTests.cpp
new file mode 100644
index 0000000000..8c5ef722ca
--- /dev/null
+++ b/Os/Linux/test/ut/LinuxMemoryTests.cpp
@@ -0,0 +1,10 @@
+// ======================================================================
+// \title Os/Linux/test/ut/LinuxMemoryTests.cpp
+// \brief tests using Linux implementation for Os::Memory interface testing
+// ======================================================================
+#include <gtest/gtest.h>
+
+int main(int argc, char **argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/Os/Stub/test/Cpu.cpp b/Os/Stub/test/Cpu.cpp
new file mode 100644
index 0000000000..54911dd953
--- /dev/null
+++ b/Os/Stub/test/Cpu.cpp
@@ -0,0 +1,45 @@
+// ======================================================================
+// \title Os/Stub/Cpu.cpp
+// \brief stub implementation for Os::Cpu
+// ======================================================================
+#include <Os/Stub/test/Cpu.hpp>
+
+namespace Os {
+namespace Stub {
+namespace Cpu {
+namespace Test {
+
+StaticData StaticData::data;
+
+TestCpu::TestCpu() {
+    StaticData::data.lastCalled = StaticData::LastFn::CONSTRUCT_FN;
+}
+
+TestCpu::~TestCpu() {
+    StaticData::data.lastCalled = StaticData::LastFn::DESTRUCT_FN;
+}
+
+
+TestCpu::Status TestCpu::_getCount(FwSizeType& cpu_count) {
+    StaticData::data.lastCalled = StaticData::LastFn::COUNT_FN;
+    StaticData::data.count = cpu_count;
+    return  StaticData::data.status_out;
+}
+
+TestCpu::Status TestCpu::_getTicks(Os::Cpu::Ticks& ticks, FwSizeType cpu_index) {
+    StaticData::data.lastCalled = StaticData::LastFn::TICKS_FN;
+    StaticData::data.index = cpu_index;
+    StaticData::data.ticks.total = ticks.total;
+    StaticData::data.ticks.used = ticks.used;
+    return  StaticData::data.status_out;
+}
+
+CpuHandle* TestCpu::getHandle() {
+    StaticData::data.lastCalled = StaticData::LastFn::HANDLE_FN;
+    return &this->m_handle;
+}
+
+} // namespace Test
+} // namespace Cpu
+} // namespace Stub
+} // namespace Os
diff --git a/Os/Stub/test/Cpu.hpp b/Os/Stub/test/Cpu.hpp
new file mode 100644
index 0000000000..881693b8f8
--- /dev/null
+++ b/Os/Stub/test/Cpu.hpp
@@ -0,0 +1,111 @@
+// ======================================================================
+// \title Os/Stub/test/Cpu.hpp
+// \brief test stub implementation for Os::Cpu, header and test definitions
+// ======================================================================
+#include <cstdio>
+#include <Os/Cpu.hpp>
+#ifndef OS_Stub_Test_Cpu_HPP
+#define OS_Stub_Test_Cpu_HPP
+
+namespace Os {
+namespace Stub {
+namespace Cpu {
+namespace Test {
+
+class TestCpu;
+
+//! Data that supports the stubbed File implementation.
+//!/
+struct StaticData {
+    enum LastFn {
+        NONE_FN,
+        CONSTRUCT_FN,
+        DESTRUCT_FN,
+        COUNT_FN,
+        TICKS_FN,
+        HANDLE_FN
+    };
+    //! Last function called
+    LastFn lastCalled = NONE_FN;
+
+    //! Count test
+    FwSizeType count = 0;
+    //! Count test
+    FwSizeType index = 0;
+
+    //! Ticks test
+    Os::Cpu::Ticks ticks;
+
+    //! Status out
+    CpuInterface::Status status_out;
+
+    // Singleton data
+    static StaticData data;
+};
+
+//! CpuHandle class definition for stub implementations.
+//!
+struct TestCpuHandle : public CpuHandle {
+};
+
+//! \brief stub implementation of Os::CpuInterface
+//!
+//! Stub implementation of `CpuInterface` for use as a delegate class handling stub console operations.
+//!
+class TestCpu : public CpuInterface {
+  public:
+    //! \brief constructor
+    //!
+    TestCpu();
+
+    //! \brief copy constructor
+    TestCpu(const TestCpu& other) = delete;
+
+    //! \brief assignment operator that copies the internal representation
+    CpuInterface& operator=(const CpuInterface& other) override = delete;
+
+    //! \brief destructor
+    //!
+    ~TestCpu() override;
+
+    //! \brief Request the count of the CPUs detected by the system
+    //!
+    //! This method wraps delegates to the underlying implementation.
+    //!
+    //! \param cpu_count: (output) filled with CPU count on system
+    //! \return: OP_OK with valid CPU count, ERROR when error occurs
+    //!
+    Status _getCount(FwSizeType& cpu_count) override;
+
+    //! \brief Get the CPU tick information for a given CPU
+    //!
+    //! CPU ticks represent a small time slice of processor time. This will retrieve the used CPU ticks and total
+    //! ticks for a given CPU. This information in a running accumulation and thus a sample-to-sample
+    //! differencing is needed to see the 'realtime' changing load. This shall be done by the caller. This method wraps
+    //! delegates to the underlying implementation.
+    //!
+    //! \param ticks: (output) filled with the tick information for the given CPU
+    //! \param cpu_index: index for CPU to read. Default: 0
+    //! \return:  ERROR when error occurs, OK otherwise.
+    //!
+    Status _getTicks(Os::Cpu::Ticks& ticks, FwSizeType cpu_index) override;
+
+    //! \brief returns the raw console handle
+    //!
+    //! Gets the raw console handle from the implementation. Note: users must include the implementation specific
+    //! header to make any real use of this handle. Otherwise it will be as an opaque type.
+    //!
+    //! \return raw console handle
+    //!
+    CpuHandle* getHandle() override;
+
+  private:
+    //! File handle for PosixFile
+    TestCpuHandle m_handle;
+};
+} // namespace Test
+} // namespace Cpu
+} // namespace Stub
+} // namespace Os
+
+#endif // OS_Stub_Test_Cpu_HPP
diff --git a/Os/Stub/test/DefaultCpu.cpp b/Os/Stub/test/DefaultCpu.cpp
new file mode 100644
index 0000000000..527879da02
--- /dev/null
+++ b/Os/Stub/test/DefaultCpu.cpp
@@ -0,0 +1,13 @@
+// ======================================================================
+// \title Os/Stub/DefaultCpu.cpp
+// \brief sets default Os::Cpu to stub implementation via linker
+// ======================================================================
+#include "Os/Cpu.hpp"
+#include "Os/Stub/test/Cpu.hpp"
+#include "Os/Delegate.hpp"
+
+namespace Os {
+CpuInterface* CpuInterface::getDelegate(CpuHandleStorage& aligned_new_memory) {
+    return Os::Delegate::makeDelegate<CpuInterface, Os::Stub::Cpu::Test::TestCpu>(aligned_new_memory);
+}
+}
diff --git a/Os/Stub/test/DefaultMemory.cpp b/Os/Stub/test/DefaultMemory.cpp
new file mode 100644
index 0000000000..8dde73025e
--- /dev/null
+++ b/Os/Stub/test/DefaultMemory.cpp
@@ -0,0 +1,13 @@
+// ======================================================================
+// \title Os/Stub/DefaultMemory.cpp
+// \brief sets default Os::Memory to stub implementation via linker
+// ======================================================================
+#include "Os/Memory.hpp"
+#include "Os/Stub/test/Memory.hpp"
+#include "Os/Delegate.hpp"
+
+namespace Os {
+MemoryInterface* MemoryInterface::getDelegate(MemoryHandleStorage& aligned_new_memory) {
+    return Os::Delegate::makeDelegate<MemoryInterface, Os::Stub::Memory::Test::TestMemory>(aligned_new_memory);
+}
+}
diff --git a/Os/Stub/test/Memory.cpp b/Os/Stub/test/Memory.cpp
new file mode 100644
index 0000000000..9ea02c5d6d
--- /dev/null
+++ b/Os/Stub/test/Memory.cpp
@@ -0,0 +1,38 @@
+// ======================================================================
+// \title Os/Stub/Memory.cpp
+// \brief stub implementation for Os::Memory
+// ======================================================================
+#include <Os/Stub/test/Memory.hpp>
+
+namespace Os {
+namespace Stub {
+namespace Memory {
+namespace Test {
+
+StaticData StaticData::data;
+
+TestMemory::TestMemory() {
+    StaticData::data.lastCalled = StaticData::LastFn::CONSTRUCT_FN;
+}
+
+TestMemory::~TestMemory() {
+    StaticData::data.lastCalled = StaticData::LastFn::DESTRUCT_FN;
+}
+
+TestMemory::Status TestMemory::_getUsage(Os::Memory::Usage& memory_usage) {
+    StaticData::data.lastCalled = StaticData::LastFn::USAGE_FN;
+    StaticData::data.usage.total = memory_usage.total;
+    StaticData::data.usage.used = memory_usage.used;
+    return Status::ERROR;
+}
+
+
+MemoryHandle* TestMemory::getHandle() {
+    StaticData::data.lastCalled = StaticData::LastFn::HANDLE_FN;
+    return &this->m_handle;
+}
+
+} // namespace Test
+} // namespace Memory
+} // namespace Stub
+} // namespace Os
diff --git a/Os/Stub/test/Memory.hpp b/Os/Stub/test/Memory.hpp
new file mode 100644
index 0000000000..209153a1f1
--- /dev/null
+++ b/Os/Stub/test/Memory.hpp
@@ -0,0 +1,96 @@
+// ======================================================================
+// \title Os/Stub/test/Memory.hpp
+// \brief test stub implementation for Os::Memory, header and test definitions
+// ======================================================================
+#include <cstdio>
+#include <Os/Memory.hpp>
+#ifndef OS_Stub_Test_Memory_HPP
+#define OS_Stub_Test_Memory_HPP
+
+namespace Os {
+namespace Stub {
+namespace Memory {
+namespace Test {
+
+class TestMemory;
+
+//! Data that supports the stubbed File implementation.
+//!/
+struct StaticData {
+    enum LastFn {
+        NONE_FN,
+        CONSTRUCT_FN,
+        DESTRUCT_FN,
+        USAGE_FN,
+        HANDLE_FN
+    };
+    //! Last function called
+    LastFn lastCalled = NONE_FN;
+
+    //! Count test
+    FwSizeType count = 0;
+    //! Count test
+    FwSizeType index = 0;
+
+    //! Ticks test
+    Os::Memory::Usage usage;
+
+    //! Status out
+    MemoryInterface::Status status_out;
+
+    // Singleton data
+    static StaticData data;
+};
+
+//! MemoryHandle class definition for stub implementations.
+//!
+struct TestMemoryHandle : public MemoryHandle {
+};
+
+//! \brief stub implementation of Os::MemoryInterface
+//!
+//! Stub implementation of `MemoryInterface` for use as a delegate class handling stub console operations.
+//!
+class TestMemory : public MemoryInterface {
+  public:
+    //! \brief constructor
+    //!
+    TestMemory();
+
+    //! \brief copy constructor
+    TestMemory(const TestMemory& other) = delete;
+
+    //! \brief assignment operator that copies the internal representation
+    MemoryInterface& operator=(const MemoryInterface& other) override = delete;
+
+    //! \brief destructor
+    //!
+    ~TestMemory() override;
+
+    //! \brief get system memory usage
+    //!
+    //! This method delegates to the underlying implementation.
+    //!
+    //! \param memory_usage: (output) data structure used to store memory usage
+    //! \return:  ERROR when error occurs, OK otherwise.
+    Status _getUsage(Os::Memory::Usage& memory_usage) override;
+
+    //! \brief returns the raw console handle
+    //!
+    //! Gets the raw console handle from the implementation. Note: users must include the implementation specific
+    //! header to make any real use of this handle. Otherwise it will be as an opaque type.
+    //!
+    //! \return raw console handle
+    //!
+    MemoryHandle* getHandle() override;
+
+  private:
+    //! File handle for PosixFile
+    TestMemoryHandle m_handle;
+};
+} // namespace Test
+} // namespace Memory
+} // namespace Stub
+} // namespace Os
+
+#endif // OS_Stub_Test_Memory_HPP
diff --git a/Os/Stub/test/ut/StubCpuTests.cpp b/Os/Stub/test/ut/StubCpuTests.cpp
new file mode 100644
index 0000000000..006d5cbe96
--- /dev/null
+++ b/Os/Stub/test/ut/StubCpuTests.cpp
@@ -0,0 +1,55 @@
+// ======================================================================
+// \title Os/Stub/test/ut/StubCpuTests.cpp
+// \brief tests using stub implementation for Os::Cpu interface testing
+// ======================================================================
+#include <gtest/gtest.h>
+#include "Os/Cpu.hpp"
+#include "Os/Stub/test/Cpu.hpp"
+#include "STest/Pick/Pick.hpp"
+
+TEST(Interface, Construction) {
+    Os::Cpu cpu;
+    ASSERT_EQ(Os::Stub::Cpu::Test::StaticData::data.lastCalled, Os::Stub::Cpu::Test::StaticData::CONSTRUCT_FN);
+}
+
+TEST(Interface, Destruction) {
+    delete (new Os::Cpu);
+    ASSERT_EQ(Os::Stub::Cpu::Test::StaticData::data.lastCalled, Os::Stub::Cpu::Test::StaticData::DESTRUCT_FN);
+}
+
+TEST(Interface, Count) {
+    Os::Cpu cpu;
+    FwSizeType count = STest::Pick::lowerUpper(0, 10000);
+    FwSizeType count_copy = count;
+    Os::CpuInterface::Status status = Os::CpuInterface::Status::ERROR;
+    Os::Stub::Cpu::Test::StaticData::data.status_out = status;
+    ASSERT_EQ(Os::Stub::Cpu::Test::StaticData::data.lastCalled, Os::Stub::Cpu::Test::StaticData::CONSTRUCT_FN);
+    ASSERT_EQ(cpu.getCount(count), status);
+    ASSERT_EQ(Os::Stub::Cpu::Test::StaticData::data.lastCalled, Os::Stub::Cpu::Test::StaticData::COUNT_FN);
+    ASSERT_EQ(Os::Stub::Cpu::Test::StaticData::data.count, count_copy);
+    ASSERT_EQ(count, count_copy);
+}
+
+TEST(Interface, Ticks) {
+    Os::Cpu cpu;
+    FwSizeType index = STest::Pick::lowerUpper(0, 10000);
+    Os::Cpu::Ticks ticks;
+    ticks.used = STest::Pick::lowerUpper(0, 10000);
+    ticks.total = STest::Pick::lowerUpper(0, 10000);
+    Os::Cpu::Ticks ticks_copy = ticks;
+    Os::CpuInterface::Status status = Os::CpuInterface::Status::ERROR;
+    Os::Stub::Cpu::Test::StaticData::data.status_out = status;
+    ASSERT_EQ(Os::Stub::Cpu::Test::StaticData::data.lastCalled, Os::Stub::Cpu::Test::StaticData::CONSTRUCT_FN);
+    ASSERT_EQ(cpu.getTicks(ticks, index), status);
+    ASSERT_EQ(Os::Stub::Cpu::Test::StaticData::data.lastCalled, Os::Stub::Cpu::Test::StaticData::TICKS_FN);
+    ASSERT_EQ(Os::Stub::Cpu::Test::StaticData::data.index, index);
+    ASSERT_EQ(Os::Stub::Cpu::Test::StaticData::data.ticks.total, ticks.total);
+    ASSERT_EQ(Os::Stub::Cpu::Test::StaticData::data.ticks.used, ticks.used);
+    ASSERT_EQ(ticks_copy.total, ticks.total);
+    ASSERT_EQ(ticks_copy.used, ticks.used);
+}
+
+int main(int argc, char **argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/Os/Stub/test/ut/StubFileTests.cpp b/Os/Stub/test/ut/StubFileTests.cpp
index caea882ee3..5836f3a74e 100644
--- a/Os/Stub/test/ut/StubFileTests.cpp
+++ b/Os/Stub/test/ut/StubFileTests.cpp
@@ -4,10 +4,9 @@
 // ======================================================================
 #include <gtest/gtest.h>
 #include "Os/File.hpp"
-#include "Os/Models/Models.hpp"
+#include "Os/Stub/test/File.hpp"
 #include "Os/test/ut/file/CommonTests.hpp"
 #include "Os/test/ut/file/RulesHeaders.hpp"
-#include "Os/Stub/test/File.hpp"
 
 namespace Os {
 namespace Test {
@@ -191,24 +190,6 @@ TEST_F(Interface, Write) {
     ASSERT_EQ(Os::Stub::File::Test::StaticData::data.writeWait, Os::File::WaitType::WAIT);
 }
 
-// Ensure that FPP shadow enumeration matches
-TEST(FppTypes, FileStatusEnum) {
-    for (FwIndexType i = static_cast<FwIndexType>(Os::File::Status::OP_OK); i < static_cast<FwIndexType>(Os::File::Status::MAX_STATUS); i++){
-        Os::File::Status status = static_cast<Os::File::Status>(i);
-        Os::FileStatus fpp_status = static_cast<Os::FileStatus::T>(status);
-        ASSERT_TRUE(fpp_status.isValid());
-    }
-}
-
-// Ensure that FPP shadow enumeration matches
-TEST(FppTypes, FileModeEnum) {
-    for (FwIndexType i = static_cast<FwIndexType>(Os::File::Mode::OPEN_CREATE); i < static_cast<FwIndexType>(Os::File::Mode::MAX_OPEN_MODE); i++){
-        Os::File::Mode mode = static_cast<Os::File::Mode>(i);
-        Os::FileMode fpp_mode = static_cast<Os::FileMode::T>(mode);
-        ASSERT_TRUE(fpp_mode.isValid());
-    }
-}
-
 int main(int argc, char **argv) {
     ::testing::InitGoogleTest(&argc, argv);
     STest::Random::seed();
diff --git a/Os/Stub/test/ut/StubMemoryTests.cpp b/Os/Stub/test/ut/StubMemoryTests.cpp
new file mode 100644
index 0000000000..f208780706
--- /dev/null
+++ b/Os/Stub/test/ut/StubMemoryTests.cpp
@@ -0,0 +1,40 @@
+// ======================================================================
+// \title Os/Stub/test/ut/StubMemoryTests.cpp
+// \brief tests using stub implementation for Os::Memory interface testing
+// ======================================================================
+#include <gtest/gtest.h>
+#include "Os/Memory.hpp"
+#include "Os/Stub/test/Memory.hpp"
+#include "STest/Pick/Pick.hpp"
+
+TEST(Interface, Construction) {
+    Os::Memory memory;
+    ASSERT_EQ(Os::Stub::Memory::Test::StaticData::data.lastCalled, Os::Stub::Memory::Test::StaticData::CONSTRUCT_FN);
+}
+
+TEST(Interface, Destruction) {
+    delete (new Os::Memory);
+    ASSERT_EQ(Os::Stub::Memory::Test::StaticData::data.lastCalled, Os::Stub::Memory::Test::StaticData::DESTRUCT_FN);
+}
+
+TEST(Interface, Usage) {
+    Os::Memory memory;
+    Os::Memory::Usage usage;
+    usage.used = STest::Pick::lowerUpper(0, 10000);
+    usage.total = STest::Pick::lowerUpper(0, 10000);
+    Os::Memory::Usage usage_copy = usage;
+    Os::MemoryInterface::Status status = Os::MemoryInterface::Status::ERROR;
+    Os::Stub::Memory::Test::StaticData::data.status_out = status;
+    ASSERT_EQ(Os::Stub::Memory::Test::StaticData::data.lastCalled, Os::Stub::Memory::Test::StaticData::CONSTRUCT_FN);
+    ASSERT_EQ(Os::Memory::getUsage(usage), status);
+    ASSERT_EQ(Os::Stub::Memory::Test::StaticData::data.lastCalled, Os::Stub::Memory::Test::StaticData::USAGE_FN);
+    ASSERT_EQ(Os::Stub::Memory::Test::StaticData::data.usage.total, usage.total);
+    ASSERT_EQ(Os::Stub::Memory::Test::StaticData::data.usage.used, usage.used);
+    ASSERT_EQ(usage_copy.total, usage.total);
+    ASSERT_EQ(usage_copy.used, usage.used);
+}
+
+int main(int argc, char **argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/Os/Stub/test/ut/StubTaskTests.cpp b/Os/Stub/test/ut/StubTaskTests.cpp
index 39ef52bd20..a969b27e8d 100644
--- a/Os/Stub/test/ut/StubTaskTests.cpp
+++ b/Os/Stub/test/ut/StubTaskTests.cpp
@@ -3,11 +3,10 @@
 // \brief tests using stub implementation for Os::Task interface testing
 // ======================================================================
 #include <gtest/gtest.h>
-#include "Os/Models/Models.hpp"
+#include "Fw/Types/String.hpp"
+#include "Os/Stub/test/Task.hpp"
 #include "Os/test/ut/task/CommonTests.hpp"
 #include "Os/test/ut/task/RulesHeaders.hpp"
-#include "Os/Stub/test/Task.hpp"
-#include "Os/Models/Models.hpp"
 
 using namespace Os::Stub::Task::Test;
 
diff --git a/Os/Stub/test/ut/StubTests.cpp b/Os/Stub/test/ut/StubTests.cpp
index ec8b2b0a3b..f8978221b9 100644
--- a/Os/Stub/test/ut/StubTests.cpp
+++ b/Os/Stub/test/ut/StubTests.cpp
@@ -7,6 +7,8 @@
 #include <Os/Console.hpp>
 #include <Os/FileSystem.hpp>
 #include <Os/Directory.hpp>
+#include <Os/Cpu.hpp>
+#include <Os/Memory.hpp>
 
 
 TEST(Stub, File) {
@@ -41,6 +43,14 @@ TEST(Stub, Directory) {
     Os::Directory _;
 }
 
+TEST(Stub, Cpu) {
+    Os::Cpu::getSingleton();
+}
+
+TEST(Stub, Memory) {
+    Os::Memory::getSingleton();
+}
+
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
     return RUN_ALL_TESTS();
diff --git a/Os/test/ut/OsSystemResourcesTest.cpp b/Os/test/ut/OsSystemResourcesTest.cpp
deleted file mode 100644
index 36cb78f2f5..0000000000
--- a/Os/test/ut/OsSystemResourcesTest.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-#include <gtest/gtest.h>
-#include <Os/SystemResources.hpp>
-#include <Fw/Types/Assert.hpp>
-#include <Fw/Types/String.hpp>
-
-void testTestSystemResources() {
-
-    Os::SystemResources::SystemResourcesStatus sys_res_status;
-    Os::SystemResources::CpuTicks cpuUtil;
-
-    U32 cpuCount;
-    U32 cpuIndex;
-
-    sys_res_status = Os::SystemResources::getCpuCount(cpuCount);
-    ASSERT_EQ(sys_res_status, Os::SystemResources::SystemResourcesStatus::SYSTEM_RESOURCES_OK);
-
-    cpuIndex = 0;
-    sys_res_status = Os::SystemResources::getCpuTicks(cpuUtil, cpuIndex);
-    ASSERT_EQ(sys_res_status, Os::SystemResources::SystemResourcesStatus::SYSTEM_RESOURCES_OK);
-
-    cpuIndex = 1000;
-    sys_res_status = Os::SystemResources::getCpuTicks(cpuUtil, cpuIndex);
-    ASSERT_EQ(sys_res_status, Os::SystemResources::SystemResourcesStatus::SYSTEM_RESOURCES_ERROR);
-}
-
-extern "C" {
-    void systemResourcesTest(void);
-}
-
-void systemResourcesTest(void) {
-    testTestSystemResources(); 
-}
diff --git a/Os/test/ut/OsTestMain.cpp b/Os/test/ut/OsTestMain.cpp
index 8a0d07687a..7a8bef8b29 100644
--- a/Os/test/ut/OsTestMain.cpp
+++ b/Os/test/ut/OsTestMain.cpp
@@ -1,40 +1,11 @@
 #include "gtest/gtest.h"
-#include <cstdlib>
-#include <unistd.h>
-#include <cstdio>
 
 extern "C" {
-/*  void qtest_block_receive();
-  void qtest_nonblock_receive();
-  void qtest_nonblock_send();
-  void qtest_block_send();
-  void qtest_performance();
-  void qtest_concurrent();*/
   void intervalTimerTest();
   void validateFileTest(const char* filename);
-  void systemResourcesTest();
   void mutexBasicLockableTest();
 }
 const char* filename;
-/*TEST(Nominal, QTestBlockRecv) {
-   qtest_block_receive();
-}
-TEST(Nominal, QTestNonBlockRecv) {
-   qtest_nonblock_receive();
-}
-TEST(Nominal, QTestNonBlockSend) {
-   qtest_nonblock_send();
-}
-TEST(Nominal, QTestBlockSend) {
-   qtest_block_send();
-}
-TEST(Nominal, QTestPerformance) {
-   qtest_performance();
-}
-TEST(Nominal, QTestConcurrentTest) {
-   qtest_concurrent();
-}
-*/
 // The interval timer unit test is timed off a 1 sec thread delay. Mac OS allows a large amount of
 // scheduling jitter to conserve energy, which rarely causes this sleep to be slightly shorter
 // (~0.99 s) or longer (~10 sec) than requested, causing the test to fail. The interval timer should
@@ -46,9 +17,7 @@ TEST(Nominal, DISABLED_IntervalTimerTest) {
 TEST(Nominal, ValidateFileTest) {
    validateFileTest(filename);
 }
-TEST(Nominal, SystemResourcesTest) { 
-   systemResourcesTest();
-}
+
 TEST(Nominal, MutexBasicLockableTest) {
   mutexBasicLockableTest();
 }
diff --git a/Os/test/ut/cpu/CommonCpuTests.cpp b/Os/test/ut/cpu/CommonCpuTests.cpp
new file mode 100644
index 0000000000..ec28e01e51
--- /dev/null
+++ b/Os/test/ut/cpu/CommonCpuTests.cpp
@@ -0,0 +1,27 @@
+// ======================================================================
+// \title Os/Stub/test/ut/StubCpuTests.cpp
+// \brief tests using stub implementation for Os::Cpu interface testing
+// ======================================================================
+#include <gtest/gtest.h>
+#include "Os/Cpu.hpp"
+#include "Os/Darwin/Cpu.hpp"
+
+TEST(Basic, Count) {
+    FwSizeType count = 0;
+    ASSERT_EQ(Os::Cpu::getCount(count), Os::Cpu::Status::OP_OK);
+    ASSERT_GT(count, 0);
+}
+
+TEST(Basic, Ticks) {
+    // Get the count
+    FwSizeType count = 0;
+    Os::Cpu::getCount(count);
+    ASSERT_GT(count, 0);
+
+    Os::Cpu::Ticks ticks_output;
+    for (FwSizeType i = 0; i < count; i++) {
+        ASSERT_EQ(Os::Cpu::getTicks(ticks_output, i), Os::Cpu::Status::OP_OK);
+        ASSERT_GT(ticks_output.used, 0);
+        ASSERT_GE(ticks_output.total, 0) << "No total on CPU: " << i;
+    }
+}
diff --git a/Os/test/ut/memory/CommonMemoryTests.cpp b/Os/test/ut/memory/CommonMemoryTests.cpp
new file mode 100644
index 0000000000..c57e91b275
--- /dev/null
+++ b/Os/test/ut/memory/CommonMemoryTests.cpp
@@ -0,0 +1,15 @@
+// ======================================================================
+// \title Os/Stub/test/ut/StubMemoryTests.cpp
+// \brief tests using stub implementation for Os::Memory interface testing
+// ======================================================================
+#include <gtest/gtest.h>
+#include "Os/Memory.hpp"
+#include "Os/Darwin/Memory.hpp"
+
+TEST(Basic, Usage) {
+    Os::Memory::Usage usage_output;
+    Os::Memory::getUsage(usage_output);
+
+    ASSERT_GT(usage_output.used, 0);
+    ASSERT_GT(usage_output.total, 0);
+}
diff --git a/Svc/SystemResources/test/ut/SystemResourcesTester.cpp b/Svc/SystemResources/test/ut/SystemResourcesTester.cpp
index fe9b1adb12..b71321daf1 100644
--- a/Svc/SystemResources/test/ut/SystemResourcesTester.cpp
+++ b/Svc/SystemResources/test/ut/SystemResourcesTester.cpp
@@ -32,8 +32,8 @@ SystemResourcesTester ::~SystemResourcesTester() {}
 // ----------------------------------------------------------------------
 
 void SystemResourcesTester ::test_tlm(bool enabled) {
-    U32 count = 0;
-    if (Os::SystemResources::getCpuCount(count) == Os::SystemResources::SYSTEM_RESOURCES_OK) {
+    FwSizeType count = 0;
+    if (Os::Cpu::getCount(count) == Os::Generic::OP_OK) {
         this->invoke_to_run(0, 0);
         count = (count <= 16) ? count : 16;
         // All cascades expected
@@ -89,11 +89,11 @@ void SystemResourcesTester ::test_tlm(bool enabled) {
             default:
                 FwSizeType free = 0;
                 FwSizeType total = 0;
-                Os::SystemResources::MemUtil memory_info;
+                Os::Memory::Usage memory_info;
                 ASSERT_TLM_CPU_SIZE((enabled) ? 1 : 0);
 
                 // Check that the filesystem reads well before asserting telemetry
-                if (enabled && Os::SystemResources::getMemUtil(memory_info) == Os::SystemResources::SYSTEM_RESOURCES_OK) {
+                if (enabled && Os::Memory::getUsage(memory_info) == Os::Generic::OP_OK) {
                     ASSERT_TLM_MEMORY_USED_SIZE(1);
                     ASSERT_TLM_MEMORY_TOTAL_SIZE(1);
                     count += 2;
diff --git a/Utils/test/ut/LockGuardTester.cpp b/Utils/test/ut/LockGuardTester.cpp
index b7d6eaf627..33b1b1a3a0 100644
--- a/Utils/test/ut/LockGuardTester.cpp
+++ b/Utils/test/ut/LockGuardTester.cpp
@@ -61,15 +61,14 @@ namespace Utils {
       Os::Task::Arguments arguments(name, taskMethod, &data);
       stat = testTask.start(arguments);
       ASSERT_EQ(stat, Os::Task::OP_OK);
-      Os::Task::delay(Fw::Time(0, 100));
+      Os::Task::delay(Fw::Time(0, 1000));
       ASSERT_EQ(data.i, 0);
     }
-    Os::Task::delay(Fw::Time(0, 100));
+    Os::Task::delay(Fw::Time(0, 1000));
     {
       LockGuard guard(data.mutex);
       ASSERT_EQ(data.i, 1);
     }
-    stat = testTask.join();
     ASSERT_EQ(stat, Os::Task::OP_OK);
   }