diff --git a/src/SharpEmu.Libs/DiscMap/DiscMapExports.cs b/src/SharpEmu.Libs/DiscMap/DiscMapExports.cs
new file mode 100644
index 0000000..7363aa1
--- /dev/null
+++ b/src/SharpEmu.Libs/DiscMap/DiscMapExports.cs
@@ -0,0 +1,104 @@
+// Copyright (C) 2026 SharpEmu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+using SharpEmu.HLE;
+
+namespace SharpEmu.Libs.DiscMap;
+
+///
+/// HLE implementation of libSceDiscMap, ported from Kyty's LibDiscMap.cpp
+/// (https://github.com/InoriRus/Kyty, MIT). Titles installed to internal
+/// storage query these entry points on nearly every file access to decide
+/// whether a read must be redirected to the Blu-ray drive. Reporting every
+/// request as already resident on HDD lets the regular file system path
+/// service the read.
+///
+public static class DiscMapExports
+{
+ private const int DiscMapErrorInvalidArgument = unchecked((int)0x81100001);
+ private const int DiscMapErrorLocationNotMapped = unchecked((int)0x81100002);
+ private const int DiscMapErrorFileNotFound = unchecked((int)0x81100003);
+ private const int DiscMapErrorNoBitmapInfo = unchecked((int)0x81100004);
+
+ [SysAbiExport(
+ Nid = "lbQKqsERhtE",
+ ExportName = "sceDiscMapIsRequestOnHDD",
+ Target = Generation.Gen4 | Generation.Gen5,
+ LibraryName = "libSceDiscMap")]
+ public static int DiscMapIsRequestOnHDD(CpuContext ctx)
+ {
+ var pathAddress = ctx[CpuRegister.Rdi];
+ var offset = ctx[CpuRegister.Rsi];
+ var size = ctx[CpuRegister.Rdx];
+ var resultAddress = ctx[CpuRegister.Rcx];
+
+ if (pathAddress == 0 || resultAddress == 0)
+ {
+ return DiscMapErrorInvalidArgument;
+ }
+
+ if (!ctx.TryWriteInt32(resultAddress, 1))
+ {
+ return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
+ }
+
+ TraceDiscMap(ctx, "sceDiscMapIsRequestOnHDD", pathAddress, offset, size);
+
+ ctx[CpuRegister.Rax] = 0;
+ return (int)OrbisGen2Result.ORBIS_GEN2_OK;
+ }
+
+ [SysAbiExport(
+ Nid = "fJgP+wqifno",
+ ExportName = "sceDiscMapUnknownFJgP",
+ Target = Generation.Gen4 | Generation.Gen5,
+ LibraryName = "libSceDiscMap")]
+ public static int DiscMapUnknownFJgP(CpuContext ctx) => WriteMappingTriple(ctx, "sceDiscMapUnknownFJgP");
+
+ [SysAbiExport(
+ Nid = "ioKMruft1ek",
+ ExportName = "sceDiscMapUnknownIoKM",
+ Target = Generation.Gen4 | Generation.Gen5,
+ LibraryName = "libSceDiscMap")]
+ public static int DiscMapUnknownIoKM(CpuContext ctx) => WriteMappingTriple(ctx, "sceDiscMapUnknownIoKM");
+
+ private static int WriteMappingTriple(CpuContext ctx, string exportName)
+ {
+ var pathAddress = ctx[CpuRegister.Rdi];
+ var offset = ctx[CpuRegister.Rsi];
+ var size = ctx[CpuRegister.Rdx];
+ var flagsAddress = ctx[CpuRegister.Rcx];
+ var outAddress1 = ctx[CpuRegister.R8];
+ var outAddress2 = ctx[CpuRegister.R9];
+
+ if (pathAddress == 0 || flagsAddress == 0 || outAddress1 == 0 || outAddress2 == 0)
+ {
+ return DiscMapErrorInvalidArgument;
+ }
+
+ if (!ctx.TryWriteUInt64(flagsAddress, 0) ||
+ !ctx.TryWriteUInt64(outAddress1, 0) ||
+ !ctx.TryWriteUInt64(outAddress2, 0))
+ {
+ return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
+ }
+
+ TraceDiscMap(ctx, exportName, pathAddress, offset, size);
+
+ ctx[CpuRegister.Rax] = 0;
+ return (int)OrbisGen2Result.ORBIS_GEN2_OK;
+ }
+
+ private static void TraceDiscMap(CpuContext ctx, string exportName, ulong pathAddress, ulong offset, ulong size)
+ {
+ if (!string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_DISCMAP"), "1", StringComparison.Ordinal))
+ {
+ return;
+ }
+
+ var path = ctx.TryReadNullTerminatedUtf8(pathAddress, 1024, out var value)
+ ? value
+ : $"";
+ Console.Error.WriteLine($"[HLE][DISCMAP] {exportName} path={path} offset=0x{offset:X} size=0x{size:X}");
+ }
+}