diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index fc6cb67c7f..ce68194c54 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -124,6 +124,10 @@ add_library(core STATIC
     hle/service/nifm/nifm_s.h
     hle/service/nifm/nifm_u.cpp
     hle/service/nifm/nifm_u.h
+    hle/service/ns/ns.cpp
+    hle/service/ns/ns.h
+    hle/service/ns/pl_u.cpp
+    hle/service/ns/pl_u.h
     hle/service/nvdrv/devices/nvdevice.h
     hle/service/nvdrv/devices/nvdisp_disp0.cpp
     hle/service/nvdrv/devices/nvdisp_disp0.h
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
new file mode 100644
index 0000000000..45681c50fb
--- /dev/null
+++ b/src/core/hle/service/ns/ns.cpp
@@ -0,0 +1,16 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/ns/ns.h"
+#include "core/hle/service/ns/pl_u.h"
+
+namespace Service {
+namespace NS {
+
+void InstallInterfaces(SM::ServiceManager& service_manager) {
+    std::make_shared<PL_U>()->InstallAsService(service_manager);
+}
+
+} // namespace NS
+} // namespace Service
diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h
new file mode 100644
index 0000000000..a4b7e3dedf
--- /dev/null
+++ b/src/core/hle/service/ns/ns.h
@@ -0,0 +1,16 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace NS {
+
+/// Registers all NS services with the specified service manager.
+void InstallInterfaces(SM::ServiceManager& service_manager);
+
+} // namespace NS
+} // namespace Service
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp
new file mode 100644
index 0000000000..cc9d03a7c0
--- /dev/null
+++ b/src/core/hle/service/ns/pl_u.cpp
@@ -0,0 +1,111 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/common_paths.h"
+#include "common/file_util.h"
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/service/ns/pl_u.h"
+
+namespace Service {
+namespace NS {
+
+struct FontRegion {
+    u32 offset;
+    u32 size;
+};
+
+// The below data is specific to shared font data dumped from Switch on f/w 2.2
+// Virtual address and offsets/sizes likely will vary by dump
+static constexpr VAddr SHARED_FONT_MEM_VADDR{0x00000009d3016000ULL};
+static constexpr u64 SHARED_FONT_MEM_SIZE{0x1100000};
+static constexpr std::array<FontRegion, 6> SHARED_FONT_REGIONS{
+    FontRegion{0x00000008, 0x001fe764}, FontRegion{0x001fe774, 0x00773e58},
+    FontRegion{0x009725d4, 0x0001aca8}, FontRegion{0x0098d284, 0x00369cec},
+    FontRegion{0x00cf6f78, 0x0039b858}, FontRegion{0x010927d8, 0x00019e80},
+};
+
+enum class LoadState : u32 {
+    Loading = 0,
+    Done = 1,
+};
+
+PL_U::PL_U() : ServiceFramework("pl:u") {
+    static const FunctionInfo functions[] = {
+        {1, &PL_U::GetLoadState, "GetLoadState"},
+        {2, &PL_U::GetSize, "GetSize"},
+        {3, &PL_U::GetSharedMemoryAddressOffset, "GetSharedMemoryAddressOffset"},
+        {4, &PL_U::GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"}};
+    RegisterHandlers(functions);
+
+    // Attempt to load shared font data from disk
+    const std::string filepath{FileUtil::GetUserPath(D_SYSDATA_IDX) + SHARED_FONT};
+    FileUtil::CreateFullPath(filepath); // Create path if not already created
+    FileUtil::IOFile file(filepath, "rb");
+
+    if (file.IsOpen()) {
+        // Read shared font data
+        ASSERT(file.GetSize() == SHARED_FONT_MEM_SIZE);
+        shared_font = std::make_shared<std::vector<u8>>(static_cast<size_t>(file.GetSize()));
+        file.ReadBytes(shared_font->data(), shared_font->size());
+    } else {
+        LOG_WARNING(Service_NS, "Unable to load shared font: %s", filepath.c_str());
+    }
+}
+
+void PL_U::GetLoadState(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const u32 font_id{rp.Pop<u32>()};
+
+    LOG_DEBUG(Service_NS, "called, font_id=%d", font_id);
+    IPC::ResponseBuilder rb{ctx, 3};
+    rb.Push(RESULT_SUCCESS);
+    rb.Push<u32>(static_cast<u32>(LoadState::Done));
+}
+
+void PL_U::GetSize(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const u32 font_id{rp.Pop<u32>()};
+
+    LOG_DEBUG(Service_NS, "called, font_id=%d", font_id);
+    IPC::ResponseBuilder rb{ctx, 3};
+    rb.Push(RESULT_SUCCESS);
+    rb.Push<u32>(SHARED_FONT_REGIONS[font_id].size);
+}
+
+void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const u32 font_id{rp.Pop<u32>()};
+
+    LOG_DEBUG(Service_NS, "called, font_id=%d", font_id);
+    IPC::ResponseBuilder rb{ctx, 3};
+    rb.Push(RESULT_SUCCESS);
+    rb.Push<u32>(SHARED_FONT_REGIONS[font_id].offset);
+}
+
+void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
+    if (shared_font != nullptr) {
+        // TODO(bunnei): This is a less-than-ideal solution to load a RAM dump of the Switch shared
+        // font data. This (likely) relies on exact address, size, and offsets from the original
+        // dump. In the future, we need to replace this with a more robust solution.
+
+        // Map backing memory for the font data
+        Kernel::g_current_process->vm_manager.MapMemoryBlock(SHARED_FONT_MEM_VADDR, shared_font, 0,
+                                                             SHARED_FONT_MEM_SIZE,
+                                                             Kernel::MemoryState::Shared);
+
+        // Create shared font memory object
+        shared_font_mem = Kernel::SharedMemory::Create(
+            Kernel::g_current_process, SHARED_FONT_MEM_SIZE, Kernel::MemoryPermission::ReadWrite,
+            Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE,
+            "PL_U:shared_font_mem");
+    }
+
+    LOG_DEBUG(Service_NS, "called");
+    IPC::ResponseBuilder rb{ctx, 2, 1};
+    rb.Push(RESULT_SUCCESS);
+    rb.PushCopyObjects(shared_font_mem);
+}
+
+} // namespace NS
+} // namespace Service
diff --git a/src/core/hle/service/ns/pl_u.h b/src/core/hle/service/ns/pl_u.h
new file mode 100644
index 0000000000..7a4766338a
--- /dev/null
+++ b/src/core/hle/service/ns/pl_u.h
@@ -0,0 +1,33 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include "core/hle/kernel/shared_memory.h"
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace NS {
+
+class PL_U final : public ServiceFramework<PL_U> {
+public:
+    PL_U();
+    ~PL_U() = default;
+
+private:
+    void GetLoadState(Kernel::HLERequestContext& ctx);
+    void GetSize(Kernel::HLERequestContext& ctx);
+    void GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx);
+    void GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx);
+
+    /// Handle to shared memory region designated for a shared font
+    Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem;
+
+    /// Backing memory for the shared font data
+    std::shared_ptr<std::vector<u8>> shared_font;
+};
+
+} // namespace NS
+} // namespace Service
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 1dd04a12f4..5e6d837290 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -23,6 +23,7 @@
 #include "core/hle/service/hid/hid.h"
 #include "core/hle/service/lm/lm.h"
 #include "core/hle/service/nifm/nifm.h"
+#include "core/hle/service/ns/ns.h"
 #include "core/hle/service/nvdrv/nvdrv.h"
 #include "core/hle/service/pctl/pctl.h"
 #include "core/hle/service/service.h"
@@ -182,6 +183,7 @@ void Init() {
     HID::InstallInterfaces(*SM::g_service_manager);
     LM::InstallInterfaces(*SM::g_service_manager);
     NIFM::InstallInterfaces(*SM::g_service_manager);
+    NS::InstallInterfaces(*SM::g_service_manager);
     Nvidia::InstallInterfaces(*SM::g_service_manager);
     PCTL::InstallInterfaces(*SM::g_service_manager);
     Sockets::InstallInterfaces(*SM::g_service_manager);