mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 19:07:01 +02:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7b7f9a70c6 | |||
| 6ad393775f |
@@ -28,9 +28,9 @@ static bool CoalescePlaceholders(uint64_t vaddr, uint64_t size) {
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename Regions, typename Source, typename Gap>
|
||||
static void CopySparseRange(const Regions& regions, uint64_t vaddr, void* data, uint64_t size,
|
||||
Source&& source, Gap&& gap) {
|
||||
template <typename Regions, typename Region, typename Gap>
|
||||
static void ForEachSparseRange(const Regions& regions, uint64_t vaddr, uint64_t size,
|
||||
Region&& region, Gap&& gap) {
|
||||
const auto end = vaddr + size;
|
||||
auto mapping = regions.lower_bound(vaddr);
|
||||
if (mapping != regions.begin()) {
|
||||
@@ -40,23 +40,34 @@ static void CopySparseRange(const Regions& regions, uint64_t vaddr, void* data,
|
||||
}
|
||||
}
|
||||
|
||||
auto* destination = static_cast<uint8_t*>(data);
|
||||
auto cursor = vaddr;
|
||||
auto cursor = vaddr;
|
||||
for (; mapping != regions.end() && mapping->second.vaddr < end; ++mapping) {
|
||||
const auto& entry = mapping->second;
|
||||
const auto start = std::max(vaddr, entry.vaddr);
|
||||
const auto bytes = std::min(end, entry.vaddr + entry.size) - start;
|
||||
if (cursor < start) {
|
||||
gap(cursor, destination + (cursor - vaddr), start - cursor);
|
||||
gap(cursor, start - cursor);
|
||||
}
|
||||
std::memcpy(destination + (start - vaddr), source(entry, start), bytes);
|
||||
region(entry, start, bytes);
|
||||
cursor = start + bytes;
|
||||
}
|
||||
if (cursor < end) {
|
||||
gap(cursor, destination + (cursor - vaddr), end - cursor);
|
||||
gap(cursor, end - cursor);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Regions, typename Source, typename Gap>
|
||||
static void CopySparseRange(const Regions& regions, uint64_t vaddr, void* data, uint64_t size,
|
||||
Source&& source, Gap&& gap) {
|
||||
auto* destination = static_cast<uint8_t*>(data);
|
||||
ForEachSparseRange(
|
||||
regions, vaddr, size,
|
||||
[&](const auto& entry, uint64_t start, uint64_t bytes) {
|
||||
std::memcpy(destination + (start - vaddr), source(entry, start), bytes);
|
||||
},
|
||||
[&](uint64_t start, uint64_t bytes) { gap(start, destination + (start - vaddr), bytes); });
|
||||
}
|
||||
|
||||
class GuestBackingStore {
|
||||
public:
|
||||
enum class FailureReason {
|
||||
@@ -200,36 +211,16 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip unbacked gaps, mirroring sparse reads that zero-fill them.
|
||||
std::lock_guard lock(m_mutex);
|
||||
const auto end = vaddr + size;
|
||||
auto first = m_maps.upper_bound(vaddr);
|
||||
if (first == m_maps.begin()) {
|
||||
return false;
|
||||
}
|
||||
--first;
|
||||
auto current = vaddr;
|
||||
for (auto mapping = first; current < end; ++mapping) {
|
||||
if (mapping == m_maps.end() || current < mapping->second.vaddr ||
|
||||
current >= mapping->second.vaddr + mapping->second.size) {
|
||||
return false;
|
||||
}
|
||||
const auto& entry = mapping->second;
|
||||
const auto bytes = std::min(end, entry.vaddr + entry.size) - current;
|
||||
if (!RangeOk(entry.backing_offset + current - entry.vaddr, bytes)) {
|
||||
return false;
|
||||
}
|
||||
current += bytes;
|
||||
}
|
||||
|
||||
const auto* source = static_cast<const uint8_t*>(data);
|
||||
current = vaddr;
|
||||
for (auto mapping = first; current < end; ++mapping) {
|
||||
const auto& entry = mapping->second;
|
||||
const auto bytes = std::min(end, entry.vaddr + entry.size) - current;
|
||||
const auto offset = entry.backing_offset + current - entry.vaddr;
|
||||
std::memcpy(m_backing_base + offset, source + (current - vaddr), bytes);
|
||||
current += bytes;
|
||||
}
|
||||
const auto* source = static_cast<const uint8_t*>(data);
|
||||
ForEachSparseRange(
|
||||
m_maps, vaddr, size,
|
||||
[&](const auto& entry, uint64_t start, uint64_t bytes) {
|
||||
std::memcpy(m_backing_base + (entry.backing_offset + start - entry.vaddr),
|
||||
source + (start - vaddr), bytes);
|
||||
},
|
||||
[](uint64_t, uint64_t) {});
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -775,8 +766,14 @@ public:
|
||||
});
|
||||
}
|
||||
|
||||
// Writes the backed bytes of a range that holds no private mappings.
|
||||
bool TryWriteBacking(uint64_t vaddr, const void* data, uint64_t size) {
|
||||
return m_backing->TryWriteBacking(vaddr, data, size);
|
||||
if (!Owns(vaddr, size)) {
|
||||
return false;
|
||||
}
|
||||
std::shared_lock lock(m_mutex);
|
||||
return !OverlapsPrivateUnlocked(vaddr, size) &&
|
||||
m_backing->TryWriteBacking(vaddr, data, size);
|
||||
}
|
||||
|
||||
bool TryReadBacking(uint64_t vaddr, void* data, uint64_t size) {
|
||||
@@ -790,15 +787,8 @@ public:
|
||||
}
|
||||
std::shared_lock lock(m_mutex);
|
||||
if constexpr (!copy_private) {
|
||||
auto mapping = m_mapped.upper_bound(vaddr);
|
||||
if (mapping != m_mapped.begin()) {
|
||||
--mapping;
|
||||
}
|
||||
for (; mapping != m_mapped.end() && mapping->second.vaddr < vaddr + size; ++mapping) {
|
||||
const auto& region = mapping->second;
|
||||
if (region.type == MappingType::Private && region.vaddr + region.size > vaddr) {
|
||||
return false;
|
||||
}
|
||||
if (OverlapsPrivateUnlocked(vaddr, size)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return m_backing->TryReadSparseBacking(
|
||||
@@ -1111,6 +1101,20 @@ private:
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool OverlapsPrivateUnlocked(uint64_t vaddr, uint64_t size) const {
|
||||
auto mapping = m_mapped.upper_bound(vaddr);
|
||||
if (mapping != m_mapped.begin()) {
|
||||
--mapping;
|
||||
}
|
||||
for (; mapping != m_mapped.end() && mapping->second.vaddr < vaddr + size; ++mapping) {
|
||||
const auto& region = mapping->second;
|
||||
if (region.type == MappingType::Private && region.vaddr + region.size > vaddr) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AddMappedUnlocked(uint64_t vaddr, uint64_t size, MappingType type) {
|
||||
if (size == 0 || UINT64_MAX - vaddr < size) {
|
||||
return false;
|
||||
|
||||
+12
-4
@@ -3389,6 +3389,11 @@ int KYTY_SYSV_ABI PthreadCancel(Pthread thread) {
|
||||
return KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
// A joined thread's native handle is gone; the guest may still hold its handle.
|
||||
if (thread->free) {
|
||||
return KERNEL_ERROR_ESRCH;
|
||||
}
|
||||
|
||||
int result = pthread_cancel(thread->p);
|
||||
|
||||
LOGF("\tthread cancel: %s, %d\n", thread->name.c_str(), result);
|
||||
@@ -3492,10 +3497,8 @@ int KYTY_SYSV_ABI PthreadGetprio(Pthread thread, int* prio) {
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(prio == nullptr);
|
||||
|
||||
sched_param native_param {};
|
||||
int native_policy = 0;
|
||||
if (pthread_getschedparam(thread->p, &native_policy, &native_param) != 0) {
|
||||
return KERNEL_ERROR_EINVAL;
|
||||
if (thread->free) {
|
||||
return KERNEL_ERROR_ESRCH;
|
||||
}
|
||||
|
||||
*prio = thread->attr->guest_priority;
|
||||
@@ -3510,6 +3513,11 @@ int KYTY_SYSV_ABI PthreadSetprio(Pthread thread, int prio) {
|
||||
return KERNEL_ERROR_ESRCH;
|
||||
}
|
||||
|
||||
// A joined thread's native handle is gone; the guest may still hold its handle.
|
||||
if (thread->free) {
|
||||
return KERNEL_ERROR_ESRCH;
|
||||
}
|
||||
|
||||
sched_param param {};
|
||||
int pol = 0;
|
||||
|
||||
|
||||
@@ -1596,20 +1596,23 @@ void TestDirectMapQueryOffsetAndPartialMunmap() {
|
||||
ExpectUnmapped(test, base + SceKernelPageSize);
|
||||
|
||||
constexpr uint64_t transaction_sentinel = 0x5452414e53414354ull; // "TRANSACT"
|
||||
constexpr uint64_t rejected_write = 0x4e4f504152544941ull; // "NOPARTIA"
|
||||
constexpr uint64_t sparse_write = 0x4e4f504152544941ull; // "NOPARTIA"
|
||||
constexpr uint64_t backed_prefix_mask = 0xffffffffull;
|
||||
const auto crossing_address = base + SceKernelPageSize - sizeof(uint32_t);
|
||||
std::memcpy(reinterpret_cast<void*>(alias_base + SceKernelPageSize - sizeof(uint32_t)),
|
||||
&transaction_sentinel, sizeof(transaction_sentinel));
|
||||
Check(test,
|
||||
!Libs::LibKernel::Memory::TryWriteBacking(crossing_address, &rejected_write,
|
||||
sizeof(rejected_write)),
|
||||
"TryWriteBacking should reject a range crossing an unmapped span");
|
||||
uint64_t backing_after_rejected_write = 0;
|
||||
std::memcpy(&backing_after_rejected_write,
|
||||
Libs::LibKernel::Memory::TryWriteBacking(crossing_address, &sparse_write,
|
||||
sizeof(sparse_write)),
|
||||
"TryWriteBacking should write a range crossing an unmapped span");
|
||||
uint64_t backing_after_sparse_write = 0;
|
||||
std::memcpy(&backing_after_sparse_write,
|
||||
reinterpret_cast<const void*>(alias_base + SceKernelPageSize - sizeof(uint32_t)),
|
||||
sizeof(backing_after_rejected_write));
|
||||
Check(test, backing_after_rejected_write == transaction_sentinel,
|
||||
"failed backing writes must not modify a validated prefix");
|
||||
sizeof(backing_after_sparse_write));
|
||||
Check(test,
|
||||
backing_after_sparse_write == ((sparse_write & backed_prefix_mask) |
|
||||
(transaction_sentinel & ~backed_prefix_mask)),
|
||||
"sparse backing writes must fill the backed prefix and skip the unmapped span");
|
||||
uint64_t rejected_read = transaction_sentinel;
|
||||
Check(test,
|
||||
!Libs::LibKernel::Memory::TryReadBacking(crossing_address, &rejected_read,
|
||||
|
||||
Reference in New Issue
Block a user