nvservices debug unlock + license change

This commit is contained in:
souldbminersmwc committed 2026-08-13 18:40:51 -04:00
1 parent e321a18479
commit 5b70938f91
18 files changed
+147 -14

No files matched your search

@@ -121,9 +121,10 @@ namespace ams::ldr {
/* Global NSO header cache. */
NsoHeader g_nso_headers[Nso_Count];
/* Pcv/Ptm check cache */
/* Pcv/Ptm/NvServices check cache */
bool g_is_pcv;
bool g_is_ptm;
bool g_is_nvsrv;
/* Global Zstd decompression context. */
constexpr size_t ZstdDctxWorkspaceSize = 0x176E8;
@@ -379,6 +380,7 @@ namespace ams::ldr {
/* Check if NCA is PCV or PTM */
g_is_pcv = meta->aci->program_id == ncm::SystemProgramId::Pcv;
g_is_ptm = meta->aci->program_id == ncm::SystemProgramId::Ptm;
g_is_nvsrv = meta->aci->program_id == ncm::SystemProgramId::NvServices;
/* If we have data to validate, validate it. */
if (meta->check_verification_data) {
@@ -752,6 +754,10 @@ namespace ams::ldr {
if (g_is_ptm) {
hoc::ptm::Patch(map_address, nso_size);
}
if (g_is_nvsrv) {
hoc::nvsrv::Patch(map_address, nso_size, nso_address);
}
}
/* Set permissions. */
@@ -0,0 +1,102 @@
/*
* Copyright (c) Souldbminer, Lightos and Horizon OC Contributors
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "nvsrv.hpp"
namespace ams::ldr::hoc::nvsrv {
namespace {
/* NvServices device names */
constexpr char DbgGpuPath[] = "/dev/nvhost-dbg-gpu";
constexpr char ProfGpuPath[] = "/dev/nvhost-prof-gpu";
/* Permission offset to patch */
constexpr size_t DevTablePermOffset = 0x68;
uintptr_t FindBytes(uintptr_t start, uintptr_t end, const void *needle, size_t len) {
const u8 *pat = reinterpret_cast<const u8 *>(needle);
for (uintptr_t addr = start; addr + len <= end; ++addr) {
if (std::memcmp(reinterpret_cast<const void *>(addr), pat, len) == 0) {
return addr;
}
}
return 0;
}
/* Unlock the devices */
Result UnlockDevicePermission(uintptr_t mapped_nso, size_t nso_size, uintptr_t nso_address, const char *path, const char *description) {
const size_t path_len = std::strlen(path) + 1;
const uintptr_t str_addr = FindBytes(mapped_nso, mapped_nso + nso_size, path, path_len);
if (str_addr == 0) {
LOGGING("nvsrv: %s path string not found (nso_size=%lx)", description, static_cast<unsigned long>(nso_size));
R_THROW(ldr::ResultInvalidNvsrvDevTable());
}
const uintptr_t str_offset = str_addr - mapped_nso;
const uintptr_t candidates[] = { str_offset, nso_address + str_offset };
uintptr_t entry_addr = 0;
for (uintptr_t ptr = mapped_nso; entry_addr == 0 && ptr + sizeof(uintptr_t) <= mapped_nso + nso_size; ptr += sizeof(uintptr_t)) {
const uintptr_t val = *reinterpret_cast<const uintptr_t *>(ptr);
for (uintptr_t cand : candidates) {
if (val == cand) {
entry_addr = ptr;
break;
}
}
}
if (entry_addr == 0) {
LOGGING("nvsrv: %s str@+%lx has no referencing table entry", description,
static_cast<unsigned long>(str_offset), static_cast<unsigned long>(candidates[0]), static_cast<unsigned long>(candidates[1]));
R_THROW(ldr::ResultInvalidNvsrvDevTable());
}
const uintptr_t perm_addr = entry_addr + DevTablePermOffset;
if (perm_addr + sizeof(uintptr_t) > mapped_nso + nso_size) {
LOGGING("nvsrv: %s entry@+%lx perm field out of bounds", description, static_cast<unsigned long>(entry_addr - mapped_nso));
R_THROW(ldr::ResultInvalidNvsrvDevTable());
}
uintptr_t *perm = reinterpret_cast<uintptr_t *>(perm_addr);
LOGGING("nvsrv: %s entry@+%lx perm@+%lx was %lx", description,
static_cast<unsigned long>(entry_addr - mapped_nso),
static_cast<unsigned long>(perm_addr - mapped_nso),
static_cast<unsigned long>(*perm));
PATCH_OFFSET(perm, static_cast<uintptr_t>(0));
R_SUCCEED();
}
}
void Patch(uintptr_t mapped_nso, size_t nso_size, uintptr_t nso_address) {
struct {
const char *path;
const char *description;
} targets[] = {
{ DbgGpuPath, "dbg-gpu" },
{ ProfGpuPath, "prof-gpu" },
};
for (auto &t : targets) {
const Result res = UnlockDevicePermission(mapped_nso, nso_size, nso_address, t.path, t.description);
LOGGING("nvsrv: %s unlock%s", t.description, R_SUCCEEDED(res) ? "ed" : " skipped");
}
}
}
@@ -0,0 +1,23 @@
/*
* Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "../oc_common.hpp"
namespace ams::ldr::hoc::nvsrv {
void Patch(uintptr_t mapped_nso, size_t nso_size, uintptr_t nso_address);
}
@@ -94,6 +94,7 @@ namespace ams::ldr {
R_DEFINE_ERROR_RESULT(HookPayloadEscapes, 1028);
R_DEFINE_ERROR_RESULT(HookDataOutOfMemory, 1029);
R_DEFINE_ERROR_RESULT(HookUnavailable, 1030);
R_DEFINE_ERROR_RESULT(InvalidNvsrvDevTable, 1031);
}
namespace ams::ldr::hoc {
@@ -21,3 +21,4 @@
#include "oc_common.hpp"
#include "pcv/pcv.hpp"
#include "ptm/ptm.hpp"
#include "nvsrv/nvsrv.hpp"
@@ -5,7 +5,7 @@
*
* Copyright (c) B3711
*
* Copyright (c) Souldbminer and Horizon OC Contributors
* Copyright (c) Souldbminer, Lightos and Horizon OC Contributors
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -5,7 +5,7 @@
*
* Copyright (c) B3711
*
* Copyright (c) Souldbminer and Horizon OC Contributors
* Copyright (c) Souldbminer, Lightos and Horizon OC Contributors
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -5,7 +5,7 @@
*
* Copyright (c) B3711
*
* Copyright (c) Souldbminer and Horizon OC Contributors
* Copyright (c) Souldbminer, Lightos and Horizon OC Contributors
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -5,7 +5,7 @@
*
* Copyright (c) B3711
*
* Copyright (c) Souldbminer and Horizon OC Contributors
* Copyright (c) Souldbminer, Lightos and Horizon OC Contributors
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -5,7 +5,7 @@
*
* Copyright (c) B3711
*
* Copyright (c) Souldbminer and Horizon OC Contributors
* Copyright (c) Souldbminer, Lightos and Horizon OC Contributors
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -5,7 +5,7 @@
*
* Copyright (c) B3711
*
* Copyright (c) Souldbminer and Horizon OC Contributors
* Copyright (c) Souldbminer, Lightos and Horizon OC Contributors
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -5,7 +5,7 @@
*
* Copyright (c) B3711
*
* Copyright (c) Souldbminer and Horizon OC Contributors
* Copyright (c) Souldbminer, Lightos and Horizon OC Contributors
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -1,6 +1,6 @@
/*
*
* Copyright (c) Souldbminer and Horizon OC Contributors
* Copyright (c) Souldbminer, Lightos and Horizon OC Contributors
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -1,5 +1,5 @@
/*
* Copyright (c) Souldbminer and Horizon OC Contributors
* Copyright (c) Souldbminer, Lightos and Horizon OC Contributors
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -1,5 +1,5 @@
/*
* Copyright (c) Souldbminer and Horizon OC Contributors
* Copyright (c) Souldbminer, Lightos and Horizon OC Contributors
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -1,5 +1,5 @@
/*
* Copyright (c) Souldbminer and Horizon OC Contributors
* Copyright (c) Souldbminer, Lightos and Horizon OC Contributors
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -1,5 +1,5 @@
/*
* Copyright (c) Souldbminer and Horizon OC Contributors
* Copyright (c) Souldbminer, Lightos and Horizon OC Contributors
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -1,5 +1,5 @@
/*
* Copyright (c) Souldbminer and Horizon OC Contributors
* Copyright (c) Souldbminer, Lightos and Horizon OC Contributors
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,