diff --git a/Ryujinx.HLE/Font/SharedFontManager.cs b/Ryujinx.HLE/Font/SharedFontManager.cs
new file mode 100644
index 000000000..fce270de8
--- /dev/null
+++ b/Ryujinx.HLE/Font/SharedFontManager.cs
@@ -0,0 +1,177 @@
+using ChocolArm64.Exceptions;
+using ChocolArm64.Memory;
+using Ryujinx.HLE.Logging;
+using Ryujinx.HLE.OsHle;
+using Ryujinx.HLE.OsHle.Handles;
+using Ryujinx.HLE.Resource;
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+
+namespace Ryujinx.HLE.Font
+{
+    public class SharedFontManager
+    {
+        private const uint SharedMemorySize = 0x1100000;
+        private Logger Log;
+
+        private string FontsPath;
+
+        private object ShMemLock;
+
+        private (AMemory, long, long)[] ShMemPositions;
+
+        private Dictionary<SharedFontType, byte[]> FontData;
+
+        private uint[] LoadedFonts;
+
+        public SharedFontManager(Logger Log, string SystemPath)
+        {
+            this.Log          = Log;
+            this.FontsPath    = Path.Combine(SystemPath, "fonts");
+
+            ShMemLock         = new object();
+
+            ShMemPositions    = new(AMemory, long, long)[0];
+
+            FontData          = new Dictionary<SharedFontType, byte[]>()
+            {
+                { SharedFontType.JapanUsEurope,       GetData("FontStandard")                  },
+                { SharedFontType.SimplifiedChinese,   GetData("FontChineseSimplified")         },
+                { SharedFontType.SimplifiedChineseEx, GetData("FontExtendedChineseSimplified") },
+                { SharedFontType.TraditionalChinese,  GetData("FontChineseTraditional")        },
+                { SharedFontType.Korean,              GetData("FontKorean")                    },
+                { SharedFontType.NintendoEx,          GetData("FontNintendoExtended")          }
+            };
+
+            int FontMemoryUsage = 0;
+            foreach (byte[] data in FontData.Values)
+            {
+                FontMemoryUsage += data.Length;
+                FontMemoryUsage += 0x8;
+            }
+
+            if (FontMemoryUsage > SharedMemorySize)
+            {
+                throw new InvalidSystemResourceException($"The sum of all fonts size exceed the shared memory size. Please make sure that the fonts don't exceed {SharedMemorySize} bytes in total. (actual size: {FontMemoryUsage} bytes)");
+            }
+
+            LoadedFonts       = new uint[FontData.Count];
+        }
+
+        public byte[] GetData(string FontName)
+        {
+            string FontFilePath = Path.Combine(FontsPath, $"{FontName}.ttf");
+            if (File.Exists(FontFilePath))
+            {
+                return File.ReadAllBytes(FontFilePath);
+            }
+            else
+            {
+                throw new InvalidSystemResourceException($"Font \"{FontName}.ttf\" not found. Please provide it in \"{FontsPath}\".");
+            }
+        }
+
+        public void MapFont(SharedFontType FontType, AMemory Memory, long Position)
+        {
+            uint SharedMemoryAddressOffset = GetSharedMemoryAddressOffset(FontType);
+            // TODO: find what are the 8 bytes before the font
+            Memory.WriteUInt64(Position + SharedMemoryAddressOffset - 8, 0);
+            Memory.WriteBytes(Position + SharedMemoryAddressOffset, FontData[FontType]);
+        }
+
+        public void PropagateNewMapFont(SharedFontType Type)
+        {
+            lock (ShMemLock)
+            {
+                foreach ((AMemory Memory, long Position, long Size) in ShMemPositions)
+                {
+                    AMemoryMapInfo MemoryInfo = Memory.Manager.GetMapInfo(Position);
+
+                    if (MemoryInfo == null)
+                    {
+                        throw new VmmPageFaultException(Position);
+                    }
+
+                    // The memory is read only, we need to changes that to add the new font
+                    AMemoryPerm originalPerms = MemoryInfo.Perm;
+                    Memory.Manager.Reprotect(Position, Size, AMemoryPerm.RW);
+                    MapFont(Type, Memory, Position);
+                    Memory.Manager.Reprotect(Position, Size, originalPerms);
+                }
+            }
+        }
+
+        internal void ShMemMap(object sender, EventArgs e)
+        {
+            HSharedMem SharedMem = (HSharedMem)sender;
+
+            lock (ShMemLock)
+            {
+                ShMemPositions = SharedMem.GetVirtualPositions();
+
+                (AMemory Memory, long Position, long Size) = ShMemPositions[ShMemPositions.Length - 1];
+
+                for (int Type = 0; Type < LoadedFonts.Length; Type++)
+                {
+                    if (LoadedFonts[(int)Type] == 1)
+                    {
+                        MapFont((SharedFontType)Type, Memory, Position);
+                    }
+                }
+            }
+        }
+
+        internal void ShMemUnmap(object sender, EventArgs e)
+        {
+            HSharedMem SharedMem = (HSharedMem)sender;
+
+            lock (ShMemLock)
+            {
+                ShMemPositions = SharedMem.GetVirtualPositions();
+            }
+        }
+
+        public void Load(SharedFontType FontType)
+        {
+            if (LoadedFonts[(int)FontType] == 0)
+            {
+                PropagateNewMapFont(FontType);
+            }
+
+            LoadedFonts[(int)FontType] = 1;
+        }
+
+        public uint GetLoadState(SharedFontType FontType)
+        {
+            if (LoadedFonts[(int)FontType] != 1)
+            {
+                // Some games don't request a load, so we need to load it here.
+                Load(FontType);
+                return 0;
+            }
+            return LoadedFonts[(int)FontType];
+        }
+
+        public uint GetFontSize(SharedFontType FontType)
+        {
+            return (uint)FontData[FontType].Length;
+        }
+
+        public uint GetSharedMemoryAddressOffset(SharedFontType FontType)
+        {
+            uint Pos = 0x8;
+
+            for (SharedFontType Type = SharedFontType.JapanUsEurope; Type < FontType; Type++)
+            {
+                Pos += GetFontSize(Type);
+                Pos += 0x8;
+            }
+
+            return Pos;
+        }
+
+        public int Count => FontData.Count;
+    }
+}
diff --git a/Ryujinx.HLE/OsHle/Services/Pl/SharedFontType.cs b/Ryujinx.HLE/Font/SharedFontType.cs
similarity index 76%
rename from Ryujinx.HLE/OsHle/Services/Pl/SharedFontType.cs
rename to Ryujinx.HLE/Font/SharedFontType.cs
index 97fd95dc9..ca8a42b0c 100644
--- a/Ryujinx.HLE/OsHle/Services/Pl/SharedFontType.cs
+++ b/Ryujinx.HLE/Font/SharedFontType.cs
@@ -1,6 +1,6 @@
-namespace Ryujinx.HLE.OsHle.Services.Pl
+namespace Ryujinx.HLE.Font
 {
-    enum SharedFontType
+    public enum SharedFontType
     {
         JapanUsEurope       = 0,
         SimplifiedChinese   = 1,
diff --git a/Ryujinx.HLE/Hid/Hid.cs b/Ryujinx.HLE/Hid/Hid.cs
index 2f007f1fb..43c040bb5 100644
--- a/Ryujinx.HLE/Hid/Hid.cs
+++ b/Ryujinx.HLE/Hid/Hid.cs
@@ -67,7 +67,7 @@ namespace Ryujinx.HLE.Input
 
         private object ShMemLock;
 
-        private (AMemory, long)[] ShMemPositions;
+        private (AMemory, long, long)[] ShMemPositions;
 
         public Hid(Logger Log)
         {
@@ -75,7 +75,7 @@ namespace Ryujinx.HLE.Input
 
             ShMemLock = new object();
 
-            ShMemPositions = new (AMemory, long)[0];
+            ShMemPositions = new (AMemory, long, long)[0];
         }
 
         internal void ShMemMap(object sender, EventArgs e)
@@ -86,7 +86,7 @@ namespace Ryujinx.HLE.Input
             {
                 ShMemPositions = SharedMem.GetVirtualPositions();
 
-                (AMemory Memory, long Position) = ShMemPositions[ShMemPositions.Length - 1];
+                (AMemory Memory, long Position, long Size) = ShMemPositions[ShMemPositions.Length - 1];
 
                 for (long Offset = 0; Offset < Horizon.HidSize; Offset += 8)
                 {
@@ -167,7 +167,7 @@ namespace Ryujinx.HLE.Input
         {
             lock (ShMemLock)
             {
-                foreach ((AMemory Memory, long Position) in ShMemPositions)
+                foreach ((AMemory Memory, long Position, long Size) in ShMemPositions)
                 {
                     long ControllerOffset = Position + HidControllersOffset;
 
@@ -218,7 +218,7 @@ namespace Ryujinx.HLE.Input
         {
             lock (ShMemLock)
             {
-                foreach ((AMemory Memory, long Position) in ShMemPositions)
+                foreach ((AMemory Memory, long Position, long Size) in ShMemPositions)
                 {
                     long TouchScreenOffset = Position + HidTouchScreenOffset;
 
diff --git a/Ryujinx.HLE/Logging/LogClass.cs b/Ryujinx.HLE/Logging/LogClass.cs
index c377ace66..95cae7e0a 100644
--- a/Ryujinx.HLE/Logging/LogClass.cs
+++ b/Ryujinx.HLE/Logging/LogClass.cs
@@ -4,6 +4,7 @@ namespace Ryujinx.HLE.Logging
     {
         Audio,
         Cpu,
+        Font,
         Gpu,
         Hid,
         Kernel,
diff --git a/Ryujinx.HLE/OsHle/Handles/HSharedMem.cs b/Ryujinx.HLE/OsHle/Handles/HSharedMem.cs
index 6426e585e..cd3d82237 100644
--- a/Ryujinx.HLE/OsHle/Handles/HSharedMem.cs
+++ b/Ryujinx.HLE/OsHle/Handles/HSharedMem.cs
@@ -6,37 +6,37 @@ namespace Ryujinx.HLE.OsHle.Handles
 {
     class HSharedMem
     {
-        private List<(AMemory, long)> Positions;
+        private List<(AMemory, long, long)> Positions;
 
         public EventHandler<EventArgs> MemoryMapped;
         public EventHandler<EventArgs> MemoryUnmapped;
 
         public HSharedMem()
         {
-            Positions = new List<(AMemory, long)>();
+            Positions = new List<(AMemory, long, long)>();
         }
 
-        public void AddVirtualPosition(AMemory Memory, long Position)
+        public void AddVirtualPosition(AMemory Memory, long Position, long Size)
         {
             lock (Positions)
             {
-                Positions.Add((Memory, Position));
+                Positions.Add((Memory, Position, Size));
 
                 MemoryMapped?.Invoke(this, EventArgs.Empty);
             }
         }
 
-        public void RemoveVirtualPosition(AMemory Memory, long Position)
+        public void RemoveVirtualPosition(AMemory Memory, long Position, long Size)
         {
             lock (Positions)
             {
-                Positions.Remove((Memory, Position));
+                Positions.Remove((Memory, Position, Size));
 
                 MemoryUnmapped?.Invoke(this, EventArgs.Empty);
             }
         }
 
-        public (AMemory, long)[] GetVirtualPositions()
+        public (AMemory, long, long)[] GetVirtualPositions()
         {
             return Positions.ToArray();
         }
diff --git a/Ryujinx.HLE/OsHle/Kernel/SvcHandler.cs b/Ryujinx.HLE/OsHle/Kernel/SvcHandler.cs
index e816c44ec..6f7bc42fd 100644
--- a/Ryujinx.HLE/OsHle/Kernel/SvcHandler.cs
+++ b/Ryujinx.HLE/OsHle/Kernel/SvcHandler.cs
@@ -22,7 +22,7 @@ namespace Ryujinx.HLE.OsHle.Kernel
 
         private ConcurrentDictionary<KThread, AutoResetEvent> SyncWaits;
 
-        private HashSet<(HSharedMem, long)> MappedSharedMems;
+        private HashSet<(HSharedMem, long, long)> MappedSharedMems;
 
         private ulong CurrentHeapSize;
 
@@ -83,7 +83,7 @@ namespace Ryujinx.HLE.OsHle.Kernel
 
             SyncWaits = new ConcurrentDictionary<KThread, AutoResetEvent>();
 
-            MappedSharedMems = new HashSet<(HSharedMem, long)>();
+            MappedSharedMems = new HashSet<(HSharedMem, long, long)>();
         }
 
         static SvcHandler()
@@ -138,9 +138,9 @@ namespace Ryujinx.HLE.OsHle.Kernel
             {
                 lock (MappedSharedMems)
                 {
-                    foreach ((HSharedMem SharedMem, long Position) in MappedSharedMems)
+                    foreach ((HSharedMem SharedMem, long Position, long Size) in MappedSharedMems)
                     {
-                        SharedMem.RemoveVirtualPosition(Memory, Position);
+                        SharedMem.RemoveVirtualPosition(Memory, Position, Size);
                     }
 
                     MappedSharedMems.Clear();
diff --git a/Ryujinx.HLE/OsHle/Kernel/SvcMemory.cs b/Ryujinx.HLE/OsHle/Kernel/SvcMemory.cs
index bb73f1ea1..f10cad7a2 100644
--- a/Ryujinx.HLE/OsHle/Kernel/SvcMemory.cs
+++ b/Ryujinx.HLE/OsHle/Kernel/SvcMemory.cs
@@ -174,15 +174,15 @@ namespace Ryujinx.HLE.OsHle.Kernel
 
                 AMemoryHelper.FillWithZeros(Memory, Src, (int)Size);
 
+                SharedMem.AddVirtualPosition(Memory, Src, Size);
+
                 Memory.Manager.Reprotect(Src, Size, (AMemoryPerm)Perm);
 
                 lock (MappedSharedMems)
                 {
-                    MappedSharedMems.Add((SharedMem, Src));
+                    MappedSharedMems.Add((SharedMem, Src, Size));
                 }
 
-                SharedMem.AddVirtualPosition(Memory, Src);
-
                 ThreadState.X0 = 0;
             }
 
@@ -210,11 +210,11 @@ namespace Ryujinx.HLE.OsHle.Kernel
             {
                 Memory.Manager.Unmap(Src, Size, (int)MemoryType.SharedMemory);
 
-                SharedMem.RemoveVirtualPosition(Memory, Src);
+                SharedMem.RemoveVirtualPosition(Memory, Src, Size);
 
                 lock (MappedSharedMems)
                 {
-                    MappedSharedMems.Remove((SharedMem, Src));
+                    MappedSharedMems.Remove((SharedMem, Src, Size));
                 }
 
                 ThreadState.X0 = 0;
diff --git a/Ryujinx.HLE/OsHle/Kernel/SvcSystem.cs b/Ryujinx.HLE/OsHle/Kernel/SvcSystem.cs
index 08305522f..a968a1dbc 100644
--- a/Ryujinx.HLE/OsHle/Kernel/SvcSystem.cs
+++ b/Ryujinx.HLE/OsHle/Kernel/SvcSystem.cs
@@ -242,7 +242,6 @@ namespace Ryujinx.HLE.OsHle.Kernel
                 Process.Scheduler.Suspend(CurrThread);
 
                 IpcMessage Cmd = new IpcMessage(CmdData, CmdPtr);
-
                 long Result = IpcHandler.IpcCall(Ns, Process, Memory, Session, Cmd, CmdPtr);
 
                 Thread.Yield();
diff --git a/Ryujinx.HLE/OsHle/Services/Pl/ISharedFontManager.cs b/Ryujinx.HLE/OsHle/Services/Pl/ISharedFontManager.cs
index 9f85f3d10..b8447ac65 100644
--- a/Ryujinx.HLE/OsHle/Services/Pl/ISharedFontManager.cs
+++ b/Ryujinx.HLE/OsHle/Services/Pl/ISharedFontManager.cs
@@ -1,3 +1,4 @@
+using Ryujinx.HLE.Font;
 using Ryujinx.HLE.OsHle.Ipc;
 using System.Collections.Generic;
 
@@ -13,11 +14,12 @@ namespace Ryujinx.HLE.OsHle.Services.Pl
         {
             m_Commands = new Dictionary<int, ServiceProcessRequest>()
             {
-                { 0, RequestLoad                  },
-                { 1, GetLoadState                 },
-                { 2, GetFontSize                  },
-                { 3, GetSharedMemoryAddressOffset },
-                { 4, GetSharedMemoryNativeHandle  }
+                { 0, RequestLoad                    },
+                { 1, GetLoadState                   },
+                { 2, GetFontSize                    },
+                { 3, GetSharedMemoryAddressOffset   },
+                { 4, GetSharedMemoryNativeHandle    },
+                { 5, GetSharedFontInOrderOfPriority }
             };
         }
 
@@ -25,26 +27,34 @@ namespace Ryujinx.HLE.OsHle.Services.Pl
         {
             SharedFontType FontType = (SharedFontType)Context.RequestData.ReadInt32();
 
+            Context.Ns.Font.Load(FontType);
+
             return 0;
         }
 
         public long GetLoadState(ServiceCtx Context)
         {
-            Context.ResponseData.Write(1); //Loaded
+            SharedFontType FontType = (SharedFontType)Context.RequestData.ReadInt32();
+
+            Context.ResponseData.Write(Context.Ns.Font.GetLoadState(FontType));
 
             return 0;
         }
 
         public long GetFontSize(ServiceCtx Context)
         {
-            Context.ResponseData.Write(Horizon.FontSize);
+            SharedFontType FontType = (SharedFontType)Context.RequestData.ReadInt32();
+
+            Context.ResponseData.Write(Context.Ns.Font.GetFontSize(FontType));
 
             return 0;
         }
 
         public long GetSharedMemoryAddressOffset(ServiceCtx Context)
         {
-            Context.ResponseData.Write(0);
+            SharedFontType FontType = (SharedFontType)Context.RequestData.ReadInt32();
+
+            Context.ResponseData.Write(Context.Ns.Font.GetSharedMemoryAddressOffset(FontType));
 
             return 0;
         }
@@ -57,5 +67,51 @@ namespace Ryujinx.HLE.OsHle.Services.Pl
 
             return 0;
         }
+
+        private uint AddFontToOrderOfPriorityList(ServiceCtx Context, SharedFontType FontType, uint BufferPos, out uint LoadState)
+        {
+            long TypesPosition          = Context.Request.ReceiveBuff[0].Position;
+            long TypesSize              = Context.Request.ReceiveBuff[0].Size;
+
+            long OffsetsPosition        = Context.Request.ReceiveBuff[1].Position;
+            long OffsetsSize            = Context.Request.ReceiveBuff[1].Size;
+
+            long FontSizeBufferPosition = Context.Request.ReceiveBuff[2].Position;
+            long FontSizeBufferSize     = Context.Request.ReceiveBuff[2].Size;
+
+            LoadState                   = Context.Ns.Font.GetLoadState(FontType);
+
+            if (BufferPos >= TypesSize || BufferPos >= OffsetsSize || BufferPos >= FontSizeBufferSize)
+            {
+                return 0;
+            }
+
+            Context.Memory.WriteUInt32(TypesPosition + BufferPos, (uint)FontType);
+            Context.Memory.WriteUInt32(OffsetsPosition + BufferPos, Context.Ns.Font.GetSharedMemoryAddressOffset(FontType));
+            Context.Memory.WriteUInt32(FontSizeBufferPosition + BufferPos, Context.Ns.Font.GetFontSize(FontType));
+
+            BufferPos += 4;
+
+            return BufferPos;
+        }
+
+        public long GetSharedFontInOrderOfPriority(ServiceCtx Context)
+        {
+            ulong LanguageCode = Context.RequestData.ReadUInt64();
+            uint  LoadedCount  = 0;
+            uint  BufferPos    = 0;
+            uint  Loaded       = 0;
+
+            for (int Type = 0; Type < Context.Ns.Font.Count; Type++)
+            {
+                BufferPos   = AddFontToOrderOfPriorityList(Context, (SharedFontType)Type, BufferPos, out Loaded);
+                LoadedCount += Loaded;
+            }
+
+            Context.ResponseData.Write(LoadedCount);
+            Context.ResponseData.Write(Context.Ns.Font.Count);
+
+            return 0;
+        }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.HLE/Resource/InvalidSystemResourceException.cs b/Ryujinx.HLE/Resource/InvalidSystemResourceException.cs
new file mode 100644
index 000000000..35c4874a3
--- /dev/null
+++ b/Ryujinx.HLE/Resource/InvalidSystemResourceException.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Ryujinx.HLE.Resource
+{
+    public class InvalidSystemResourceException : Exception
+    {
+        public InvalidSystemResourceException(string message)
+            : base(message)
+        {
+        }
+
+    }
+}
diff --git a/Ryujinx.HLE/Ryujinx.HLE.csproj b/Ryujinx.HLE/Ryujinx.HLE.csproj
index acef4be9e..f7fb84a58 100644
--- a/Ryujinx.HLE/Ryujinx.HLE.csproj
+++ b/Ryujinx.HLE/Ryujinx.HLE.csproj
@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
     <TargetFramework>netcoreapp2.1</TargetFramework>
diff --git a/Ryujinx.HLE/Switch.cs b/Ryujinx.HLE/Switch.cs
index 74c0564a9..a80ca86c1 100644
--- a/Ryujinx.HLE/Switch.cs
+++ b/Ryujinx.HLE/Switch.cs
@@ -1,5 +1,6 @@
 using Ryujinx.Audio;
 using Ryujinx.Graphics.Gal;
+using Ryujinx.HLE.Font;
 using Ryujinx.HLE.Gpu;
 using Ryujinx.HLE.Input;
 using Ryujinx.HLE.Logging;
@@ -27,6 +28,8 @@ namespace Ryujinx.HLE
 
         public Hid Hid { get; private set; }
 
+        public SharedFontManager Font { get; private set; }
+
         public event EventHandler Finish;
 
         public Switch(IGalRenderer Renderer, IAalOutput AudioOut)
@@ -57,8 +60,13 @@ namespace Ryujinx.HLE
 
             Hid = new Hid(Log);
 
-            Os.HidSharedMem.MemoryMapped   += Hid.ShMemMap;
-            Os.HidSharedMem.MemoryUnmapped += Hid.ShMemUnmap;
+            Font = new SharedFontManager(Log, VFs.GetSystemPath());
+
+            Os.HidSharedMem.MemoryMapped    += Hid.ShMemMap;
+            Os.HidSharedMem.MemoryUnmapped  += Hid.ShMemUnmap;
+
+            Os.FontSharedMem.MemoryMapped   += Font.ShMemMap;
+            Os.FontSharedMem.MemoryUnmapped += Font.ShMemUnmap;
         }
 
         public void LoadCart(string ExeFsDir, string RomFsFile = null)
diff --git a/Ryujinx.HLE/VirtualFileSystem.cs b/Ryujinx.HLE/VirtualFileSystem.cs
index df1fc9db1..31b8e184c 100644
--- a/Ryujinx.HLE/VirtualFileSystem.cs
+++ b/Ryujinx.HLE/VirtualFileSystem.cs
@@ -8,6 +8,7 @@ namespace Ryujinx.HLE
         private const string BasePath   = "RyuFs";
         private const string NandPath   = "nand";
         private const string SdCardPath = "sdmc";
+        private const string SystemPath = "system";
 
         public Stream RomFs { get; private set; }
 
@@ -45,6 +46,8 @@ namespace Ryujinx.HLE
 
         public string GetGameSavesPath() => MakeDirAndGetFullPath(NandPath);
 
+        public string GetSystemPath() => MakeDirAndGetFullPath(SystemPath);
+
         public string SwitchPathToSystemPath(string SwitchPath)
         {
             string[] Parts = SwitchPath.Split(":");