diff options
| author | 2022-09-09 21:17:52 -0700 | |
|---|---|---|
| committer | 2022-10-18 19:13:34 -0700 | |
| commit | 58eb6953d1417d667af36461ac8391e005f49457 (patch) | |
| tree | 3d21d4c4029e8d1e5087fbc11c8fe132f98d16db /src | |
| parent | core: hle: kernel: k_memory_block_manager: Update. (diff) | |
| download | yuzu-58eb6953d1417d667af36461ac8391e005f49457.tar.gz yuzu-58eb6953d1417d667af36461ac8391e005f49457.tar.xz yuzu-58eb6953d1417d667af36461ac8391e005f49457.zip | |
core: hle: kernel: k_memory_block: Update.
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/kernel/k_memory_block.h | 506 | ||||
| -rw-r--r-- | src/core/hle/service/ldr/ldr.cpp | 4 |
2 files changed, 391 insertions, 119 deletions
diff --git a/src/core/hle/kernel/k_memory_block.h b/src/core/hle/kernel/k_memory_block.h index 18df1f836..9444f6bd2 100644 --- a/src/core/hle/kernel/k_memory_block.h +++ b/src/core/hle/kernel/k_memory_block.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include "common/alignment.h" | 6 | #include "common/alignment.h" |
| 7 | #include "common/assert.h" | 7 | #include "common/assert.h" |
| 8 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 9 | #include "common/intrusive_red_black_tree.h" | ||
| 9 | #include "core/hle/kernel/memory_types.h" | 10 | #include "core/hle/kernel/memory_types.h" |
| 10 | #include "core/hle/kernel/svc_types.h" | 11 | #include "core/hle/kernel/svc_types.h" |
| 11 | 12 | ||
| @@ -168,9 +169,8 @@ constexpr KMemoryPermission ConvertToKMemoryPermission(Svc::MemoryPermission per | |||
| 168 | 169 | ||
| 169 | enum class KMemoryAttribute : u8 { | 170 | enum class KMemoryAttribute : u8 { |
| 170 | None = 0x00, | 171 | None = 0x00, |
| 171 | Mask = 0x7F, | 172 | All = 0xFF, |
| 172 | All = Mask, | 173 | UserMask = All, |
| 173 | DontCareMask = 0x80, | ||
| 174 | 174 | ||
| 175 | Locked = static_cast<u8>(Svc::MemoryAttribute::Locked), | 175 | Locked = static_cast<u8>(Svc::MemoryAttribute::Locked), |
| 176 | IpcLocked = static_cast<u8>(Svc::MemoryAttribute::IpcLocked), | 176 | IpcLocked = static_cast<u8>(Svc::MemoryAttribute::IpcLocked), |
| @@ -178,76 +178,112 @@ enum class KMemoryAttribute : u8 { | |||
| 178 | Uncached = static_cast<u8>(Svc::MemoryAttribute::Uncached), | 178 | Uncached = static_cast<u8>(Svc::MemoryAttribute::Uncached), |
| 179 | 179 | ||
| 180 | SetMask = Uncached, | 180 | SetMask = Uncached, |
| 181 | |||
| 182 | IpcAndDeviceMapped = IpcLocked | DeviceShared, | ||
| 183 | LockedAndIpcLocked = Locked | IpcLocked, | ||
| 184 | DeviceSharedAndUncached = DeviceShared | Uncached | ||
| 185 | }; | 181 | }; |
| 186 | DECLARE_ENUM_FLAG_OPERATORS(KMemoryAttribute); | 182 | DECLARE_ENUM_FLAG_OPERATORS(KMemoryAttribute); |
| 187 | 183 | ||
| 188 | static_assert((static_cast<u8>(KMemoryAttribute::Mask) & | 184 | enum class KMemoryBlockDisableMergeAttribute : u8 { |
| 189 | static_cast<u8>(KMemoryAttribute::DontCareMask)) == 0); | 185 | None = 0, |
| 186 | Normal = (1u << 0), | ||
| 187 | DeviceLeft = (1u << 1), | ||
| 188 | IpcLeft = (1u << 2), | ||
| 189 | Locked = (1u << 3), | ||
| 190 | DeviceRight = (1u << 4), | ||
| 191 | |||
| 192 | AllLeft = Normal | DeviceLeft | IpcLeft | Locked, | ||
| 193 | AllRight = DeviceRight, | ||
| 194 | }; | ||
| 195 | DECLARE_ENUM_FLAG_OPERATORS(KMemoryBlockDisableMergeAttribute); | ||
| 190 | 196 | ||
| 191 | struct KMemoryInfo { | 197 | struct KMemoryInfo { |
| 192 | VAddr addr{}; | 198 | uintptr_t m_address; |
| 193 | std::size_t size{}; | 199 | size_t m_size; |
| 194 | KMemoryState state{}; | 200 | KMemoryState m_state; |
| 195 | KMemoryPermission perm{}; | 201 | u16 m_device_disable_merge_left_count; |
| 196 | KMemoryAttribute attribute{}; | 202 | u16 m_device_disable_merge_right_count; |
| 197 | KMemoryPermission original_perm{}; | 203 | u16 m_ipc_lock_count; |
| 198 | u16 ipc_lock_count{}; | 204 | u16 m_device_use_count; |
| 199 | u16 device_use_count{}; | 205 | u16 m_ipc_disable_merge_count; |
| 206 | KMemoryPermission m_permission; | ||
| 207 | KMemoryAttribute m_attribute; | ||
| 208 | KMemoryPermission m_original_permission; | ||
| 209 | KMemoryBlockDisableMergeAttribute m_disable_merge_attribute; | ||
| 200 | 210 | ||
| 201 | constexpr Svc::MemoryInfo GetSvcMemoryInfo() const { | 211 | constexpr Svc::MemoryInfo GetSvcMemoryInfo() const { |
| 202 | return { | 212 | return { |
| 203 | addr, | 213 | .addr = m_address, |
| 204 | size, | 214 | .size = m_size, |
| 205 | static_cast<Svc::MemoryState>(state & KMemoryState::Mask), | 215 | .state = static_cast<Svc::MemoryState>(m_state & KMemoryState::Mask), |
| 206 | static_cast<Svc::MemoryAttribute>(attribute & KMemoryAttribute::Mask), | 216 | .attr = static_cast<Svc::MemoryAttribute>(m_attribute & KMemoryAttribute::UserMask), |
| 207 | static_cast<Svc::MemoryPermission>(perm & KMemoryPermission::UserMask), | 217 | .perm = static_cast<Svc::MemoryPermission>(m_permission & KMemoryPermission::UserMask), |
| 208 | ipc_lock_count, | 218 | .ipc_refcount = m_ipc_lock_count, |
| 209 | device_use_count, | 219 | .device_refcount = m_device_use_count, |
| 220 | .padding = {}, | ||
| 210 | }; | 221 | }; |
| 211 | } | 222 | } |
| 212 | 223 | ||
| 213 | constexpr VAddr GetAddress() const { | 224 | constexpr uintptr_t GetAddress() const { |
| 214 | return addr; | 225 | return m_address; |
| 226 | } | ||
| 227 | |||
| 228 | constexpr size_t GetSize() const { | ||
| 229 | return m_size; | ||
| 215 | } | 230 | } |
| 216 | constexpr std::size_t GetSize() const { | 231 | |
| 217 | return size; | 232 | constexpr size_t GetNumPages() const { |
| 233 | return this->GetSize() / PageSize; | ||
| 218 | } | 234 | } |
| 219 | constexpr std::size_t GetNumPages() const { | 235 | |
| 220 | return GetSize() / PageSize; | 236 | constexpr uintptr_t GetEndAddress() const { |
| 237 | return this->GetAddress() + this->GetSize(); | ||
| 221 | } | 238 | } |
| 222 | constexpr VAddr GetEndAddress() const { | 239 | |
| 223 | return GetAddress() + GetSize(); | 240 | constexpr uintptr_t GetLastAddress() const { |
| 241 | return this->GetEndAddress() - 1; | ||
| 224 | } | 242 | } |
| 225 | constexpr VAddr GetLastAddress() const { | 243 | |
| 226 | return GetEndAddress() - 1; | 244 | constexpr u16 GetIpcLockCount() const { |
| 245 | return m_ipc_lock_count; | ||
| 227 | } | 246 | } |
| 247 | |||
| 248 | constexpr u16 GetIpcDisableMergeCount() const { | ||
| 249 | return m_ipc_disable_merge_count; | ||
| 250 | } | ||
| 251 | |||
| 228 | constexpr KMemoryState GetState() const { | 252 | constexpr KMemoryState GetState() const { |
| 229 | return state; | 253 | return m_state; |
| 254 | } | ||
| 255 | |||
| 256 | constexpr KMemoryPermission GetPermission() const { | ||
| 257 | return m_permission; | ||
| 230 | } | 258 | } |
| 259 | |||
| 260 | constexpr KMemoryPermission GetOriginalPermission() const { | ||
| 261 | return m_original_permission; | ||
| 262 | } | ||
| 263 | |||
| 231 | constexpr KMemoryAttribute GetAttribute() const { | 264 | constexpr KMemoryAttribute GetAttribute() const { |
| 232 | return attribute; | 265 | return m_attribute; |
| 233 | } | 266 | } |
| 234 | constexpr KMemoryPermission GetPermission() const { | 267 | |
| 235 | return perm; | 268 | constexpr KMemoryBlockDisableMergeAttribute GetDisableMergeAttribute() const { |
| 269 | return m_disable_merge_attribute; | ||
| 236 | } | 270 | } |
| 237 | }; | 271 | }; |
| 238 | 272 | ||
| 239 | class KMemoryBlock final { | 273 | class KMemoryBlock : public Common::IntrusiveRedBlackTreeBaseNode<KMemoryBlock> { |
| 240 | friend class KMemoryBlockManager; | ||
| 241 | |||
| 242 | private: | 274 | private: |
| 243 | VAddr addr{}; | 275 | u16 m_device_disable_merge_left_count; |
| 244 | std::size_t num_pages{}; | 276 | u16 m_device_disable_merge_right_count; |
| 245 | KMemoryState state{KMemoryState::None}; | 277 | VAddr m_address; |
| 246 | u16 ipc_lock_count{}; | 278 | size_t m_num_pages; |
| 247 | u16 device_use_count{}; | 279 | KMemoryState m_memory_state; |
| 248 | KMemoryPermission perm{KMemoryPermission::None}; | 280 | u16 m_ipc_lock_count; |
| 249 | KMemoryPermission original_perm{KMemoryPermission::None}; | 281 | u16 m_device_use_count; |
| 250 | KMemoryAttribute attribute{KMemoryAttribute::None}; | 282 | u16 m_ipc_disable_merge_count; |
| 283 | KMemoryPermission m_permission; | ||
| 284 | KMemoryPermission m_original_permission; | ||
| 285 | KMemoryAttribute m_attribute; | ||
| 286 | KMemoryBlockDisableMergeAttribute m_disable_merge_attribute; | ||
| 251 | 287 | ||
| 252 | public: | 288 | public: |
| 253 | static constexpr int Compare(const KMemoryBlock& lhs, const KMemoryBlock& rhs) { | 289 | static constexpr int Compare(const KMemoryBlock& lhs, const KMemoryBlock& rhs) { |
| @@ -261,113 +297,349 @@ public: | |||
| 261 | } | 297 | } |
| 262 | 298 | ||
| 263 | public: | 299 | public: |
| 264 | constexpr KMemoryBlock() = default; | ||
| 265 | constexpr KMemoryBlock(VAddr addr_, std::size_t num_pages_, KMemoryState state_, | ||
| 266 | KMemoryPermission perm_, KMemoryAttribute attribute_) | ||
| 267 | : addr{addr_}, num_pages(num_pages_), state{state_}, perm{perm_}, attribute{attribute_} {} | ||
| 268 | |||
| 269 | constexpr VAddr GetAddress() const { | 300 | constexpr VAddr GetAddress() const { |
| 270 | return addr; | 301 | return m_address; |
| 271 | } | 302 | } |
| 272 | 303 | ||
| 273 | constexpr std::size_t GetNumPages() const { | 304 | constexpr size_t GetNumPages() const { |
| 274 | return num_pages; | 305 | return m_num_pages; |
| 275 | } | 306 | } |
| 276 | 307 | ||
| 277 | constexpr std::size_t GetSize() const { | 308 | constexpr size_t GetSize() const { |
| 278 | return GetNumPages() * PageSize; | 309 | return this->GetNumPages() * PageSize; |
| 279 | } | 310 | } |
| 280 | 311 | ||
| 281 | constexpr VAddr GetEndAddress() const { | 312 | constexpr VAddr GetEndAddress() const { |
| 282 | return GetAddress() + GetSize(); | 313 | return this->GetAddress() + this->GetSize(); |
| 283 | } | 314 | } |
| 284 | 315 | ||
| 285 | constexpr VAddr GetLastAddress() const { | 316 | constexpr VAddr GetLastAddress() const { |
| 286 | return GetEndAddress() - 1; | 317 | return this->GetEndAddress() - 1; |
| 318 | } | ||
| 319 | |||
| 320 | constexpr u16 GetIpcLockCount() const { | ||
| 321 | return m_ipc_lock_count; | ||
| 322 | } | ||
| 323 | |||
| 324 | constexpr u16 GetIpcDisableMergeCount() const { | ||
| 325 | return m_ipc_disable_merge_count; | ||
| 326 | } | ||
| 327 | |||
| 328 | constexpr KMemoryPermission GetPermission() const { | ||
| 329 | return m_permission; | ||
| 330 | } | ||
| 331 | |||
| 332 | constexpr KMemoryPermission GetOriginalPermission() const { | ||
| 333 | return m_original_permission; | ||
| 334 | } | ||
| 335 | |||
| 336 | constexpr KMemoryAttribute GetAttribute() const { | ||
| 337 | return m_attribute; | ||
| 287 | } | 338 | } |
| 288 | 339 | ||
| 289 | constexpr KMemoryInfo GetMemoryInfo() const { | 340 | constexpr KMemoryInfo GetMemoryInfo() const { |
| 290 | return { | 341 | return { |
| 291 | GetAddress(), GetSize(), state, perm, | 342 | .m_address = this->GetAddress(), |
| 292 | attribute, original_perm, ipc_lock_count, device_use_count, | 343 | .m_size = this->GetSize(), |
| 344 | .m_state = m_memory_state, | ||
| 345 | .m_device_disable_merge_left_count = m_device_disable_merge_left_count, | ||
| 346 | .m_device_disable_merge_right_count = m_device_disable_merge_right_count, | ||
| 347 | .m_ipc_lock_count = m_ipc_lock_count, | ||
| 348 | .m_device_use_count = m_device_use_count, | ||
| 349 | .m_ipc_disable_merge_count = m_ipc_disable_merge_count, | ||
| 350 | .m_permission = m_permission, | ||
| 351 | .m_attribute = m_attribute, | ||
| 352 | .m_original_permission = m_original_permission, | ||
| 353 | .m_disable_merge_attribute = m_disable_merge_attribute, | ||
| 293 | }; | 354 | }; |
| 294 | } | 355 | } |
| 295 | 356 | ||
| 296 | void ShareToDevice(KMemoryPermission /*new_perm*/) { | 357 | public: |
| 297 | ASSERT((attribute & KMemoryAttribute::DeviceShared) == KMemoryAttribute::DeviceShared || | 358 | explicit KMemoryBlock() = default; |
| 298 | device_use_count == 0); | 359 | |
| 299 | attribute |= KMemoryAttribute::DeviceShared; | 360 | constexpr KMemoryBlock(VAddr addr, size_t np, KMemoryState ms, KMemoryPermission p, |
| 300 | const u16 new_use_count{++device_use_count}; | 361 | KMemoryAttribute attr) |
| 301 | ASSERT(new_use_count > 0); | 362 | : Common::IntrusiveRedBlackTreeBaseNode<KMemoryBlock>(), |
| 363 | m_device_disable_merge_left_count(), m_device_disable_merge_right_count(), | ||
| 364 | m_address(addr), m_num_pages(np), m_memory_state(ms), m_ipc_lock_count(0), | ||
| 365 | m_device_use_count(0), m_ipc_disable_merge_count(), m_permission(p), | ||
| 366 | m_original_permission(KMemoryPermission::None), m_attribute(attr), | ||
| 367 | m_disable_merge_attribute() {} | ||
| 368 | |||
| 369 | constexpr void Initialize(VAddr addr, size_t np, KMemoryState ms, KMemoryPermission p, | ||
| 370 | KMemoryAttribute attr) { | ||
| 371 | m_device_disable_merge_left_count = 0; | ||
| 372 | m_device_disable_merge_right_count = 0; | ||
| 373 | m_address = addr; | ||
| 374 | m_num_pages = np; | ||
| 375 | m_memory_state = ms; | ||
| 376 | m_ipc_lock_count = 0; | ||
| 377 | m_device_use_count = 0; | ||
| 378 | m_permission = p; | ||
| 379 | m_original_permission = KMemoryPermission::None; | ||
| 380 | m_attribute = attr; | ||
| 381 | m_disable_merge_attribute = KMemoryBlockDisableMergeAttribute::None; | ||
| 382 | } | ||
| 383 | |||
| 384 | constexpr bool HasProperties(KMemoryState s, KMemoryPermission p, KMemoryAttribute a) const { | ||
| 385 | constexpr auto AttributeIgnoreMask = | ||
| 386 | KMemoryAttribute::IpcLocked | KMemoryAttribute::DeviceShared; | ||
| 387 | return m_memory_state == s && m_permission == p && | ||
| 388 | (m_attribute | AttributeIgnoreMask) == (a | AttributeIgnoreMask); | ||
| 389 | } | ||
| 390 | |||
| 391 | constexpr bool HasSameProperties(const KMemoryBlock& rhs) const { | ||
| 392 | return m_memory_state == rhs.m_memory_state && m_permission == rhs.m_permission && | ||
| 393 | m_original_permission == rhs.m_original_permission && | ||
| 394 | m_attribute == rhs.m_attribute && m_ipc_lock_count == rhs.m_ipc_lock_count && | ||
| 395 | m_device_use_count == rhs.m_device_use_count; | ||
| 396 | } | ||
| 397 | |||
| 398 | constexpr bool CanMergeWith(const KMemoryBlock& rhs) const { | ||
| 399 | return this->HasSameProperties(rhs) && | ||
| 400 | (m_disable_merge_attribute & KMemoryBlockDisableMergeAttribute::AllRight) == | ||
| 401 | KMemoryBlockDisableMergeAttribute::None && | ||
| 402 | (rhs.m_disable_merge_attribute & KMemoryBlockDisableMergeAttribute::AllLeft) == | ||
| 403 | KMemoryBlockDisableMergeAttribute::None; | ||
| 302 | } | 404 | } |
| 303 | 405 | ||
| 304 | void UnshareToDevice(KMemoryPermission /*new_perm*/) { | 406 | constexpr bool Contains(VAddr addr) const { |
| 305 | ASSERT((attribute & KMemoryAttribute::DeviceShared) == KMemoryAttribute::DeviceShared); | 407 | return this->GetAddress() <= addr && addr <= this->GetEndAddress(); |
| 306 | const u16 prev_use_count{device_use_count--}; | 408 | } |
| 307 | ASSERT(prev_use_count > 0); | 409 | |
| 308 | if (prev_use_count == 1) { | 410 | constexpr void Add(const KMemoryBlock& added_block) { |
| 309 | attribute &= ~KMemoryAttribute::DeviceShared; | 411 | ASSERT(added_block.GetNumPages() > 0); |
| 412 | ASSERT(this->GetAddress() + added_block.GetSize() - 1 < | ||
| 413 | this->GetEndAddress() + added_block.GetSize() - 1); | ||
| 414 | |||
| 415 | m_num_pages += added_block.GetNumPages(); | ||
| 416 | m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>( | ||
| 417 | m_disable_merge_attribute | added_block.m_disable_merge_attribute); | ||
| 418 | m_device_disable_merge_right_count = added_block.m_device_disable_merge_right_count; | ||
| 419 | } | ||
| 420 | |||
| 421 | constexpr void Update(KMemoryState s, KMemoryPermission p, KMemoryAttribute a, | ||
| 422 | bool set_disable_merge_attr, u8 set_mask, u8 clear_mask) { | ||
| 423 | ASSERT(m_original_permission == KMemoryPermission::None); | ||
| 424 | ASSERT((m_attribute & KMemoryAttribute::IpcLocked) == KMemoryAttribute::None); | ||
| 425 | |||
| 426 | m_memory_state = s; | ||
| 427 | m_permission = p; | ||
| 428 | m_attribute = static_cast<KMemoryAttribute>( | ||
| 429 | a | (m_attribute & (KMemoryAttribute::IpcLocked | KMemoryAttribute::DeviceShared))); | ||
| 430 | |||
| 431 | if (set_disable_merge_attr && set_mask != 0) { | ||
| 432 | m_disable_merge_attribute = m_disable_merge_attribute | | ||
| 433 | static_cast<KMemoryBlockDisableMergeAttribute>(set_mask); | ||
| 434 | } | ||
| 435 | if (clear_mask != 0) { | ||
| 436 | m_disable_merge_attribute = m_disable_merge_attribute & | ||
| 437 | static_cast<KMemoryBlockDisableMergeAttribute>(~clear_mask); | ||
| 310 | } | 438 | } |
| 311 | } | 439 | } |
| 312 | 440 | ||
| 313 | private: | 441 | constexpr void Split(KMemoryBlock* block, VAddr addr) { |
| 314 | constexpr bool HasProperties(KMemoryState s, KMemoryPermission p, KMemoryAttribute a) const { | 442 | ASSERT(this->GetAddress() < addr); |
| 315 | constexpr KMemoryAttribute AttributeIgnoreMask{KMemoryAttribute::DontCareMask | | 443 | ASSERT(this->Contains(addr)); |
| 316 | KMemoryAttribute::IpcLocked | | 444 | ASSERT(Common::IsAligned(addr, PageSize)); |
| 317 | KMemoryAttribute::DeviceShared}; | 445 | |
| 318 | return state == s && perm == p && | 446 | block->m_address = m_address; |
| 319 | (attribute | AttributeIgnoreMask) == (a | AttributeIgnoreMask); | 447 | block->m_num_pages = (addr - this->GetAddress()) / PageSize; |
| 448 | block->m_memory_state = m_memory_state; | ||
| 449 | block->m_ipc_lock_count = m_ipc_lock_count; | ||
| 450 | block->m_device_use_count = m_device_use_count; | ||
| 451 | block->m_permission = m_permission; | ||
| 452 | block->m_original_permission = m_original_permission; | ||
| 453 | block->m_attribute = m_attribute; | ||
| 454 | block->m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>( | ||
| 455 | m_disable_merge_attribute & KMemoryBlockDisableMergeAttribute::AllLeft); | ||
| 456 | block->m_ipc_disable_merge_count = m_ipc_disable_merge_count; | ||
| 457 | block->m_device_disable_merge_left_count = m_device_disable_merge_left_count; | ||
| 458 | block->m_device_disable_merge_right_count = 0; | ||
| 459 | |||
| 460 | m_address = addr; | ||
| 461 | m_num_pages -= block->m_num_pages; | ||
| 462 | |||
| 463 | m_ipc_disable_merge_count = 0; | ||
| 464 | m_device_disable_merge_left_count = 0; | ||
| 465 | m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>( | ||
| 466 | m_disable_merge_attribute & KMemoryBlockDisableMergeAttribute::AllRight); | ||
| 320 | } | 467 | } |
| 321 | 468 | ||
| 322 | constexpr bool HasSameProperties(const KMemoryBlock& rhs) const { | 469 | constexpr void UpdateDeviceDisableMergeStateForShareLeft( |
| 323 | return state == rhs.state && perm == rhs.perm && original_perm == rhs.original_perm && | 470 | [[maybe_unused]] KMemoryPermission new_perm, bool left, [[maybe_unused]] bool right) { |
| 324 | attribute == rhs.attribute && ipc_lock_count == rhs.ipc_lock_count && | 471 | if (left) { |
| 325 | device_use_count == rhs.device_use_count; | 472 | m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>( |
| 473 | m_disable_merge_attribute | KMemoryBlockDisableMergeAttribute::DeviceLeft); | ||
| 474 | const u16 new_device_disable_merge_left_count = ++m_device_disable_merge_left_count; | ||
| 475 | ASSERT(new_device_disable_merge_left_count > 0); | ||
| 476 | } | ||
| 326 | } | 477 | } |
| 327 | 478 | ||
| 328 | constexpr bool Contains(VAddr start) const { | 479 | constexpr void UpdateDeviceDisableMergeStateForShareRight( |
| 329 | return GetAddress() <= start && start <= GetEndAddress(); | 480 | [[maybe_unused]] KMemoryPermission new_perm, [[maybe_unused]] bool left, bool right) { |
| 481 | if (right) { | ||
| 482 | m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>( | ||
| 483 | m_disable_merge_attribute | KMemoryBlockDisableMergeAttribute::DeviceRight); | ||
| 484 | const u16 new_device_disable_merge_right_count = ++m_device_disable_merge_right_count; | ||
| 485 | ASSERT(new_device_disable_merge_right_count > 0); | ||
| 486 | } | ||
| 487 | } | ||
| 488 | |||
| 489 | constexpr void UpdateDeviceDisableMergeStateForShare(KMemoryPermission new_perm, bool left, | ||
| 490 | bool right) { | ||
| 491 | this->UpdateDeviceDisableMergeStateForShareLeft(new_perm, left, right); | ||
| 492 | this->UpdateDeviceDisableMergeStateForShareRight(new_perm, left, right); | ||
| 330 | } | 493 | } |
| 331 | 494 | ||
| 332 | constexpr void Add(std::size_t count) { | 495 | constexpr void ShareToDevice([[maybe_unused]] KMemoryPermission new_perm, bool left, |
| 333 | ASSERT(count > 0); | 496 | bool right) { |
| 334 | ASSERT(GetAddress() + count * PageSize - 1 < GetEndAddress() + count * PageSize - 1); | 497 | // We must either be shared or have a zero lock count. |
| 498 | ASSERT((m_attribute & KMemoryAttribute::DeviceShared) == KMemoryAttribute::DeviceShared || | ||
| 499 | m_device_use_count == 0); | ||
| 335 | 500 | ||
| 336 | num_pages += count; | 501 | // Share. |
| 502 | const u16 new_count = ++m_device_use_count; | ||
| 503 | ASSERT(new_count > 0); | ||
| 504 | |||
| 505 | m_attribute = static_cast<KMemoryAttribute>(m_attribute | KMemoryAttribute::DeviceShared); | ||
| 506 | |||
| 507 | this->UpdateDeviceDisableMergeStateForShare(new_perm, left, right); | ||
| 337 | } | 508 | } |
| 338 | 509 | ||
| 339 | constexpr void Update(KMemoryState new_state, KMemoryPermission new_perm, | 510 | constexpr void UpdateDeviceDisableMergeStateForUnshareLeft( |
| 340 | KMemoryAttribute new_attribute) { | 511 | [[maybe_unused]] KMemoryPermission new_perm, bool left, [[maybe_unused]] bool right) { |
| 341 | ASSERT(original_perm == KMemoryPermission::None); | ||
| 342 | ASSERT((attribute & KMemoryAttribute::IpcLocked) == KMemoryAttribute::None); | ||
| 343 | 512 | ||
| 344 | state = new_state; | 513 | if (left) { |
| 345 | perm = new_perm; | 514 | if (!m_device_disable_merge_left_count) { |
| 515 | return; | ||
| 516 | } | ||
| 517 | --m_device_disable_merge_left_count; | ||
| 518 | } | ||
| 346 | 519 | ||
| 347 | attribute = static_cast<KMemoryAttribute>( | 520 | m_device_disable_merge_left_count = |
| 348 | new_attribute | | 521 | std::min(m_device_disable_merge_left_count, m_device_use_count); |
| 349 | (attribute & (KMemoryAttribute::IpcLocked | KMemoryAttribute::DeviceShared))); | 522 | |
| 523 | if (m_device_disable_merge_left_count == 0) { | ||
| 524 | m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>( | ||
| 525 | m_disable_merge_attribute & ~KMemoryBlockDisableMergeAttribute::DeviceLeft); | ||
| 526 | } | ||
| 350 | } | 527 | } |
| 351 | 528 | ||
| 352 | constexpr KMemoryBlock Split(VAddr split_addr) { | 529 | constexpr void UpdateDeviceDisableMergeStateForUnshareRight( |
| 353 | ASSERT(GetAddress() < split_addr); | 530 | [[maybe_unused]] KMemoryPermission new_perm, [[maybe_unused]] bool left, bool right) { |
| 354 | ASSERT(Contains(split_addr)); | 531 | if (right) { |
| 355 | ASSERT(Common::IsAligned(split_addr, PageSize)); | 532 | const u16 old_device_disable_merge_right_count = m_device_disable_merge_right_count--; |
| 533 | ASSERT(old_device_disable_merge_right_count > 0); | ||
| 534 | if (old_device_disable_merge_right_count == 1) { | ||
| 535 | m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>( | ||
| 536 | m_disable_merge_attribute & ~KMemoryBlockDisableMergeAttribute::DeviceRight); | ||
| 537 | } | ||
| 538 | } | ||
| 539 | } | ||
| 356 | 540 | ||
| 357 | KMemoryBlock block; | 541 | constexpr void UpdateDeviceDisableMergeStateForUnshare(KMemoryPermission new_perm, bool left, |
| 358 | block.addr = addr; | 542 | bool right) { |
| 359 | block.num_pages = (split_addr - GetAddress()) / PageSize; | 543 | this->UpdateDeviceDisableMergeStateForUnshareLeft(new_perm, left, right); |
| 360 | block.state = state; | 544 | this->UpdateDeviceDisableMergeStateForUnshareRight(new_perm, left, right); |
| 361 | block.ipc_lock_count = ipc_lock_count; | 545 | } |
| 362 | block.device_use_count = device_use_count; | ||
| 363 | block.perm = perm; | ||
| 364 | block.original_perm = original_perm; | ||
| 365 | block.attribute = attribute; | ||
| 366 | 546 | ||
| 367 | addr = split_addr; | 547 | constexpr void UnshareToDevice([[maybe_unused]] KMemoryPermission new_perm, bool left, |
| 368 | num_pages -= block.num_pages; | 548 | bool right) { |
| 549 | // We must be shared. | ||
| 550 | ASSERT((m_attribute & KMemoryAttribute::DeviceShared) == KMemoryAttribute::DeviceShared); | ||
| 551 | |||
| 552 | // Unhare. | ||
| 553 | const u16 old_count = m_device_use_count--; | ||
| 554 | ASSERT(old_count > 0); | ||
| 555 | |||
| 556 | if (old_count == 1) { | ||
| 557 | m_attribute = | ||
| 558 | static_cast<KMemoryAttribute>(m_attribute & ~KMemoryAttribute::DeviceShared); | ||
| 559 | } | ||
| 560 | |||
| 561 | this->UpdateDeviceDisableMergeStateForUnshare(new_perm, left, right); | ||
| 562 | } | ||
| 563 | |||
| 564 | constexpr void UnshareToDeviceRight([[maybe_unused]] KMemoryPermission new_perm, bool left, | ||
| 565 | bool right) { | ||
| 566 | |||
| 567 | // We must be shared. | ||
| 568 | ASSERT((m_attribute & KMemoryAttribute::DeviceShared) == KMemoryAttribute::DeviceShared); | ||
| 569 | |||
| 570 | // Unhare. | ||
| 571 | const u16 old_count = m_device_use_count--; | ||
| 572 | ASSERT(old_count > 0); | ||
| 573 | |||
| 574 | if (old_count == 1) { | ||
| 575 | m_attribute = | ||
| 576 | static_cast<KMemoryAttribute>(m_attribute & ~KMemoryAttribute::DeviceShared); | ||
| 577 | } | ||
| 578 | |||
| 579 | this->UpdateDeviceDisableMergeStateForUnshareRight(new_perm, left, right); | ||
| 580 | } | ||
| 581 | |||
| 582 | constexpr void LockForIpc(KMemoryPermission new_perm, bool left, [[maybe_unused]] bool right) { | ||
| 583 | // We must either be locked or have a zero lock count. | ||
| 584 | ASSERT((m_attribute & KMemoryAttribute::IpcLocked) == KMemoryAttribute::IpcLocked || | ||
| 585 | m_ipc_lock_count == 0); | ||
| 586 | |||
| 587 | // Lock. | ||
| 588 | const u16 new_lock_count = ++m_ipc_lock_count; | ||
| 589 | ASSERT(new_lock_count > 0); | ||
| 590 | |||
| 591 | // If this is our first lock, update our permissions. | ||
| 592 | if (new_lock_count == 1) { | ||
| 593 | ASSERT(m_original_permission == KMemoryPermission::None); | ||
| 594 | ASSERT((m_permission | new_perm | KMemoryPermission::NotMapped) == | ||
| 595 | (m_permission | KMemoryPermission::NotMapped)); | ||
| 596 | ASSERT((m_permission & KMemoryPermission::UserExecute) != | ||
| 597 | KMemoryPermission::UserExecute || | ||
| 598 | (new_perm == KMemoryPermission::UserRead)); | ||
| 599 | m_original_permission = m_permission; | ||
| 600 | m_permission = static_cast<KMemoryPermission>( | ||
| 601 | (new_perm & KMemoryPermission::IpcLockChangeMask) | | ||
| 602 | (m_original_permission & ~KMemoryPermission::IpcLockChangeMask)); | ||
| 603 | } | ||
| 604 | m_attribute = static_cast<KMemoryAttribute>(m_attribute | KMemoryAttribute::IpcLocked); | ||
| 605 | |||
| 606 | if (left) { | ||
| 607 | m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>( | ||
| 608 | m_disable_merge_attribute | KMemoryBlockDisableMergeAttribute::IpcLeft); | ||
| 609 | const u16 new_ipc_disable_merge_count = ++m_ipc_disable_merge_count; | ||
| 610 | ASSERT(new_ipc_disable_merge_count > 0); | ||
| 611 | } | ||
| 612 | } | ||
| 613 | |||
| 614 | constexpr void UnlockForIpc([[maybe_unused]] KMemoryPermission new_perm, bool left, | ||
| 615 | [[maybe_unused]] bool right) { | ||
| 616 | // We must be locked. | ||
| 617 | ASSERT((m_attribute & KMemoryAttribute::IpcLocked) == KMemoryAttribute::IpcLocked); | ||
| 618 | |||
| 619 | // Unlock. | ||
| 620 | const u16 old_lock_count = m_ipc_lock_count--; | ||
| 621 | ASSERT(old_lock_count > 0); | ||
| 622 | |||
| 623 | // If this is our last unlock, update our permissions. | ||
| 624 | if (old_lock_count == 1) { | ||
| 625 | ASSERT(m_original_permission != KMemoryPermission::None); | ||
| 626 | m_permission = m_original_permission; | ||
| 627 | m_original_permission = KMemoryPermission::None; | ||
| 628 | m_attribute = static_cast<KMemoryAttribute>(m_attribute & ~KMemoryAttribute::IpcLocked); | ||
| 629 | } | ||
| 630 | |||
| 631 | if (left) { | ||
| 632 | const u16 old_ipc_disable_merge_count = m_ipc_disable_merge_count--; | ||
| 633 | ASSERT(old_ipc_disable_merge_count > 0); | ||
| 634 | if (old_ipc_disable_merge_count == 1) { | ||
| 635 | m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>( | ||
| 636 | m_disable_merge_attribute & ~KMemoryBlockDisableMergeAttribute::IpcLeft); | ||
| 637 | } | ||
| 638 | } | ||
| 639 | } | ||
| 369 | 640 | ||
| 370 | return block; | 641 | constexpr KMemoryBlockDisableMergeAttribute GetDisableMergeAttribute() const { |
| 642 | return m_disable_merge_attribute; | ||
| 371 | } | 643 | } |
| 372 | }; | 644 | }; |
| 373 | static_assert(std::is_trivially_destructible<KMemoryBlock>::value); | 645 | static_assert(std::is_trivially_destructible<KMemoryBlock>::value); |
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index becd6d1b9..652441bc2 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp | |||
| @@ -290,7 +290,7 @@ public: | |||
| 290 | const std::size_t padding_size{page_table.GetNumGuardPages() * Kernel::PageSize}; | 290 | const std::size_t padding_size{page_table.GetNumGuardPages() * Kernel::PageSize}; |
| 291 | const auto start_info{page_table.QueryInfo(start - 1)}; | 291 | const auto start_info{page_table.QueryInfo(start - 1)}; |
| 292 | 292 | ||
| 293 | if (start_info.state != Kernel::KMemoryState::Free) { | 293 | if (start_info.GetState() != Kernel::KMemoryState::Free) { |
| 294 | return {}; | 294 | return {}; |
| 295 | } | 295 | } |
| 296 | 296 | ||
| @@ -300,7 +300,7 @@ public: | |||
| 300 | 300 | ||
| 301 | const auto end_info{page_table.QueryInfo(start + size)}; | 301 | const auto end_info{page_table.QueryInfo(start + size)}; |
| 302 | 302 | ||
| 303 | if (end_info.state != Kernel::KMemoryState::Free) { | 303 | if (end_info.GetState() != Kernel::KMemoryState::Free) { |
| 304 | return {}; | 304 | return {}; |
| 305 | } | 305 | } |
| 306 | 306 | ||