Compare commits
1 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
689f346e97 |
@@ -3,4 +3,4 @@
|
||||
|
||||
[codespell]
|
||||
skip = ./.git,./build,./dist,./Doxyfile,./externals,./LICENSES,./src/android/app/src/main/res
|
||||
ignore-words-list = aci,allright,ba,canonicalizations,deques,froms,hda,inout,lod,masia,nam,nax,nd,optin,pullrequests,pullrequest,te,transfered,unstall,uscaled,vas,zink
|
||||
ignore-words-list = aci,allright,ba,canonicalizations,deques,froms,hda,inout,lod,masia,nam,nax,nd,optin,pullrequests,pullrequest,te,transfered,unstall,uscaled,zink
|
||||
|
||||
2
externals/CMakeLists.txt
vendored
2
externals/CMakeLists.txt
vendored
@@ -168,7 +168,7 @@ if (NOT TARGET LLVM::Demangle)
|
||||
add_library(LLVM::Demangle ALIAS demangle)
|
||||
endif()
|
||||
|
||||
add_library(stb stb/stb_dxt.cpp stb/stb_image.cpp stb/stb_image_resize.cpp stb/stb_image_write.cpp)
|
||||
add_library(stb stb/stb_dxt.cpp stb/stb_image.cpp stb/stb_image_resize.cpp)
|
||||
target_include_directories(stb PUBLIC ./stb)
|
||||
|
||||
add_library(bc_decoder bc_decoder/bc_decoder.cpp)
|
||||
|
||||
1677
externals/stb/stb_image_write.cpp
vendored
1677
externals/stb/stb_image_write.cpp
vendored
File diff suppressed because it is too large
Load Diff
297
externals/stb/stb_image_write.h
vendored
297
externals/stb/stb_image_write.h
vendored
@@ -1,297 +0,0 @@
|
||||
// SPDX-FileCopyrightText: stb http://nothings.org/stb
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/* stb_image_write - v1.16 - public domain - http://nothings.org/stb
|
||||
writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015
|
||||
no warranty implied; use at your own risk
|
||||
|
||||
Before #including,
|
||||
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
|
||||
in the file that you want to have the implementation.
|
||||
|
||||
Will probably not work correctly with strict-aliasing optimizations.
|
||||
|
||||
ABOUT:
|
||||
|
||||
This header file is a library for writing images to C stdio or a callback.
|
||||
|
||||
The PNG output is not optimal; it is 20-50% larger than the file
|
||||
written by a decent optimizing implementation; though providing a custom
|
||||
zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that.
|
||||
This library is designed for source code compactness and simplicity,
|
||||
not optimal image file size or run-time performance.
|
||||
|
||||
BUILDING:
|
||||
|
||||
You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h.
|
||||
You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace
|
||||
malloc,realloc,free.
|
||||
You can #define STBIW_MEMMOVE() to replace memmove()
|
||||
You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function
|
||||
for PNG compression (instead of the builtin one), it must have the following signature:
|
||||
unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality);
|
||||
The returned data will be freed with STBIW_FREE() (free() by default),
|
||||
so it must be heap allocated with STBIW_MALLOC() (malloc() by default),
|
||||
|
||||
UNICODE:
|
||||
|
||||
If compiling for Windows and you wish to use Unicode filenames, compile
|
||||
with
|
||||
#define STBIW_WINDOWS_UTF8
|
||||
and pass utf8-encoded filenames. Call stbiw_convert_wchar_to_utf8 to convert
|
||||
Windows wchar_t filenames to utf8.
|
||||
|
||||
USAGE:
|
||||
|
||||
There are five functions, one for each image file format:
|
||||
|
||||
int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
|
||||
int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
|
||||
int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
|
||||
int stbi_write_jpg(char const *filename, int w, int h, int comp, const void *data, int quality);
|
||||
int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
|
||||
|
||||
void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically
|
||||
|
||||
There are also five equivalent functions that use an arbitrary write function. You are
|
||||
expected to open/close your file-equivalent before and after calling these:
|
||||
|
||||
int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes);
|
||||
int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
|
||||
int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
|
||||
int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
|
||||
int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);
|
||||
|
||||
where the callback is:
|
||||
void stbi_write_func(void *context, void *data, int size);
|
||||
|
||||
You can configure it with these global variables:
|
||||
int stbi_write_tga_with_rle; // defaults to true; set to 0 to disable RLE
|
||||
int stbi_write_png_compression_level; // defaults to 8; set to higher for more compression
|
||||
int stbi_write_force_png_filter; // defaults to -1; set to 0..5 to force a filter mode
|
||||
|
||||
|
||||
You can define STBI_WRITE_NO_STDIO to disable the file variant of these
|
||||
functions, so the library will not use stdio.h at all. However, this will
|
||||
also disable HDR writing, because it requires stdio for formatted output.
|
||||
|
||||
Each function returns 0 on failure and non-0 on success.
|
||||
|
||||
The functions create an image file defined by the parameters. The image
|
||||
is a rectangle of pixels stored from left-to-right, top-to-bottom.
|
||||
Each pixel contains 'comp' channels of data stored interleaved with 8-bits
|
||||
per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is
|
||||
monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall.
|
||||
The *data pointer points to the first byte of the top-left-most pixel.
|
||||
For PNG, "stride_in_bytes" is the distance in bytes from the first byte of
|
||||
a row of pixels to the first byte of the next row of pixels.
|
||||
|
||||
PNG creates output files with the same number of components as the input.
|
||||
The BMP format expands Y to RGB in the file format and does not
|
||||
output alpha.
|
||||
|
||||
PNG supports writing rectangles of data even when the bytes storing rows of
|
||||
data are not consecutive in memory (e.g. sub-rectangles of a larger image),
|
||||
by supplying the stride between the beginning of adjacent rows. The other
|
||||
formats do not. (Thus you cannot write a native-format BMP through the BMP
|
||||
writer, both because it is in BGR order and because it may have padding
|
||||
at the end of the line.)
|
||||
|
||||
PNG allows you to set the deflate compression level by setting the global
|
||||
variable 'stbi_write_png_compression_level' (it defaults to 8).
|
||||
|
||||
HDR expects linear float data. Since the format is always 32-bit rgb(e)
|
||||
data, alpha (if provided) is discarded, and for monochrome data it is
|
||||
replicated across all three channels.
|
||||
|
||||
TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed
|
||||
data, set the global variable 'stbi_write_tga_with_rle' to 0.
|
||||
|
||||
JPEG does ignore alpha channels in input data; quality is between 1 and 100.
|
||||
Higher quality looks better but results in a bigger image.
|
||||
JPEG baseline (no JPEG progressive).
|
||||
|
||||
CREDITS:
|
||||
|
||||
|
||||
Sean Barrett - PNG/BMP/TGA
|
||||
Baldur Karlsson - HDR
|
||||
Jean-Sebastien Guay - TGA monochrome
|
||||
Tim Kelsey - misc enhancements
|
||||
Alan Hickman - TGA RLE
|
||||
Emmanuel Julien - initial file IO callback implementation
|
||||
Jon Olick - original jo_jpeg.cpp code
|
||||
Daniel Gibson - integrate JPEG, allow external zlib
|
||||
Aarni Koskela - allow choosing PNG filter
|
||||
|
||||
bugfixes:
|
||||
github:Chribba
|
||||
Guillaume Chereau
|
||||
github:jry2
|
||||
github:romigrou
|
||||
Sergio Gonzalez
|
||||
Jonas Karlsson
|
||||
Filip Wasil
|
||||
Thatcher Ulrich
|
||||
github:poppolopoppo
|
||||
Patrick Boettcher
|
||||
github:xeekworx
|
||||
Cap Petschulat
|
||||
Simon Rodriguez
|
||||
Ivan Tikhonov
|
||||
github:ignotion
|
||||
Adam Schackart
|
||||
Andrew Kensler
|
||||
|
||||
LICENSE
|
||||
|
||||
See end of file for license information.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE_STB_IMAGE_WRITE_H
|
||||
#define INCLUDE_STB_IMAGE_WRITE_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
// if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline'
|
||||
#ifndef STBIWDEF
|
||||
#ifdef STB_IMAGE_WRITE_STATIC
|
||||
#define STBIWDEF static
|
||||
#else
|
||||
#ifdef __cplusplus
|
||||
#define STBIWDEF extern "C"
|
||||
#else
|
||||
#define STBIWDEF extern
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations
|
||||
STBIWDEF int stbi_write_tga_with_rle;
|
||||
STBIWDEF int stbi_write_png_compression_level;
|
||||
STBIWDEF int stbi_write_force_png_filter;
|
||||
#endif
|
||||
|
||||
#ifndef STBI_WRITE_NO_STDIO
|
||||
STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
|
||||
STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
|
||||
STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
|
||||
STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
|
||||
STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality);
|
||||
|
||||
#ifdef STBIW_WINDOWS_UTF8
|
||||
STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef void stbi_write_func(void *context, void *data, int size);
|
||||
|
||||
STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes);
|
||||
STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
|
||||
STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
|
||||
STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
|
||||
STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);
|
||||
STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len);
|
||||
|
||||
STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean);
|
||||
|
||||
#endif//INCLUDE_STB_IMAGE_WRITE_H
|
||||
|
||||
/* Revision history
|
||||
1.16 (2021-07-11)
|
||||
make Deflate code emit uncompressed blocks when it would otherwise expand
|
||||
support writing BMPs with alpha channel
|
||||
1.15 (2020-07-13) unknown
|
||||
1.14 (2020-02-02) updated JPEG writer to downsample chroma channels
|
||||
1.13
|
||||
1.12
|
||||
1.11 (2019-08-11)
|
||||
|
||||
1.10 (2019-02-07)
|
||||
support utf8 filenames in Windows; fix warnings and platform ifdefs
|
||||
1.09 (2018-02-11)
|
||||
fix typo in zlib quality API, improve STB_I_W_STATIC in C++
|
||||
1.08 (2018-01-29)
|
||||
add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter
|
||||
1.07 (2017-07-24)
|
||||
doc fix
|
||||
1.06 (2017-07-23)
|
||||
writing JPEG (using Jon Olick's code)
|
||||
1.05 ???
|
||||
1.04 (2017-03-03)
|
||||
monochrome BMP expansion
|
||||
1.03 ???
|
||||
1.02 (2016-04-02)
|
||||
avoid allocating large structures on the stack
|
||||
1.01 (2016-01-16)
|
||||
STBIW_REALLOC_SIZED: support allocators with no realloc support
|
||||
avoid race-condition in crc initialization
|
||||
minor compile issues
|
||||
1.00 (2015-09-14)
|
||||
installable file IO function
|
||||
0.99 (2015-09-13)
|
||||
warning fixes; TGA rle support
|
||||
0.98 (2015-04-08)
|
||||
added STBIW_MALLOC, STBIW_ASSERT etc
|
||||
0.97 (2015-01-18)
|
||||
fixed HDR asserts, rewrote HDR rle logic
|
||||
0.96 (2015-01-17)
|
||||
add HDR output
|
||||
fix monochrome BMP
|
||||
0.95 (2014-08-17)
|
||||
add monochrome TGA output
|
||||
0.94 (2014-05-31)
|
||||
rename private functions to avoid conflicts with stb_image.h
|
||||
0.93 (2014-05-27)
|
||||
warning fixes
|
||||
0.92 (2010-08-01)
|
||||
casts to unsigned char to fix warnings
|
||||
0.91 (2010-07-17)
|
||||
first public release
|
||||
0.90 first internal release
|
||||
*/
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -11,7 +11,6 @@
|
||||
#include <mach/mach.h>
|
||||
#elif defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#include "common/string_util.h"
|
||||
#else
|
||||
#if defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
#include <pthread_np.h>
|
||||
@@ -83,8 +82,29 @@ void SetCurrentThreadPriority(ThreadPriority new_priority) {
|
||||
#ifdef _MSC_VER
|
||||
|
||||
// Sets the debugger-visible name of the current thread.
|
||||
// Uses trick documented in:
|
||||
// https://docs.microsoft.com/en-us/visualstudio/debugger/how-to-set-a-thread-name-in-native-code
|
||||
void SetCurrentThreadName(const char* name) {
|
||||
SetThreadDescription(GetCurrentThread(), UTF8ToUTF16W(name).data());
|
||||
static const DWORD MS_VC_EXCEPTION = 0x406D1388;
|
||||
|
||||
#pragma pack(push, 8)
|
||||
struct THREADNAME_INFO {
|
||||
DWORD dwType; // must be 0x1000
|
||||
LPCSTR szName; // pointer to name (in user addr space)
|
||||
DWORD dwThreadID; // thread ID (-1=caller thread)
|
||||
DWORD dwFlags; // reserved for future use, must be zero
|
||||
} info;
|
||||
#pragma pack(pop)
|
||||
|
||||
info.dwType = 0x1000;
|
||||
info.szName = name;
|
||||
info.dwThreadID = std::numeric_limits<DWORD>::max();
|
||||
info.dwFlags = 0;
|
||||
|
||||
__try {
|
||||
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
|
||||
} __except (EXCEPTION_CONTINUE_EXECUTION) {
|
||||
}
|
||||
}
|
||||
|
||||
#else // !MSVC_VER, so must be POSIX threads
|
||||
|
||||
@@ -822,13 +822,11 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) {
|
||||
const char i = True(mem_info.attribute & MemoryAttribute::IpcLocked) ? 'I' : '-';
|
||||
const char d = True(mem_info.attribute & MemoryAttribute::DeviceShared) ? 'D' : '-';
|
||||
const char u = True(mem_info.attribute & MemoryAttribute::Uncached) ? 'U' : '-';
|
||||
const char p =
|
||||
True(mem_info.attribute & MemoryAttribute::PermissionLocked) ? 'P' : '-';
|
||||
|
||||
reply += fmt::format(" {:#012x} - {:#012x} {} {} {}{}{}{}{} [{}, {}]\n",
|
||||
mem_info.base_address,
|
||||
mem_info.base_address + mem_info.size - 1, perm, state, l, i,
|
||||
d, u, p, mem_info.ipc_count, mem_info.device_count);
|
||||
reply +=
|
||||
fmt::format(" {:#012x} - {:#012x} {} {} {}{}{}{} [{}, {}]\n",
|
||||
mem_info.base_address, mem_info.base_address + mem_info.size - 1,
|
||||
perm, state, l, i, d, u, mem_info.ipc_count, mem_info.device_count);
|
||||
}
|
||||
|
||||
const uintptr_t next_address = mem_info.base_address + mem_info.size;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/file_sys/system_archive/system_version.h"
|
||||
#include "core/file_sys/vfs_vector.h"
|
||||
#include "core/hle/api_version.h"
|
||||
@@ -13,9 +12,6 @@ std::string GetLongDisplayVersion() {
|
||||
}
|
||||
|
||||
VirtualDir SystemVersion() {
|
||||
LOG_WARNING(Common_Filesystem, "called - Using hardcoded firmware version '{}'",
|
||||
GetLongDisplayVersion());
|
||||
|
||||
VirtualFile file = std::make_shared<VectorVfsFile>(std::vector<u8>(0x100), "file");
|
||||
file->WriteObject(HLE::ApiVersion::HOS_VERSION_MAJOR, 0);
|
||||
file->WriteObject(HLE::ApiVersion::HOS_VERSION_MINOR, 1);
|
||||
|
||||
@@ -106,7 +106,7 @@ static_assert(KernelPageBufferAdditionalSize ==
|
||||
/// memory.
|
||||
static KPhysicalAddress TranslateSlabAddrToPhysical(KMemoryLayout& memory_layout,
|
||||
KVirtualAddress slab_addr) {
|
||||
slab_addr -= memory_layout.GetSlabRegion().GetAddress();
|
||||
slab_addr -= GetInteger(memory_layout.GetSlabRegionAddress());
|
||||
return GetInteger(slab_addr) + Core::DramMemoryMap::SlabHeapBase;
|
||||
}
|
||||
|
||||
@@ -196,12 +196,7 @@ void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout) {
|
||||
auto& kernel = system.Kernel();
|
||||
|
||||
// Get the start of the slab region, since that's where we'll be working.
|
||||
const KMemoryRegion& slab_region = memory_layout.GetSlabRegion();
|
||||
KVirtualAddress address = slab_region.GetAddress();
|
||||
|
||||
// Clear the slab region.
|
||||
// TODO: implement access to kernel VAs.
|
||||
// std::memset(device_ptr, 0, slab_region.GetSize());
|
||||
KVirtualAddress address = memory_layout.GetSlabRegionAddress();
|
||||
|
||||
// Initialize slab type array to be in sorted order.
|
||||
std::array<KSlabType, KSlabType_Count> slab_types;
|
||||
|
||||
@@ -19,8 +19,4 @@ static inline KPhysicalAddress GetInitialProcessBinaryPhysicalAddress() {
|
||||
MainMemoryAddress);
|
||||
}
|
||||
|
||||
static inline size_t GetInitialProcessBinarySize() {
|
||||
return InitialProcessBinarySizeMax;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -36,7 +36,6 @@ enum class KMemoryState : u32 {
|
||||
FlagCanChangeAttribute = (1 << 24),
|
||||
FlagCanCodeMemory = (1 << 25),
|
||||
FlagLinearMapped = (1 << 26),
|
||||
FlagCanPermissionLock = (1 << 27),
|
||||
|
||||
FlagsData = FlagCanReprotect | FlagCanUseIpc | FlagCanUseNonDeviceIpc | FlagCanUseNonSecureIpc |
|
||||
FlagMapped | FlagCanAlias | FlagCanTransfer | FlagCanQueryPhysical |
|
||||
@@ -51,16 +50,12 @@ enum class KMemoryState : u32 {
|
||||
FlagLinearMapped,
|
||||
|
||||
Free = static_cast<u32>(Svc::MemoryState::Free),
|
||||
|
||||
IoMemory = static_cast<u32>(Svc::MemoryState::Io) | FlagMapped | FlagCanDeviceMap |
|
||||
FlagCanAlignedDeviceMap,
|
||||
IoRegister =
|
||||
static_cast<u32>(Svc::MemoryState::Io) | FlagCanDeviceMap | FlagCanAlignedDeviceMap,
|
||||
|
||||
Io = static_cast<u32>(Svc::MemoryState::Io) | FlagMapped | FlagCanDeviceMap |
|
||||
FlagCanAlignedDeviceMap,
|
||||
Static = static_cast<u32>(Svc::MemoryState::Static) | FlagMapped | FlagCanQueryPhysical,
|
||||
Code = static_cast<u32>(Svc::MemoryState::Code) | FlagsCode | FlagCanMapProcess,
|
||||
CodeData = static_cast<u32>(Svc::MemoryState::CodeData) | FlagsData | FlagCanMapProcess |
|
||||
FlagCanCodeMemory | FlagCanPermissionLock,
|
||||
FlagCanCodeMemory,
|
||||
Normal = static_cast<u32>(Svc::MemoryState::Normal) | FlagsData | FlagCanCodeMemory,
|
||||
Shared = static_cast<u32>(Svc::MemoryState::Shared) | FlagMapped | FlagReferenceCounted |
|
||||
FlagLinearMapped,
|
||||
@@ -70,8 +65,7 @@ enum class KMemoryState : u32 {
|
||||
AliasCode = static_cast<u32>(Svc::MemoryState::AliasCode) | FlagsCode | FlagCanMapProcess |
|
||||
FlagCanCodeAlias,
|
||||
AliasCodeData = static_cast<u32>(Svc::MemoryState::AliasCodeData) | FlagsData |
|
||||
FlagCanMapProcess | FlagCanCodeAlias | FlagCanCodeMemory |
|
||||
FlagCanPermissionLock,
|
||||
FlagCanMapProcess | FlagCanCodeAlias | FlagCanCodeMemory,
|
||||
|
||||
Ipc = static_cast<u32>(Svc::MemoryState::Ipc) | FlagsMisc | FlagCanAlignedDeviceMap |
|
||||
FlagCanUseIpc | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
|
||||
@@ -79,7 +73,7 @@ enum class KMemoryState : u32 {
|
||||
Stack = static_cast<u32>(Svc::MemoryState::Stack) | FlagsMisc | FlagCanAlignedDeviceMap |
|
||||
FlagCanUseIpc | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
|
||||
|
||||
ThreadLocal = static_cast<u32>(Svc::MemoryState::ThreadLocal) | FlagLinearMapped,
|
||||
ThreadLocal = static_cast<u32>(Svc::MemoryState::ThreadLocal) | FlagMapped | FlagLinearMapped,
|
||||
|
||||
Transfered = static_cast<u32>(Svc::MemoryState::Transfered) | FlagsMisc |
|
||||
FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc |
|
||||
@@ -100,7 +94,7 @@ enum class KMemoryState : u32 {
|
||||
NonDeviceIpc =
|
||||
static_cast<u32>(Svc::MemoryState::NonDeviceIpc) | FlagsMisc | FlagCanUseNonDeviceIpc,
|
||||
|
||||
Kernel = static_cast<u32>(Svc::MemoryState::Kernel),
|
||||
Kernel = static_cast<u32>(Svc::MemoryState::Kernel) | FlagMapped,
|
||||
|
||||
GeneratedCode = static_cast<u32>(Svc::MemoryState::GeneratedCode) | FlagMapped |
|
||||
FlagReferenceCounted | FlagCanDebug | FlagLinearMapped,
|
||||
@@ -111,36 +105,34 @@ enum class KMemoryState : u32 {
|
||||
|
||||
Insecure = static_cast<u32>(Svc::MemoryState::Insecure) | FlagMapped | FlagReferenceCounted |
|
||||
FlagLinearMapped | FlagCanChangeAttribute | FlagCanDeviceMap |
|
||||
FlagCanAlignedDeviceMap | FlagCanQueryPhysical | FlagCanUseNonSecureIpc |
|
||||
FlagCanUseNonDeviceIpc,
|
||||
FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
|
||||
};
|
||||
DECLARE_ENUM_FLAG_OPERATORS(KMemoryState);
|
||||
|
||||
static_assert(static_cast<u32>(KMemoryState::Free) == 0x00000000);
|
||||
static_assert(static_cast<u32>(KMemoryState::IoMemory) == 0x00182001);
|
||||
static_assert(static_cast<u32>(KMemoryState::IoRegister) == 0x00180001);
|
||||
static_assert(static_cast<u32>(KMemoryState::Io) == 0x00182001);
|
||||
static_assert(static_cast<u32>(KMemoryState::Static) == 0x00042002);
|
||||
static_assert(static_cast<u32>(KMemoryState::Code) == 0x04DC7E03);
|
||||
static_assert(static_cast<u32>(KMemoryState::CodeData) == 0x0FFEBD04);
|
||||
static_assert(static_cast<u32>(KMemoryState::CodeData) == 0x07FEBD04);
|
||||
static_assert(static_cast<u32>(KMemoryState::Normal) == 0x077EBD05);
|
||||
static_assert(static_cast<u32>(KMemoryState::Shared) == 0x04402006);
|
||||
|
||||
static_assert(static_cast<u32>(KMemoryState::AliasCode) == 0x04DD7E08);
|
||||
static_assert(static_cast<u32>(KMemoryState::AliasCodeData) == 0x0FFFBD09);
|
||||
static_assert(static_cast<u32>(KMemoryState::AliasCodeData) == 0x07FFBD09);
|
||||
static_assert(static_cast<u32>(KMemoryState::Ipc) == 0x045C3C0A);
|
||||
static_assert(static_cast<u32>(KMemoryState::Stack) == 0x045C3C0B);
|
||||
static_assert(static_cast<u32>(KMemoryState::ThreadLocal) == 0x0400000C);
|
||||
static_assert(static_cast<u32>(KMemoryState::ThreadLocal) == 0x0400200C);
|
||||
static_assert(static_cast<u32>(KMemoryState::Transfered) == 0x055C3C0D);
|
||||
static_assert(static_cast<u32>(KMemoryState::SharedTransfered) == 0x045C380E);
|
||||
static_assert(static_cast<u32>(KMemoryState::SharedCode) == 0x0440380F);
|
||||
static_assert(static_cast<u32>(KMemoryState::Inaccessible) == 0x00000010);
|
||||
static_assert(static_cast<u32>(KMemoryState::NonSecureIpc) == 0x045C3811);
|
||||
static_assert(static_cast<u32>(KMemoryState::NonDeviceIpc) == 0x044C2812);
|
||||
static_assert(static_cast<u32>(KMemoryState::Kernel) == 0x00000013);
|
||||
static_assert(static_cast<u32>(KMemoryState::Kernel) == 0x00002013);
|
||||
static_assert(static_cast<u32>(KMemoryState::GeneratedCode) == 0x04402214);
|
||||
static_assert(static_cast<u32>(KMemoryState::CodeOut) == 0x04402015);
|
||||
static_assert(static_cast<u32>(KMemoryState::Coverage) == 0x00002016);
|
||||
static_assert(static_cast<u32>(KMemoryState::Insecure) == 0x055C3817);
|
||||
static_assert(static_cast<u32>(KMemoryState::Insecure) == 0x05583817);
|
||||
|
||||
enum class KMemoryPermission : u8 {
|
||||
None = 0,
|
||||
@@ -190,9 +182,8 @@ enum class KMemoryAttribute : u8 {
|
||||
IpcLocked = static_cast<u8>(Svc::MemoryAttribute::IpcLocked),
|
||||
DeviceShared = static_cast<u8>(Svc::MemoryAttribute::DeviceShared),
|
||||
Uncached = static_cast<u8>(Svc::MemoryAttribute::Uncached),
|
||||
PermissionLocked = static_cast<u8>(Svc::MemoryAttribute::PermissionLocked),
|
||||
|
||||
SetMask = Uncached | PermissionLocked,
|
||||
SetMask = Uncached,
|
||||
};
|
||||
DECLARE_ENUM_FLAG_OPERATORS(KMemoryAttribute);
|
||||
|
||||
@@ -270,10 +261,6 @@ struct KMemoryInfo {
|
||||
return m_state;
|
||||
}
|
||||
|
||||
constexpr Svc::MemoryState GetSvcState() const {
|
||||
return static_cast<Svc::MemoryState>(m_state & KMemoryState::Mask);
|
||||
}
|
||||
|
||||
constexpr KMemoryPermission GetPermission() const {
|
||||
return m_permission;
|
||||
}
|
||||
@@ -339,10 +326,6 @@ public:
|
||||
return this->GetEndAddress() - 1;
|
||||
}
|
||||
|
||||
constexpr KMemoryState GetState() const {
|
||||
return m_memory_state;
|
||||
}
|
||||
|
||||
constexpr u16 GetIpcLockCount() const {
|
||||
return m_ipc_lock_count;
|
||||
}
|
||||
@@ -460,13 +443,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
constexpr void UpdateAttribute(KMemoryAttribute mask, KMemoryAttribute attr) {
|
||||
ASSERT(False(mask & KMemoryAttribute::IpcLocked));
|
||||
ASSERT(False(mask & KMemoryAttribute::DeviceShared));
|
||||
|
||||
m_attribute = (m_attribute & ~mask) | attr;
|
||||
}
|
||||
|
||||
constexpr void Split(KMemoryBlock* block, KProcessAddress addr) {
|
||||
ASSERT(this->GetAddress() < addr);
|
||||
ASSERT(this->Contains(addr));
|
||||
|
||||
@@ -160,8 +160,8 @@ void KMemoryBlockManager::Update(KMemoryBlockManagerUpdateAllocator* allocator,
|
||||
}
|
||||
|
||||
// Update block state.
|
||||
it->Update(state, perm, attr, it->GetAddress() == address,
|
||||
static_cast<u8>(set_disable_attr), static_cast<u8>(clear_disable_attr));
|
||||
it->Update(state, perm, attr, cur_address == address, static_cast<u8>(set_disable_attr),
|
||||
static_cast<u8>(clear_disable_attr));
|
||||
cur_address += cur_info.GetSize();
|
||||
remaining_pages -= cur_info.GetNumPages();
|
||||
}
|
||||
@@ -175,9 +175,7 @@ void KMemoryBlockManager::UpdateIfMatch(KMemoryBlockManagerUpdateAllocator* allo
|
||||
KProcessAddress address, size_t num_pages,
|
||||
KMemoryState test_state, KMemoryPermission test_perm,
|
||||
KMemoryAttribute test_attr, KMemoryState state,
|
||||
KMemoryPermission perm, KMemoryAttribute attr,
|
||||
KMemoryBlockDisableMergeAttribute set_disable_attr,
|
||||
KMemoryBlockDisableMergeAttribute clear_disable_attr) {
|
||||
KMemoryPermission perm, KMemoryAttribute attr) {
|
||||
// Ensure for auditing that we never end up with an invalid tree.
|
||||
KScopedMemoryBlockManagerAuditor auditor(this);
|
||||
ASSERT(Common::IsAligned(GetInteger(address), PageSize));
|
||||
@@ -216,8 +214,7 @@ void KMemoryBlockManager::UpdateIfMatch(KMemoryBlockManagerUpdateAllocator* allo
|
||||
}
|
||||
|
||||
// Update block state.
|
||||
it->Update(state, perm, attr, false, static_cast<u8>(set_disable_attr),
|
||||
static_cast<u8>(clear_disable_attr));
|
||||
it->Update(state, perm, attr, false, 0, 0);
|
||||
cur_address += cur_info.GetSize();
|
||||
remaining_pages -= cur_info.GetNumPages();
|
||||
} else {
|
||||
@@ -287,65 +284,6 @@ void KMemoryBlockManager::UpdateLock(KMemoryBlockManagerUpdateAllocator* allocat
|
||||
this->CoalesceForUpdate(allocator, address, num_pages);
|
||||
}
|
||||
|
||||
void KMemoryBlockManager::UpdateAttribute(KMemoryBlockManagerUpdateAllocator* allocator,
|
||||
KProcessAddress address, size_t num_pages,
|
||||
KMemoryAttribute mask, KMemoryAttribute attr) {
|
||||
// Ensure for auditing that we never end up with an invalid tree.
|
||||
KScopedMemoryBlockManagerAuditor auditor(this);
|
||||
ASSERT(Common::IsAligned(GetInteger(address), PageSize));
|
||||
|
||||
KProcessAddress cur_address = address;
|
||||
size_t remaining_pages = num_pages;
|
||||
iterator it = this->FindIterator(address);
|
||||
|
||||
while (remaining_pages > 0) {
|
||||
const size_t remaining_size = remaining_pages * PageSize;
|
||||
KMemoryInfo cur_info = it->GetMemoryInfo();
|
||||
|
||||
if ((it->GetAttribute() & mask) != attr) {
|
||||
// If we need to, create a new block before and insert it.
|
||||
if (cur_info.GetAddress() != GetInteger(cur_address)) {
|
||||
KMemoryBlock* new_block = allocator->Allocate();
|
||||
|
||||
it->Split(new_block, cur_address);
|
||||
it = m_memory_block_tree.insert(*new_block);
|
||||
it++;
|
||||
|
||||
cur_info = it->GetMemoryInfo();
|
||||
cur_address = cur_info.GetAddress();
|
||||
}
|
||||
|
||||
// If we need to, create a new block after and insert it.
|
||||
if (cur_info.GetSize() > remaining_size) {
|
||||
KMemoryBlock* new_block = allocator->Allocate();
|
||||
|
||||
it->Split(new_block, cur_address + remaining_size);
|
||||
it = m_memory_block_tree.insert(*new_block);
|
||||
|
||||
cur_info = it->GetMemoryInfo();
|
||||
}
|
||||
|
||||
// Update block state.
|
||||
it->UpdateAttribute(mask, attr);
|
||||
cur_address += cur_info.GetSize();
|
||||
remaining_pages -= cur_info.GetNumPages();
|
||||
} else {
|
||||
// If we already have the right attributes, just advance.
|
||||
if (cur_address + remaining_size < cur_info.GetEndAddress()) {
|
||||
remaining_pages = 0;
|
||||
cur_address += remaining_size;
|
||||
} else {
|
||||
remaining_pages =
|
||||
(cur_address + remaining_size - cur_info.GetEndAddress()) / PageSize;
|
||||
cur_address = cur_info.GetEndAddress();
|
||||
}
|
||||
}
|
||||
it++;
|
||||
}
|
||||
|
||||
this->CoalesceForUpdate(allocator, address, num_pages);
|
||||
}
|
||||
|
||||
// Debug.
|
||||
bool KMemoryBlockManager::CheckState() const {
|
||||
// Loop over every block, ensuring that we are sorted and coalesced.
|
||||
|
||||
@@ -115,11 +115,7 @@ public:
|
||||
void UpdateIfMatch(KMemoryBlockManagerUpdateAllocator* allocator, KProcessAddress address,
|
||||
size_t num_pages, KMemoryState test_state, KMemoryPermission test_perm,
|
||||
KMemoryAttribute test_attr, KMemoryState state, KMemoryPermission perm,
|
||||
KMemoryAttribute attr, KMemoryBlockDisableMergeAttribute set_disable_attr,
|
||||
KMemoryBlockDisableMergeAttribute clear_disable_attr);
|
||||
|
||||
void UpdateAttribute(KMemoryBlockManagerUpdateAllocator* allocator, KProcessAddress address,
|
||||
size_t num_pages, KMemoryAttribute mask, KMemoryAttribute attr);
|
||||
KMemoryAttribute attr);
|
||||
|
||||
iterator FindIterator(KProcessAddress address) const {
|
||||
return m_memory_block_tree.find(KMemoryBlock(
|
||||
|
||||
@@ -137,9 +137,11 @@ public:
|
||||
return GetStackTopAddress(core_id, KMemoryRegionType_KernelMiscExceptionStack);
|
||||
}
|
||||
|
||||
const KMemoryRegion& GetSlabRegion() const {
|
||||
return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_KernelSlab));
|
||||
KVirtualAddress GetSlabRegionAddress() const {
|
||||
return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_KernelSlab))
|
||||
.GetAddress();
|
||||
}
|
||||
|
||||
const KMemoryRegion& GetDeviceRegion(KMemoryRegionType type) const {
|
||||
return Dereference(GetPhysicalMemoryRegionTree().FindFirstDerived(type));
|
||||
}
|
||||
|
||||
@@ -119,8 +119,7 @@ void KMemoryManager::Initialize(KVirtualAddress management_region, size_t manage
|
||||
// Free each region to its corresponding heap.
|
||||
size_t reserved_sizes[MaxManagerCount] = {};
|
||||
const KPhysicalAddress ini_start = GetInitialProcessBinaryPhysicalAddress();
|
||||
const size_t ini_size = GetInitialProcessBinarySize();
|
||||
const KPhysicalAddress ini_end = ini_start + ini_size;
|
||||
const KPhysicalAddress ini_end = ini_start + InitialProcessBinarySizeMax;
|
||||
const KPhysicalAddress ini_last = ini_end - 1;
|
||||
for (const auto& it : m_system.Kernel().MemoryLayout().GetPhysicalMemoryRegionTree()) {
|
||||
if (it.IsDerivedFrom(KMemoryRegionType_DramUserPool)) {
|
||||
@@ -138,13 +137,13 @@ void KMemoryManager::Initialize(KVirtualAddress management_region, size_t manage
|
||||
}
|
||||
|
||||
// Open/reserve the ini memory.
|
||||
manager.OpenFirst(ini_start, ini_size / PageSize);
|
||||
reserved_sizes[it.GetAttributes()] += ini_size;
|
||||
manager.OpenFirst(ini_start, InitialProcessBinarySizeMax / PageSize);
|
||||
reserved_sizes[it.GetAttributes()] += InitialProcessBinarySizeMax;
|
||||
|
||||
// Free memory after the ini to the heap.
|
||||
if (ini_last != cur_last) {
|
||||
ASSERT(cur_end != 0);
|
||||
manager.Free(ini_end, (cur_end - ini_end) / PageSize);
|
||||
manager.Free(ini_end, cur_end - ini_end);
|
||||
}
|
||||
} else {
|
||||
// Ensure there's no partial overlap with the ini image.
|
||||
|
||||
@@ -190,15 +190,9 @@ static_assert(KMemoryRegionType_DramKernelInitPt.GetValue() ==
|
||||
constexpr inline auto KMemoryRegionType_DramKernelSecureAppletMemory =
|
||||
KMemoryRegionType_DramKernelBase.DeriveSparse(1, 3, 0).SetAttribute(
|
||||
KMemoryRegionAttr_LinearMapped);
|
||||
constexpr inline const auto KMemoryRegionType_DramKernelSecureUnknown =
|
||||
KMemoryRegionType_DramKernelBase.DeriveSparse(1, 3, 1).SetAttribute(
|
||||
KMemoryRegionAttr_LinearMapped);
|
||||
static_assert(KMemoryRegionType_DramKernelSecureAppletMemory.GetValue() ==
|
||||
(0x18E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap |
|
||||
KMemoryRegionAttr_LinearMapped));
|
||||
static_assert(KMemoryRegionType_DramKernelSecureUnknown.GetValue() ==
|
||||
(0x28E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap |
|
||||
KMemoryRegionAttr_LinearMapped));
|
||||
|
||||
constexpr inline auto KMemoryRegionType_DramReservedEarly =
|
||||
KMemoryRegionType_DramReservedBase.DeriveAttribute(KMemoryRegionAttr_NoUserMap);
|
||||
@@ -223,18 +217,16 @@ constexpr inline auto KMemoryRegionType_DramPoolPartition =
|
||||
static_assert(KMemoryRegionType_DramPoolPartition.GetValue() ==
|
||||
(0x26 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
|
||||
|
||||
// UNUSED: .Derive(4, 1);
|
||||
// UNUSED: .Derive(4, 2);
|
||||
constexpr inline const auto KMemoryRegionType_DramPoolManagement =
|
||||
KMemoryRegionType_DramPoolPartition.Derive(4, 0).SetAttribute(
|
||||
constexpr inline auto KMemoryRegionType_DramPoolManagement =
|
||||
KMemoryRegionType_DramPoolPartition.DeriveTransition(0, 2).DeriveTransition().SetAttribute(
|
||||
KMemoryRegionAttr_CarveoutProtected);
|
||||
constexpr inline const auto KMemoryRegionType_DramUserPool =
|
||||
KMemoryRegionType_DramPoolPartition.Derive(4, 3);
|
||||
constexpr inline auto KMemoryRegionType_DramUserPool =
|
||||
KMemoryRegionType_DramPoolPartition.DeriveTransition(1, 2).DeriveTransition();
|
||||
static_assert(KMemoryRegionType_DramPoolManagement.GetValue() ==
|
||||
(0xE6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap |
|
||||
(0x166 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap |
|
||||
KMemoryRegionAttr_CarveoutProtected));
|
||||
static_assert(KMemoryRegionType_DramUserPool.GetValue() ==
|
||||
(0x266 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
|
||||
(0x1A6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
|
||||
|
||||
constexpr inline auto KMemoryRegionType_DramApplicationPool =
|
||||
KMemoryRegionType_DramUserPool.Derive(4, 0);
|
||||
@@ -245,63 +237,60 @@ constexpr inline auto KMemoryRegionType_DramSystemNonSecurePool =
|
||||
constexpr inline auto KMemoryRegionType_DramSystemPool =
|
||||
KMemoryRegionType_DramUserPool.Derive(4, 3).SetAttribute(KMemoryRegionAttr_CarveoutProtected);
|
||||
static_assert(KMemoryRegionType_DramApplicationPool.GetValue() ==
|
||||
(0xE66 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
|
||||
(0x7A6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
|
||||
static_assert(KMemoryRegionType_DramAppletPool.GetValue() ==
|
||||
(0x1666 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
|
||||
(0xBA6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
|
||||
static_assert(KMemoryRegionType_DramSystemNonSecurePool.GetValue() ==
|
||||
(0x1A66 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
|
||||
(0xDA6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
|
||||
static_assert(KMemoryRegionType_DramSystemPool.GetValue() ==
|
||||
(0x2666 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap |
|
||||
(0x13A6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap |
|
||||
KMemoryRegionAttr_CarveoutProtected));
|
||||
|
||||
constexpr inline auto KMemoryRegionType_VirtualDramHeapBase =
|
||||
KMemoryRegionType_Dram.DeriveSparse(1, 4, 0);
|
||||
KMemoryRegionType_Dram.DeriveSparse(1, 3, 0);
|
||||
constexpr inline auto KMemoryRegionType_VirtualDramKernelPtHeap =
|
||||
KMemoryRegionType_Dram.DeriveSparse(1, 4, 1);
|
||||
KMemoryRegionType_Dram.DeriveSparse(1, 3, 1);
|
||||
constexpr inline auto KMemoryRegionType_VirtualDramKernelTraceBuffer =
|
||||
KMemoryRegionType_Dram.DeriveSparse(1, 4, 2);
|
||||
KMemoryRegionType_Dram.DeriveSparse(1, 3, 2);
|
||||
static_assert(KMemoryRegionType_VirtualDramHeapBase.GetValue() == 0x1A);
|
||||
static_assert(KMemoryRegionType_VirtualDramKernelPtHeap.GetValue() == 0x2A);
|
||||
static_assert(KMemoryRegionType_VirtualDramKernelTraceBuffer.GetValue() == 0x4A);
|
||||
|
||||
// UNUSED: .Derive(4, 2);
|
||||
constexpr inline const auto KMemoryRegionType_VirtualDramUnknownDebug =
|
||||
KMemoryRegionType_Dram.Advance(2).Derive(4, 0);
|
||||
constexpr inline const auto KMemoryRegionType_VirtualDramKernelSecureAppletMemory =
|
||||
KMemoryRegionType_Dram.Advance(2).Derive(4, 1);
|
||||
constexpr inline const auto KMemoryRegionType_VirtualDramKernelSecureUnknown =
|
||||
KMemoryRegionType_Dram.Advance(2).Derive(4, 3);
|
||||
static_assert(KMemoryRegionType_VirtualDramUnknownDebug.GetValue() == (0x32));
|
||||
static_assert(KMemoryRegionType_VirtualDramKernelSecureAppletMemory.GetValue() == (0x52));
|
||||
static_assert(KMemoryRegionType_VirtualDramKernelSecureUnknown.GetValue() == (0x92));
|
||||
// UNUSED: .DeriveSparse(2, 2, 0);
|
||||
constexpr inline auto KMemoryRegionType_VirtualDramUnknownDebug =
|
||||
KMemoryRegionType_Dram.DeriveSparse(2, 2, 1);
|
||||
static_assert(KMemoryRegionType_VirtualDramUnknownDebug.GetValue() == (0x52));
|
||||
|
||||
// UNUSED: .Derive(4, 3);
|
||||
constexpr inline const auto KMemoryRegionType_VirtualDramKernelInitPt =
|
||||
KMemoryRegionType_VirtualDramHeapBase.Derive(4, 0);
|
||||
constexpr inline const auto KMemoryRegionType_VirtualDramPoolManagement =
|
||||
KMemoryRegionType_VirtualDramHeapBase.Derive(4, 1);
|
||||
constexpr inline const auto KMemoryRegionType_VirtualDramUserPool =
|
||||
KMemoryRegionType_VirtualDramHeapBase.Derive(4, 2);
|
||||
static_assert(KMemoryRegionType_VirtualDramKernelInitPt.GetValue() == 0x31A);
|
||||
static_assert(KMemoryRegionType_VirtualDramPoolManagement.GetValue() == 0x51A);
|
||||
static_assert(KMemoryRegionType_VirtualDramUserPool.GetValue() == 0x61A);
|
||||
constexpr inline auto KMemoryRegionType_VirtualDramKernelSecureAppletMemory =
|
||||
KMemoryRegionType_Dram.DeriveSparse(3, 1, 0);
|
||||
static_assert(KMemoryRegionType_VirtualDramKernelSecureAppletMemory.GetValue() == (0x62));
|
||||
|
||||
constexpr inline auto KMemoryRegionType_VirtualDramKernelInitPt =
|
||||
KMemoryRegionType_VirtualDramHeapBase.Derive(3, 0);
|
||||
constexpr inline auto KMemoryRegionType_VirtualDramPoolManagement =
|
||||
KMemoryRegionType_VirtualDramHeapBase.Derive(3, 1);
|
||||
constexpr inline auto KMemoryRegionType_VirtualDramUserPool =
|
||||
KMemoryRegionType_VirtualDramHeapBase.Derive(3, 2);
|
||||
static_assert(KMemoryRegionType_VirtualDramKernelInitPt.GetValue() == 0x19A);
|
||||
static_assert(KMemoryRegionType_VirtualDramPoolManagement.GetValue() == 0x29A);
|
||||
static_assert(KMemoryRegionType_VirtualDramUserPool.GetValue() == 0x31A);
|
||||
|
||||
// NOTE: For unknown reason, the pools are derived out-of-order here.
|
||||
// It's worth eventually trying to understand why Nintendo made this choice.
|
||||
// UNUSED: .Derive(6, 0);
|
||||
// UNUSED: .Derive(6, 1);
|
||||
constexpr inline const auto KMemoryRegionType_VirtualDramApplicationPool =
|
||||
KMemoryRegionType_VirtualDramUserPool.Derive(4, 0);
|
||||
constexpr inline const auto KMemoryRegionType_VirtualDramAppletPool =
|
||||
KMemoryRegionType_VirtualDramUserPool.Derive(4, 1);
|
||||
constexpr inline const auto KMemoryRegionType_VirtualDramSystemNonSecurePool =
|
||||
KMemoryRegionType_VirtualDramUserPool.Derive(4, 2);
|
||||
constexpr inline const auto KMemoryRegionType_VirtualDramSystemPool =
|
||||
KMemoryRegionType_VirtualDramUserPool.Derive(4, 3);
|
||||
static_assert(KMemoryRegionType_VirtualDramApplicationPool.GetValue() == 0x361A);
|
||||
static_assert(KMemoryRegionType_VirtualDramAppletPool.GetValue() == 0x561A);
|
||||
static_assert(KMemoryRegionType_VirtualDramSystemNonSecurePool.GetValue() == 0x661A);
|
||||
static_assert(KMemoryRegionType_VirtualDramSystemPool.GetValue() == 0x961A);
|
||||
constexpr inline auto KMemoryRegionType_VirtualDramAppletPool =
|
||||
KMemoryRegionType_VirtualDramUserPool.Derive(6, 2);
|
||||
constexpr inline auto KMemoryRegionType_VirtualDramApplicationPool =
|
||||
KMemoryRegionType_VirtualDramUserPool.Derive(6, 3);
|
||||
constexpr inline auto KMemoryRegionType_VirtualDramSystemNonSecurePool =
|
||||
KMemoryRegionType_VirtualDramUserPool.Derive(6, 4);
|
||||
constexpr inline auto KMemoryRegionType_VirtualDramSystemPool =
|
||||
KMemoryRegionType_VirtualDramUserPool.Derive(6, 5);
|
||||
static_assert(KMemoryRegionType_VirtualDramAppletPool.GetValue() == 0x1B1A);
|
||||
static_assert(KMemoryRegionType_VirtualDramApplicationPool.GetValue() == 0x271A);
|
||||
static_assert(KMemoryRegionType_VirtualDramSystemNonSecurePool.GetValue() == 0x2B1A);
|
||||
static_assert(KMemoryRegionType_VirtualDramSystemPool.GetValue() == 0x331A);
|
||||
|
||||
constexpr inline auto KMemoryRegionType_ArchDeviceBase =
|
||||
KMemoryRegionType_Kernel.DeriveTransition(0, 1).SetSparseOnly();
|
||||
@@ -365,14 +354,12 @@ constexpr inline auto KMemoryRegionType_KernelTemp =
|
||||
static_assert(KMemoryRegionType_KernelTemp.GetValue() == 0x31);
|
||||
|
||||
constexpr KMemoryRegionType GetTypeForVirtualLinearMapping(u32 type_id) {
|
||||
if (KMemoryRegionType_DramKernelPtHeap.IsAncestorOf(type_id)) {
|
||||
if (KMemoryRegionType_KernelTraceBuffer.IsAncestorOf(type_id)) {
|
||||
return KMemoryRegionType_VirtualDramKernelTraceBuffer;
|
||||
} else if (KMemoryRegionType_DramKernelPtHeap.IsAncestorOf(type_id)) {
|
||||
return KMemoryRegionType_VirtualDramKernelPtHeap;
|
||||
} else if (KMemoryRegionType_DramKernelSecureAppletMemory.IsAncestorOf(type_id)) {
|
||||
return KMemoryRegionType_VirtualDramKernelSecureAppletMemory;
|
||||
} else if (KMemoryRegionType_DramKernelSecureUnknown.IsAncestorOf(type_id)) {
|
||||
return KMemoryRegionType_VirtualDramKernelSecureUnknown;
|
||||
} else if (KMemoryRegionType_KernelTraceBuffer.IsAncestorOf(type_id)) {
|
||||
return KMemoryRegionType_VirtualDramKernelTraceBuffer;
|
||||
} else if ((type_id | KMemoryRegionAttr_ShouldKernelMap) == type_id) {
|
||||
return KMemoryRegionType_VirtualDramUnknownDebug;
|
||||
} else {
|
||||
|
||||
@@ -183,17 +183,12 @@ private:
|
||||
|
||||
class KScopedPageGroup {
|
||||
public:
|
||||
explicit KScopedPageGroup(const KPageGroup* gp, bool not_first = true) : m_pg(gp) {
|
||||
explicit KScopedPageGroup(const KPageGroup* gp) : m_pg(gp) {
|
||||
if (m_pg) {
|
||||
if (not_first) {
|
||||
m_pg->Open();
|
||||
} else {
|
||||
m_pg->OpenFirst();
|
||||
}
|
||||
m_pg->Open();
|
||||
}
|
||||
}
|
||||
explicit KScopedPageGroup(const KPageGroup& gp, bool not_first = true)
|
||||
: KScopedPageGroup(std::addressof(gp), not_first) {}
|
||||
explicit KScopedPageGroup(const KPageGroup& gp) : KScopedPageGroup(std::addressof(gp)) {}
|
||||
~KScopedPageGroup() {
|
||||
if (m_pg) {
|
||||
m_pg->Close();
|
||||
|
||||
@@ -505,7 +505,7 @@ Result KPageTable::UnmapCodeMemory(KProcessAddress dst_address, KProcessAddress
|
||||
R_TRY(this->CheckMemoryStateContiguous(
|
||||
std::addressof(num_dst_allocator_blocks), dst_address, size, KMemoryState::FlagCanCodeAlias,
|
||||
KMemoryState::FlagCanCodeAlias, KMemoryPermission::None, KMemoryPermission::None,
|
||||
KMemoryAttribute::All & ~KMemoryAttribute::PermissionLocked, KMemoryAttribute::None));
|
||||
KMemoryAttribute::All, KMemoryAttribute::None));
|
||||
|
||||
// Determine whether any pages being unmapped are code.
|
||||
bool any_code_pages = false;
|
||||
@@ -1724,43 +1724,29 @@ Result KPageTable::MapPhysicalMemory(KProcessAddress address, size_t size) {
|
||||
PageSize;
|
||||
|
||||
// While we have pages to map, map them.
|
||||
{
|
||||
// Create a page group for the current mapping range.
|
||||
KPageGroup cur_pg(m_kernel, m_block_info_manager);
|
||||
{
|
||||
ON_RESULT_FAILURE_2 {
|
||||
cur_pg.OpenFirst();
|
||||
cur_pg.Close();
|
||||
};
|
||||
while (map_pages > 0) {
|
||||
// Check if we're at the end of the physical block.
|
||||
if (pg_pages == 0) {
|
||||
// Ensure there are more pages to map.
|
||||
ASSERT(pg_it != pg.end());
|
||||
|
||||
size_t remain_pages = map_pages;
|
||||
while (remain_pages > 0) {
|
||||
// Check if we're at the end of the physical block.
|
||||
if (pg_pages == 0) {
|
||||
// Ensure there are more pages to map.
|
||||
ASSERT(pg_it != pg.end());
|
||||
|
||||
// Advance our physical block.
|
||||
++pg_it;
|
||||
pg_phys_addr = pg_it->GetAddress();
|
||||
pg_pages = pg_it->GetNumPages();
|
||||
}
|
||||
|
||||
// Add whatever we can to the current block.
|
||||
const size_t cur_pages = std::min(pg_pages, remain_pages);
|
||||
R_TRY(cur_pg.AddBlock(pg_phys_addr +
|
||||
((pg_pages - cur_pages) * PageSize),
|
||||
cur_pages));
|
||||
|
||||
// Advance.
|
||||
remain_pages -= cur_pages;
|
||||
pg_pages -= cur_pages;
|
||||
}
|
||||
// Advance our physical block.
|
||||
++pg_it;
|
||||
pg_phys_addr = pg_it->GetAddress();
|
||||
pg_pages = pg_it->GetNumPages();
|
||||
}
|
||||
|
||||
// Map the pages.
|
||||
R_TRY(this->Operate(cur_address, map_pages, cur_pg,
|
||||
OperationType::MapFirstGroup));
|
||||
// Map whatever we can.
|
||||
const size_t cur_pages = std::min(pg_pages, map_pages);
|
||||
R_TRY(Operate(cur_address, cur_pages, KMemoryPermission::UserReadWrite,
|
||||
OperationType::MapFirst, pg_phys_addr));
|
||||
|
||||
// Advance.
|
||||
cur_address += cur_pages * PageSize;
|
||||
map_pages -= cur_pages;
|
||||
|
||||
pg_phys_addr += cur_pages * PageSize;
|
||||
pg_pages -= cur_pages;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1784,11 +1770,7 @@ Result KPageTable::MapPhysicalMemory(KProcessAddress address, size_t size) {
|
||||
m_memory_block_manager.UpdateIfMatch(
|
||||
std::addressof(allocator), address, size / PageSize, KMemoryState::Free,
|
||||
KMemoryPermission::None, KMemoryAttribute::None, KMemoryState::Normal,
|
||||
KMemoryPermission::UserReadWrite, KMemoryAttribute::None,
|
||||
address == this->GetAliasRegionStart()
|
||||
? KMemoryBlockDisableMergeAttribute::Normal
|
||||
: KMemoryBlockDisableMergeAttribute::None,
|
||||
KMemoryBlockDisableMergeAttribute::None);
|
||||
KMemoryPermission::UserReadWrite, KMemoryAttribute::None);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
@@ -1886,13 +1868,6 @@ Result KPageTable::UnmapPhysicalMemory(KProcessAddress address, size_t size) {
|
||||
|
||||
// Iterate over the memory, unmapping as we go.
|
||||
auto it = m_memory_block_manager.FindIterator(cur_address);
|
||||
|
||||
const auto clear_merge_attr =
|
||||
(it->GetState() == KMemoryState::Normal &&
|
||||
it->GetAddress() == this->GetAliasRegionStart() && it->GetAddress() == address)
|
||||
? KMemoryBlockDisableMergeAttribute::Normal
|
||||
: KMemoryBlockDisableMergeAttribute::None;
|
||||
|
||||
while (true) {
|
||||
// Check that the iterator is valid.
|
||||
ASSERT(it != m_memory_block_manager.end());
|
||||
@@ -1930,7 +1905,7 @@ Result KPageTable::UnmapPhysicalMemory(KProcessAddress address, size_t size) {
|
||||
m_memory_block_manager.Update(std::addressof(allocator), address, size / PageSize,
|
||||
KMemoryState::Free, KMemoryPermission::None,
|
||||
KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::None,
|
||||
clear_merge_attr);
|
||||
KMemoryBlockDisableMergeAttribute::None);
|
||||
|
||||
// We succeeded.
|
||||
R_SUCCEED();
|
||||
@@ -2404,7 +2379,8 @@ Result KPageTable::MapPageGroup(KProcessAddress* out_addr, const KPageGroup& pg,
|
||||
KScopedPageTableUpdater updater(this);
|
||||
|
||||
// Perform mapping operation.
|
||||
const KPageProperties properties = {perm, false, false, DisableMergeAttribute::DisableHead};
|
||||
const KPageProperties properties = {perm, state == KMemoryState::Io, false,
|
||||
DisableMergeAttribute::DisableHead};
|
||||
R_TRY(this->MapPageGroupImpl(updater.GetPageList(), addr, pg, properties, false));
|
||||
|
||||
// Update the blocks.
|
||||
@@ -2446,7 +2422,8 @@ Result KPageTable::MapPageGroup(KProcessAddress addr, const KPageGroup& pg, KMem
|
||||
KScopedPageTableUpdater updater(this);
|
||||
|
||||
// Perform mapping operation.
|
||||
const KPageProperties properties = {perm, false, false, DisableMergeAttribute::DisableHead};
|
||||
const KPageProperties properties = {perm, state == KMemoryState::Io, false,
|
||||
DisableMergeAttribute::DisableHead};
|
||||
R_TRY(this->MapPageGroupImpl(updater.GetPageList(), addr, pg, properties, false));
|
||||
|
||||
// Update the blocks.
|
||||
@@ -2675,18 +2652,11 @@ Result KPageTable::SetMemoryAttribute(KProcessAddress addr, size_t size, u32 mas
|
||||
size_t num_allocator_blocks;
|
||||
constexpr auto AttributeTestMask =
|
||||
~(KMemoryAttribute::SetMask | KMemoryAttribute::DeviceShared);
|
||||
const KMemoryState state_test_mask =
|
||||
static_cast<KMemoryState>(((mask & static_cast<u32>(KMemoryAttribute::Uncached))
|
||||
? static_cast<u32>(KMemoryState::FlagCanChangeAttribute)
|
||||
: 0) |
|
||||
((mask & static_cast<u32>(KMemoryAttribute::PermissionLocked))
|
||||
? static_cast<u32>(KMemoryState::FlagCanPermissionLock)
|
||||
: 0));
|
||||
R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm),
|
||||
std::addressof(old_attr), std::addressof(num_allocator_blocks),
|
||||
addr, size, state_test_mask, state_test_mask,
|
||||
KMemoryPermission::None, KMemoryPermission::None,
|
||||
AttributeTestMask, KMemoryAttribute::None, ~AttributeTestMask));
|
||||
R_TRY(this->CheckMemoryState(
|
||||
std::addressof(old_state), std::addressof(old_perm), std::addressof(old_attr),
|
||||
std::addressof(num_allocator_blocks), addr, size, KMemoryState::FlagCanChangeAttribute,
|
||||
KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None,
|
||||
AttributeTestMask, KMemoryAttribute::None, ~AttributeTestMask));
|
||||
|
||||
// Create an update allocator.
|
||||
Result allocator_result{ResultSuccess};
|
||||
@@ -2694,17 +2664,18 @@ Result KPageTable::SetMemoryAttribute(KProcessAddress addr, size_t size, u32 mas
|
||||
m_memory_block_slab_manager, num_allocator_blocks);
|
||||
R_TRY(allocator_result);
|
||||
|
||||
// If we need to, perform a change attribute operation.
|
||||
if (True(KMemoryAttribute::Uncached & static_cast<KMemoryAttribute>(mask))) {
|
||||
// Perform operation.
|
||||
R_TRY(this->Operate(addr, num_pages, old_perm,
|
||||
OperationType::ChangePermissionsAndRefreshAndFlush, 0));
|
||||
}
|
||||
// Determine the new attribute.
|
||||
const KMemoryAttribute new_attr =
|
||||
static_cast<KMemoryAttribute>(((old_attr & static_cast<KMemoryAttribute>(~mask)) |
|
||||
static_cast<KMemoryAttribute>(attr & mask)));
|
||||
|
||||
// Perform operation.
|
||||
this->Operate(addr, num_pages, old_perm, OperationType::ChangePermissionsAndRefresh);
|
||||
|
||||
// Update the blocks.
|
||||
m_memory_block_manager.UpdateAttribute(std::addressof(allocator), addr, num_pages,
|
||||
static_cast<KMemoryAttribute>(mask),
|
||||
static_cast<KMemoryAttribute>(attr));
|
||||
m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, old_state, old_perm,
|
||||
new_attr, KMemoryBlockDisableMergeAttribute::None,
|
||||
KMemoryBlockDisableMergeAttribute::None);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
@@ -2892,8 +2863,7 @@ Result KPageTable::LockForMapDeviceAddressSpace(bool* out_is_io, KProcessAddress
|
||||
&KMemoryBlock::ShareToDevice, KMemoryPermission::None);
|
||||
|
||||
// Set whether the locked memory was io.
|
||||
*out_is_io =
|
||||
static_cast<Svc::MemoryState>(old_state & KMemoryState::Mask) == Svc::MemoryState::Io;
|
||||
*out_is_io = old_state == KMemoryState::Io;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
@@ -3051,10 +3021,9 @@ Result KPageTable::Operate(KProcessAddress addr, size_t num_pages, const KPageGr
|
||||
ASSERT(num_pages == page_group.GetNumPages());
|
||||
|
||||
switch (operation) {
|
||||
case OperationType::MapGroup:
|
||||
case OperationType::MapFirstGroup: {
|
||||
case OperationType::MapGroup: {
|
||||
// We want to maintain a new reference to every page in the group.
|
||||
KScopedPageGroup spg(page_group, operation != OperationType::MapFirstGroup);
|
||||
KScopedPageGroup spg(page_group);
|
||||
|
||||
for (const auto& node : page_group) {
|
||||
const size_t size{node.GetNumPages() * PageSize};
|
||||
@@ -3096,6 +3065,7 @@ Result KPageTable::Operate(KProcessAddress addr, size_t num_pages, KMemoryPermis
|
||||
m_memory->UnmapRegion(*m_page_table_impl, addr, num_pages * PageSize);
|
||||
break;
|
||||
}
|
||||
case OperationType::MapFirst:
|
||||
case OperationType::Map: {
|
||||
ASSERT(map_addr);
|
||||
ASSERT(Common::IsAligned(GetInteger(map_addr), PageSize));
|
||||
@@ -3103,7 +3073,11 @@ Result KPageTable::Operate(KProcessAddress addr, size_t num_pages, KMemoryPermis
|
||||
|
||||
// Open references to pages, if we should.
|
||||
if (IsHeapPhysicalAddress(m_kernel.MemoryLayout(), map_addr)) {
|
||||
m_kernel.MemoryManager().Open(map_addr, num_pages);
|
||||
if (operation == OperationType::MapFirst) {
|
||||
m_kernel.MemoryManager().OpenFirst(map_addr, num_pages);
|
||||
} else {
|
||||
m_kernel.MemoryManager().Open(map_addr, num_pages);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -3113,7 +3087,6 @@ Result KPageTable::Operate(KProcessAddress addr, size_t num_pages, KMemoryPermis
|
||||
}
|
||||
case OperationType::ChangePermissions:
|
||||
case OperationType::ChangePermissionsAndRefresh:
|
||||
case OperationType::ChangePermissionsAndRefreshAndFlush:
|
||||
break;
|
||||
default:
|
||||
ASSERT(false);
|
||||
@@ -3133,79 +3106,79 @@ void KPageTable::FinalizeUpdate(PageLinkedList* page_list) {
|
||||
}
|
||||
}
|
||||
|
||||
KProcessAddress KPageTable::GetRegionAddress(Svc::MemoryState state) const {
|
||||
KProcessAddress KPageTable::GetRegionAddress(KMemoryState state) const {
|
||||
switch (state) {
|
||||
case Svc::MemoryState::Free:
|
||||
case Svc::MemoryState::Kernel:
|
||||
case KMemoryState::Free:
|
||||
case KMemoryState::Kernel:
|
||||
return m_address_space_start;
|
||||
case Svc::MemoryState::Normal:
|
||||
case KMemoryState::Normal:
|
||||
return m_heap_region_start;
|
||||
case Svc::MemoryState::Ipc:
|
||||
case Svc::MemoryState::NonSecureIpc:
|
||||
case Svc::MemoryState::NonDeviceIpc:
|
||||
case KMemoryState::Ipc:
|
||||
case KMemoryState::NonSecureIpc:
|
||||
case KMemoryState::NonDeviceIpc:
|
||||
return m_alias_region_start;
|
||||
case Svc::MemoryState::Stack:
|
||||
case KMemoryState::Stack:
|
||||
return m_stack_region_start;
|
||||
case Svc::MemoryState::Static:
|
||||
case Svc::MemoryState::ThreadLocal:
|
||||
case KMemoryState::Static:
|
||||
case KMemoryState::ThreadLocal:
|
||||
return m_kernel_map_region_start;
|
||||
case Svc::MemoryState::Io:
|
||||
case Svc::MemoryState::Shared:
|
||||
case Svc::MemoryState::AliasCode:
|
||||
case Svc::MemoryState::AliasCodeData:
|
||||
case Svc::MemoryState::Transfered:
|
||||
case Svc::MemoryState::SharedTransfered:
|
||||
case Svc::MemoryState::SharedCode:
|
||||
case Svc::MemoryState::GeneratedCode:
|
||||
case Svc::MemoryState::CodeOut:
|
||||
case Svc::MemoryState::Coverage:
|
||||
case Svc::MemoryState::Insecure:
|
||||
case KMemoryState::Io:
|
||||
case KMemoryState::Shared:
|
||||
case KMemoryState::AliasCode:
|
||||
case KMemoryState::AliasCodeData:
|
||||
case KMemoryState::Transfered:
|
||||
case KMemoryState::SharedTransfered:
|
||||
case KMemoryState::SharedCode:
|
||||
case KMemoryState::GeneratedCode:
|
||||
case KMemoryState::CodeOut:
|
||||
case KMemoryState::Coverage:
|
||||
case KMemoryState::Insecure:
|
||||
return m_alias_code_region_start;
|
||||
case Svc::MemoryState::Code:
|
||||
case Svc::MemoryState::CodeData:
|
||||
case KMemoryState::Code:
|
||||
case KMemoryState::CodeData:
|
||||
return m_code_region_start;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
size_t KPageTable::GetRegionSize(Svc::MemoryState state) const {
|
||||
size_t KPageTable::GetRegionSize(KMemoryState state) const {
|
||||
switch (state) {
|
||||
case Svc::MemoryState::Free:
|
||||
case Svc::MemoryState::Kernel:
|
||||
case KMemoryState::Free:
|
||||
case KMemoryState::Kernel:
|
||||
return m_address_space_end - m_address_space_start;
|
||||
case Svc::MemoryState::Normal:
|
||||
case KMemoryState::Normal:
|
||||
return m_heap_region_end - m_heap_region_start;
|
||||
case Svc::MemoryState::Ipc:
|
||||
case Svc::MemoryState::NonSecureIpc:
|
||||
case Svc::MemoryState::NonDeviceIpc:
|
||||
case KMemoryState::Ipc:
|
||||
case KMemoryState::NonSecureIpc:
|
||||
case KMemoryState::NonDeviceIpc:
|
||||
return m_alias_region_end - m_alias_region_start;
|
||||
case Svc::MemoryState::Stack:
|
||||
case KMemoryState::Stack:
|
||||
return m_stack_region_end - m_stack_region_start;
|
||||
case Svc::MemoryState::Static:
|
||||
case Svc::MemoryState::ThreadLocal:
|
||||
case KMemoryState::Static:
|
||||
case KMemoryState::ThreadLocal:
|
||||
return m_kernel_map_region_end - m_kernel_map_region_start;
|
||||
case Svc::MemoryState::Io:
|
||||
case Svc::MemoryState::Shared:
|
||||
case Svc::MemoryState::AliasCode:
|
||||
case Svc::MemoryState::AliasCodeData:
|
||||
case Svc::MemoryState::Transfered:
|
||||
case Svc::MemoryState::SharedTransfered:
|
||||
case Svc::MemoryState::SharedCode:
|
||||
case Svc::MemoryState::GeneratedCode:
|
||||
case Svc::MemoryState::CodeOut:
|
||||
case Svc::MemoryState::Coverage:
|
||||
case Svc::MemoryState::Insecure:
|
||||
case KMemoryState::Io:
|
||||
case KMemoryState::Shared:
|
||||
case KMemoryState::AliasCode:
|
||||
case KMemoryState::AliasCodeData:
|
||||
case KMemoryState::Transfered:
|
||||
case KMemoryState::SharedTransfered:
|
||||
case KMemoryState::SharedCode:
|
||||
case KMemoryState::GeneratedCode:
|
||||
case KMemoryState::CodeOut:
|
||||
case KMemoryState::Coverage:
|
||||
case KMemoryState::Insecure:
|
||||
return m_alias_code_region_end - m_alias_code_region_start;
|
||||
case Svc::MemoryState::Code:
|
||||
case Svc::MemoryState::CodeData:
|
||||
case KMemoryState::Code:
|
||||
case KMemoryState::CodeData:
|
||||
return m_code_region_end - m_code_region_start;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
bool KPageTable::CanContain(KProcessAddress addr, size_t size, Svc::MemoryState state) const {
|
||||
bool KPageTable::CanContain(KProcessAddress addr, size_t size, KMemoryState state) const {
|
||||
const KProcessAddress end = addr + size;
|
||||
const KProcessAddress last = end - 1;
|
||||
|
||||
@@ -3219,32 +3192,32 @@ bool KPageTable::CanContain(KProcessAddress addr, size_t size, Svc::MemoryState
|
||||
const bool is_in_alias = !(end <= m_alias_region_start || m_alias_region_end <= addr ||
|
||||
m_alias_region_start == m_alias_region_end);
|
||||
switch (state) {
|
||||
case Svc::MemoryState::Free:
|
||||
case Svc::MemoryState::Kernel:
|
||||
case KMemoryState::Free:
|
||||
case KMemoryState::Kernel:
|
||||
return is_in_region;
|
||||
case Svc::MemoryState::Io:
|
||||
case Svc::MemoryState::Static:
|
||||
case Svc::MemoryState::Code:
|
||||
case Svc::MemoryState::CodeData:
|
||||
case Svc::MemoryState::Shared:
|
||||
case Svc::MemoryState::AliasCode:
|
||||
case Svc::MemoryState::AliasCodeData:
|
||||
case Svc::MemoryState::Stack:
|
||||
case Svc::MemoryState::ThreadLocal:
|
||||
case Svc::MemoryState::Transfered:
|
||||
case Svc::MemoryState::SharedTransfered:
|
||||
case Svc::MemoryState::SharedCode:
|
||||
case Svc::MemoryState::GeneratedCode:
|
||||
case Svc::MemoryState::CodeOut:
|
||||
case Svc::MemoryState::Coverage:
|
||||
case Svc::MemoryState::Insecure:
|
||||
case KMemoryState::Io:
|
||||
case KMemoryState::Static:
|
||||
case KMemoryState::Code:
|
||||
case KMemoryState::CodeData:
|
||||
case KMemoryState::Shared:
|
||||
case KMemoryState::AliasCode:
|
||||
case KMemoryState::AliasCodeData:
|
||||
case KMemoryState::Stack:
|
||||
case KMemoryState::ThreadLocal:
|
||||
case KMemoryState::Transfered:
|
||||
case KMemoryState::SharedTransfered:
|
||||
case KMemoryState::SharedCode:
|
||||
case KMemoryState::GeneratedCode:
|
||||
case KMemoryState::CodeOut:
|
||||
case KMemoryState::Coverage:
|
||||
case KMemoryState::Insecure:
|
||||
return is_in_region && !is_in_heap && !is_in_alias;
|
||||
case Svc::MemoryState::Normal:
|
||||
case KMemoryState::Normal:
|
||||
ASSERT(is_in_heap);
|
||||
return is_in_region && !is_in_alias;
|
||||
case Svc::MemoryState::Ipc:
|
||||
case Svc::MemoryState::NonSecureIpc:
|
||||
case Svc::MemoryState::NonDeviceIpc:
|
||||
case KMemoryState::Ipc:
|
||||
case KMemoryState::NonSecureIpc:
|
||||
case KMemoryState::NonDeviceIpc:
|
||||
ASSERT(is_in_alias);
|
||||
return is_in_region && !is_in_heap;
|
||||
default:
|
||||
@@ -3308,16 +3281,21 @@ Result KPageTable::CheckMemoryStateContiguous(size_t* out_blocks_needed, KProces
|
||||
|
||||
Result KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm,
|
||||
KMemoryAttribute* out_attr, size_t* out_blocks_needed,
|
||||
KMemoryBlockManager::const_iterator it,
|
||||
KProcessAddress last_addr, KMemoryState state_mask,
|
||||
KProcessAddress addr, size_t size, KMemoryState state_mask,
|
||||
KMemoryState state, KMemoryPermission perm_mask,
|
||||
KMemoryPermission perm, KMemoryAttribute attr_mask,
|
||||
KMemoryAttribute attr, KMemoryAttribute ignore_attr) const {
|
||||
ASSERT(this->IsLockedByCurrentThread());
|
||||
|
||||
// Get information about the first block.
|
||||
const KProcessAddress last_addr = addr + size - 1;
|
||||
KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(addr);
|
||||
KMemoryInfo info = it->GetMemoryInfo();
|
||||
|
||||
// If the start address isn't aligned, we need a block.
|
||||
const size_t blocks_for_start_align =
|
||||
(Common::AlignDown(GetInteger(addr), PageSize) != info.GetAddress()) ? 1 : 0;
|
||||
|
||||
// Validate all blocks in the range have correct state.
|
||||
const KMemoryState first_state = info.m_state;
|
||||
const KMemoryPermission first_perm = info.m_permission;
|
||||
@@ -3343,6 +3321,10 @@ Result KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermission*
|
||||
info = it->GetMemoryInfo();
|
||||
}
|
||||
|
||||
// If the end address isn't aligned, we need a block.
|
||||
const size_t blocks_for_end_align =
|
||||
(Common::AlignUp(GetInteger(addr) + size, PageSize) != info.GetEndAddress()) ? 1 : 0;
|
||||
|
||||
// Write output state.
|
||||
if (out_state != nullptr) {
|
||||
*out_state = first_state;
|
||||
@@ -3353,39 +3335,9 @@ Result KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermission*
|
||||
if (out_attr != nullptr) {
|
||||
*out_attr = static_cast<KMemoryAttribute>(first_attr & ~ignore_attr);
|
||||
}
|
||||
|
||||
// If the end address isn't aligned, we need a block.
|
||||
if (out_blocks_needed != nullptr) {
|
||||
const size_t blocks_for_end_align =
|
||||
(Common::AlignDown(GetInteger(last_addr), PageSize) + PageSize != info.GetEndAddress())
|
||||
? 1
|
||||
: 0;
|
||||
*out_blocks_needed = blocks_for_end_align;
|
||||
*out_blocks_needed = blocks_for_start_align + blocks_for_end_align;
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm,
|
||||
KMemoryAttribute* out_attr, size_t* out_blocks_needed,
|
||||
KProcessAddress addr, size_t size, KMemoryState state_mask,
|
||||
KMemoryState state, KMemoryPermission perm_mask,
|
||||
KMemoryPermission perm, KMemoryAttribute attr_mask,
|
||||
KMemoryAttribute attr, KMemoryAttribute ignore_attr) const {
|
||||
ASSERT(this->IsLockedByCurrentThread());
|
||||
|
||||
// Check memory state.
|
||||
const KProcessAddress last_addr = addr + size - 1;
|
||||
KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(addr);
|
||||
R_TRY(this->CheckMemoryState(out_state, out_perm, out_attr, out_blocks_needed, it, last_addr,
|
||||
state_mask, state, perm_mask, perm, attr_mask, attr, ignore_attr));
|
||||
|
||||
// If the start address isn't aligned, we need a block.
|
||||
if (out_blocks_needed != nullptr &&
|
||||
Common::AlignDown(GetInteger(addr), PageSize) != it->GetAddress()) {
|
||||
++(*out_blocks_needed);
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
@@ -126,6 +126,8 @@ public:
|
||||
return m_block_info_manager;
|
||||
}
|
||||
|
||||
bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const;
|
||||
|
||||
Result MapPages(KProcessAddress* out_addr, size_t num_pages, size_t alignment,
|
||||
KPhysicalAddress phys_addr, KProcessAddress region_start,
|
||||
size_t region_num_pages, KMemoryState state, KMemoryPermission perm) {
|
||||
@@ -160,21 +162,6 @@ public:
|
||||
void RemapPageGroup(PageLinkedList* page_list, KProcessAddress address, size_t size,
|
||||
const KPageGroup& pg);
|
||||
|
||||
KProcessAddress GetRegionAddress(Svc::MemoryState state) const;
|
||||
size_t GetRegionSize(Svc::MemoryState state) const;
|
||||
bool CanContain(KProcessAddress addr, size_t size, Svc::MemoryState state) const;
|
||||
|
||||
KProcessAddress GetRegionAddress(KMemoryState state) const {
|
||||
return this->GetRegionAddress(static_cast<Svc::MemoryState>(state & KMemoryState::Mask));
|
||||
}
|
||||
size_t GetRegionSize(KMemoryState state) const {
|
||||
return this->GetRegionSize(static_cast<Svc::MemoryState>(state & KMemoryState::Mask));
|
||||
}
|
||||
bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const {
|
||||
return this->CanContain(addr, size,
|
||||
static_cast<Svc::MemoryState>(state & KMemoryState::Mask));
|
||||
}
|
||||
|
||||
protected:
|
||||
struct PageLinkedList {
|
||||
private:
|
||||
@@ -217,13 +204,12 @@ protected:
|
||||
private:
|
||||
enum class OperationType : u32 {
|
||||
Map = 0,
|
||||
MapGroup = 1,
|
||||
MapFirstGroup = 2,
|
||||
MapFirst = 1,
|
||||
MapGroup = 2,
|
||||
Unmap = 3,
|
||||
ChangePermissions = 4,
|
||||
ChangePermissionsAndRefresh = 5,
|
||||
ChangePermissionsAndRefreshAndFlush = 6,
|
||||
Separate = 7,
|
||||
Separate = 6,
|
||||
};
|
||||
|
||||
static constexpr KMemoryAttribute DefaultMemoryIgnoreAttr =
|
||||
@@ -242,6 +228,8 @@ private:
|
||||
Result Operate(KProcessAddress addr, size_t num_pages, KMemoryPermission perm,
|
||||
OperationType operation, KPhysicalAddress map_addr = 0);
|
||||
void FinalizeUpdate(PageLinkedList* page_list);
|
||||
KProcessAddress GetRegionAddress(KMemoryState state) const;
|
||||
size_t GetRegionSize(KMemoryState state) const;
|
||||
|
||||
KProcessAddress FindFreeArea(KProcessAddress region_start, size_t region_num_pages,
|
||||
size_t num_pages, size_t alignment, size_t offset,
|
||||
@@ -262,13 +250,6 @@ private:
|
||||
Result CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask, KMemoryState state,
|
||||
KMemoryPermission perm_mask, KMemoryPermission perm,
|
||||
KMemoryAttribute attr_mask, KMemoryAttribute attr) const;
|
||||
Result CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm,
|
||||
KMemoryAttribute* out_attr, size_t* out_blocks_needed,
|
||||
KMemoryBlockManager::const_iterator it, KProcessAddress last_addr,
|
||||
KMemoryState state_mask, KMemoryState state,
|
||||
KMemoryPermission perm_mask, KMemoryPermission perm,
|
||||
KMemoryAttribute attr_mask, KMemoryAttribute attr,
|
||||
KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) const;
|
||||
Result CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm,
|
||||
KMemoryAttribute* out_attr, size_t* out_blocks_needed,
|
||||
KProcessAddress addr, size_t size, KMemoryState state_mask,
|
||||
|
||||
@@ -149,7 +149,7 @@ u64 KProcess::GetTotalPhysicalMemoryUsed() {
|
||||
}
|
||||
|
||||
u64 KProcess::GetTotalPhysicalMemoryUsedWithoutSystemResource() {
|
||||
return this->GetTotalPhysicalMemoryUsed() - this->GetSystemResourceSize();
|
||||
return this->GetTotalPhysicalMemoryUsed() - this->GetSystemResourceUsage();
|
||||
}
|
||||
|
||||
bool KProcess::ReleaseUserException(KThread* thread) {
|
||||
|
||||
@@ -623,33 +623,14 @@ struct KernelCore::Impl {
|
||||
ASSERT(memory_layout->GetPhysicalMemoryRegionTree().Insert(
|
||||
GetInteger(slab_start_phys_addr), slab_region_size, KMemoryRegionType_DramKernelSlab));
|
||||
|
||||
// Insert a physical region for the secure applet memory.
|
||||
const auto secure_applet_end_phys_addr =
|
||||
slab_end_phys_addr + KSystemControl::SecureAppletMemorySize;
|
||||
if constexpr (KSystemControl::SecureAppletMemorySize > 0) {
|
||||
ASSERT(memory_layout->GetPhysicalMemoryRegionTree().Insert(
|
||||
GetInteger(slab_end_phys_addr), KSystemControl::SecureAppletMemorySize,
|
||||
KMemoryRegionType_DramKernelSecureAppletMemory));
|
||||
}
|
||||
|
||||
// Insert a physical region for the unknown debug2 region.
|
||||
constexpr size_t SecureUnknownRegionSize = 0;
|
||||
const size_t secure_unknown_size = SecureUnknownRegionSize;
|
||||
const auto secure_unknown_end_phys_addr = secure_applet_end_phys_addr + secure_unknown_size;
|
||||
if constexpr (SecureUnknownRegionSize > 0) {
|
||||
ASSERT(memory_layout->GetPhysicalMemoryRegionTree().Insert(
|
||||
GetInteger(secure_applet_end_phys_addr), secure_unknown_size,
|
||||
KMemoryRegionType_DramKernelSecureUnknown));
|
||||
}
|
||||
|
||||
// Determine size available for kernel page table heaps, requiring > 8 MB.
|
||||
const KPhysicalAddress resource_end_phys_addr = slab_start_phys_addr + resource_region_size;
|
||||
const size_t page_table_heap_size = resource_end_phys_addr - secure_unknown_end_phys_addr;
|
||||
const size_t page_table_heap_size = resource_end_phys_addr - slab_end_phys_addr;
|
||||
ASSERT(page_table_heap_size / 4_MiB > 2);
|
||||
|
||||
// Insert a physical region for the kernel page table heap region
|
||||
ASSERT(memory_layout->GetPhysicalMemoryRegionTree().Insert(
|
||||
GetInteger(secure_unknown_end_phys_addr), page_table_heap_size,
|
||||
GetInteger(slab_end_phys_addr), page_table_heap_size,
|
||||
KMemoryRegionType_DramKernelPtHeap));
|
||||
|
||||
// All DRAM regions that we haven't tagged by this point will be mapped under the linear
|
||||
|
||||
@@ -76,7 +76,7 @@ Result MapUnmapMemorySanityChecks(const KPageTable& manager, u64 dst_addr, u64 s
|
||||
} // namespace
|
||||
|
||||
Result SetMemoryPermission(Core::System& system, u64 address, u64 size, MemoryPermission perm) {
|
||||
LOG_DEBUG(Kernel_SVC, "called, address=0x{:016X}, size=0x{:X}, perm=0x{:08X}", address, size,
|
||||
LOG_DEBUG(Kernel_SVC, "called, address=0x{:016X}, size=0x{:X}, perm=0x{:08X", address, size,
|
||||
perm);
|
||||
|
||||
// Validate address / size.
|
||||
@@ -108,16 +108,10 @@ Result SetMemoryAttribute(Core::System& system, u64 address, u64 size, u32 mask,
|
||||
R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
|
||||
|
||||
// Validate the attribute and mask.
|
||||
constexpr u32 SupportedMask =
|
||||
static_cast<u32>(MemoryAttribute::Uncached | MemoryAttribute::PermissionLocked);
|
||||
constexpr u32 SupportedMask = static_cast<u32>(MemoryAttribute::Uncached);
|
||||
R_UNLESS((mask | attr) == mask, ResultInvalidCombination);
|
||||
R_UNLESS((mask | attr | SupportedMask) == SupportedMask, ResultInvalidCombination);
|
||||
|
||||
// Check that permission locked is either being set or not masked.
|
||||
R_UNLESS((static_cast<Svc::MemoryAttribute>(mask) & Svc::MemoryAttribute::PermissionLocked) ==
|
||||
(static_cast<Svc::MemoryAttribute>(attr) & Svc::MemoryAttribute::PermissionLocked),
|
||||
ResultInvalidCombination);
|
||||
|
||||
// Validate that the region is in range for the current process.
|
||||
auto& page_table{GetCurrentProcess(system.Kernel()).GetPageTable()};
|
||||
R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
|
||||
|
||||
@@ -46,7 +46,6 @@ enum class MemoryAttribute : u32 {
|
||||
IpcLocked = (1 << 1),
|
||||
DeviceShared = (1 << 2),
|
||||
Uncached = (1 << 3),
|
||||
PermissionLocked = (1 << 4),
|
||||
};
|
||||
DECLARE_ENUM_FLAG_OPERATORS(MemoryAttribute);
|
||||
|
||||
|
||||
@@ -25,12 +25,11 @@ void LoopProcess(Core::System& system) {
|
||||
server_manager->RegisterNamedService(
|
||||
"caps:u", std::make_shared<IAlbumApplicationService>(system, album_manager));
|
||||
|
||||
server_manager->RegisterNamedService(
|
||||
"caps:ss", std::make_shared<IScreenShotService>(system, album_manager));
|
||||
server_manager->RegisterNamedService("caps:ss", std::make_shared<IScreenShotService>(system));
|
||||
server_manager->RegisterNamedService("caps:sc",
|
||||
std::make_shared<IScreenShotControlService>(system));
|
||||
server_manager->RegisterNamedService(
|
||||
"caps:su", std::make_shared<IScreenShotApplicationService>(system, album_manager));
|
||||
server_manager->RegisterNamedService("caps:su",
|
||||
std::make_shared<IScreenShotApplicationService>(system));
|
||||
|
||||
ServerManager::RunServer(std::move(server_manager));
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include <sstream>
|
||||
#include <stb_image.h>
|
||||
#include <stb_image_resize.h>
|
||||
#include <stb_image_write.h>
|
||||
|
||||
#include "common/fs/file.h"
|
||||
#include "common/fs/path_util.h"
|
||||
@@ -228,49 +227,6 @@ Result AlbumManager::LoadAlbumScreenShotThumbnail(
|
||||
+static_cast<int>(out_image_output.height), decoder_options.flags);
|
||||
}
|
||||
|
||||
Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry,
|
||||
const ScreenShotAttribute& attribute,
|
||||
std::span<const u8> image_data, u64 aruid) {
|
||||
return SaveScreenShot(out_entry, attribute, {}, image_data, aruid);
|
||||
}
|
||||
|
||||
Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry,
|
||||
const ScreenShotAttribute& attribute,
|
||||
const ApplicationData& app_data, std::span<const u8> image_data,
|
||||
u64 aruid) {
|
||||
const u64 title_id = system.GetApplicationProcessProgramID();
|
||||
const auto& user_clock = system.GetTimeManager().GetStandardUserSystemClockCore();
|
||||
|
||||
s64 posix_time{};
|
||||
Result result = user_clock.GetCurrentTime(system, posix_time);
|
||||
|
||||
if (result.IsError()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const auto date = ConvertToAlbumDateTime(posix_time);
|
||||
|
||||
return SaveImage(out_entry, image_data, title_id, date);
|
||||
}
|
||||
|
||||
Result AlbumManager::SaveEditedScreenShot(ApplicationAlbumEntry& out_entry,
|
||||
const ScreenShotAttribute& attribute,
|
||||
const AlbumFileId& file_id,
|
||||
std::span<const u8> image_data) {
|
||||
const auto& user_clock = system.GetTimeManager().GetStandardUserSystemClockCore();
|
||||
|
||||
s64 posix_time{};
|
||||
Result result = user_clock.GetCurrentTime(system, posix_time);
|
||||
|
||||
if (result.IsError()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const auto date = ConvertToAlbumDateTime(posix_time);
|
||||
|
||||
return SaveImage(out_entry, image_data, file_id.application_id, date);
|
||||
}
|
||||
|
||||
Result AlbumManager::GetFile(std::filesystem::path& out_path, const AlbumFileId& file_id) const {
|
||||
const auto file = album_files.find(file_id);
|
||||
|
||||
@@ -409,45 +365,6 @@ Result AlbumManager::LoadImage(std::span<u8> out_image, const std::filesystem::p
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result AlbumManager::SaveImage(ApplicationAlbumEntry& out_entry, std::span<const u8> image,
|
||||
u64 title_id, const AlbumFileDateTime& date) const {
|
||||
const auto screenshot_path =
|
||||
Common::FS::GetYuzuPathString(Common::FS::YuzuPath::ScreenshotsDir);
|
||||
const std::string formatted_date =
|
||||
fmt::format("{:04}-{:02}-{:02}_{:02}-{:02}-{:02}-{:03}", date.year, date.month, date.day,
|
||||
date.hour, date.minute, date.second, 0);
|
||||
const std::string file_path =
|
||||
fmt::format("{}/{:016x}_{}.png", screenshot_path, title_id, formatted_date);
|
||||
|
||||
const Common::FS::IOFile db_file{file_path, Common::FS::FileAccessMode::Write,
|
||||
Common::FS::FileType::BinaryFile};
|
||||
|
||||
s32 len;
|
||||
const u8* png = stbi_write_png_to_mem(image.data(), 0, 1280, 720, STBI_rgb_alpha, &len);
|
||||
|
||||
if (!png) {
|
||||
return ResultFileCountLimit;
|
||||
}
|
||||
|
||||
std::vector<u8> png_image(len);
|
||||
std::memcpy(png_image.data(), png, len);
|
||||
|
||||
if (db_file.Write(png_image) != png_image.size()) {
|
||||
return ResultFileCountLimit;
|
||||
}
|
||||
|
||||
out_entry = {
|
||||
.size = png_image.size(),
|
||||
.hash = {},
|
||||
.datetime = date,
|
||||
.storage = AlbumStorage::Sd,
|
||||
.content = ContentType::Screenshot,
|
||||
.unknown = 1,
|
||||
};
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
AlbumFileDateTime AlbumManager::ConvertToAlbumDateTime(u64 posix_time) const {
|
||||
Time::TimeZone::CalendarInfo calendar_date{};
|
||||
const auto& time_zone_manager =
|
||||
|
||||
@@ -58,15 +58,6 @@ public:
|
||||
std::vector<u8>& out_image, const AlbumFileId& file_id,
|
||||
const ScreenShotDecodeOption& decoder_options) const;
|
||||
|
||||
Result SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute,
|
||||
std::span<const u8> image_data, u64 aruid);
|
||||
Result SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute,
|
||||
const ApplicationData& app_data, std::span<const u8> image_data,
|
||||
u64 aruid);
|
||||
Result SaveEditedScreenShot(ApplicationAlbumEntry& out_entry,
|
||||
const ScreenShotAttribute& attribute, const AlbumFileId& file_id,
|
||||
std::span<const u8> image_data);
|
||||
|
||||
private:
|
||||
static constexpr std::size_t NandAlbumFileLimit = 1000;
|
||||
static constexpr std::size_t SdAlbumFileLimit = 10000;
|
||||
@@ -76,8 +67,6 @@ private:
|
||||
Result GetAlbumEntry(AlbumEntry& out_entry, const std::filesystem::path& path) const;
|
||||
Result LoadImage(std::span<u8> out_image, const std::filesystem::path& path, int width,
|
||||
int height, ScreenShotDecoderFlag flag) const;
|
||||
Result SaveImage(ApplicationAlbumEntry& out_entry, std::span<const u8> image, u64 title_id,
|
||||
const AlbumFileDateTime& date) const;
|
||||
|
||||
AlbumFileDateTime ConvertToAlbumDateTime(u64 posix_time) const;
|
||||
|
||||
|
||||
@@ -1,25 +1,19 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/service/caps/caps_manager.h"
|
||||
#include "core/hle/service/caps/caps_types.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
|
||||
#include "core/hle/service/caps/caps_ss.h"
|
||||
|
||||
namespace Service::Capture {
|
||||
|
||||
IScreenShotService::IScreenShotService(Core::System& system_,
|
||||
std::shared_ptr<AlbumManager> album_manager)
|
||||
: ServiceFramework{system_, "caps:ss"}, manager{album_manager} {
|
||||
IScreenShotService::IScreenShotService(Core::System& system_)
|
||||
: ServiceFramework{system_, "caps:ss"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{201, nullptr, "SaveScreenShot"},
|
||||
{202, nullptr, "SaveEditedScreenShot"},
|
||||
{203, &IScreenShotService::SaveScreenShotEx0, "SaveScreenShotEx0"},
|
||||
{203, nullptr, "SaveScreenShotEx0"},
|
||||
{204, nullptr, "SaveEditedScreenShotEx0"},
|
||||
{206, &IScreenShotService::SaveEditedScreenShotEx1, "SaveEditedScreenShotEx1"},
|
||||
{206, nullptr, "Unknown206"},
|
||||
{208, nullptr, "SaveScreenShotOfMovieEx1"},
|
||||
{1000, nullptr, "Unknown1000"},
|
||||
};
|
||||
@@ -30,65 +24,4 @@ IScreenShotService::IScreenShotService(Core::System& system_,
|
||||
|
||||
IScreenShotService::~IScreenShotService() = default;
|
||||
|
||||
void IScreenShotService::SaveScreenShotEx0(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
ScreenShotAttribute attribute{};
|
||||
u32 report_option{};
|
||||
INSERT_PADDING_BYTES(0x4);
|
||||
u64 applet_resource_user_id{};
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x50, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
const auto image_data_buffer = ctx.ReadBuffer();
|
||||
|
||||
LOG_INFO(Service_Capture,
|
||||
"called, report_option={}, image_data_buffer_size={}, applet_resource_user_id={}",
|
||||
parameters.report_option, image_data_buffer.size(),
|
||||
parameters.applet_resource_user_id);
|
||||
|
||||
ApplicationAlbumEntry entry{};
|
||||
const auto result = manager->SaveScreenShot(entry, parameters.attribute, image_data_buffer,
|
||||
parameters.applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 10};
|
||||
rb.Push(result);
|
||||
rb.PushRaw(entry);
|
||||
}
|
||||
void IScreenShotService::SaveEditedScreenShotEx1(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
ScreenShotAttribute attribute;
|
||||
u64 width;
|
||||
u64 height;
|
||||
u64 thumbnail_width;
|
||||
u64 thumbnail_height;
|
||||
AlbumFileId file_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x78, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
const auto application_data_buffer = ctx.ReadBuffer(0);
|
||||
const auto image_data_buffer = ctx.ReadBuffer(1);
|
||||
const auto thumbnail_image_data_buffer = ctx.ReadBuffer(2);
|
||||
|
||||
LOG_INFO(Service_Capture,
|
||||
"called, width={}, height={}, thumbnail_width={}, thumbnail_height={}, "
|
||||
"application_id={:016x}, storage={}, type={}, app_data_buffer_size={}, "
|
||||
"image_data_buffer_size={}, thumbnail_image_buffer_size={}",
|
||||
parameters.width, parameters.height, parameters.thumbnail_width,
|
||||
parameters.thumbnail_height, parameters.file_id.application_id,
|
||||
parameters.file_id.storage, parameters.file_id.type, application_data_buffer.size(),
|
||||
image_data_buffer.size(), thumbnail_image_data_buffer.size());
|
||||
|
||||
ApplicationAlbumEntry entry{};
|
||||
const auto result = manager->SaveEditedScreenShot(entry, parameters.attribute,
|
||||
parameters.file_id, image_data_buffer);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 10};
|
||||
rb.Push(result);
|
||||
rb.PushRaw(entry);
|
||||
}
|
||||
|
||||
} // namespace Service::Capture
|
||||
|
||||
@@ -13,14 +13,8 @@ namespace Service::Capture {
|
||||
|
||||
class IScreenShotService final : public ServiceFramework<IScreenShotService> {
|
||||
public:
|
||||
explicit IScreenShotService(Core::System& system_, std::shared_ptr<AlbumManager> album_manager);
|
||||
explicit IScreenShotService(Core::System& system_);
|
||||
~IScreenShotService() override;
|
||||
|
||||
private:
|
||||
void SaveScreenShotEx0(HLERequestContext& ctx);
|
||||
void SaveEditedScreenShotEx1(HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<AlbumManager> manager;
|
||||
};
|
||||
|
||||
} // namespace Service::Capture
|
||||
|
||||
@@ -2,22 +2,19 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/service/caps/caps_manager.h"
|
||||
#include "core/hle/service/caps/caps_su.h"
|
||||
#include "core/hle/service/caps/caps_types.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
|
||||
namespace Service::Capture {
|
||||
|
||||
IScreenShotApplicationService::IScreenShotApplicationService(
|
||||
Core::System& system_, std::shared_ptr<AlbumManager> album_manager)
|
||||
: ServiceFramework{system_, "caps:su"}, manager{album_manager} {
|
||||
IScreenShotApplicationService::IScreenShotApplicationService(Core::System& system_)
|
||||
: ServiceFramework{system_, "caps:su"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{32, &IScreenShotApplicationService::SetShimLibraryVersion, "SetShimLibraryVersion"},
|
||||
{201, nullptr, "SaveScreenShot"},
|
||||
{203, &IScreenShotApplicationService::SaveScreenShotEx0, "SaveScreenShotEx0"},
|
||||
{205, &IScreenShotApplicationService::SaveScreenShotEx1, "SaveScreenShotEx1"},
|
||||
{203, nullptr, "SaveScreenShotEx0"},
|
||||
{205, nullptr, "SaveScreenShotEx1"},
|
||||
{210, nullptr, "SaveScreenShotEx2"},
|
||||
};
|
||||
// clang-format on
|
||||
@@ -39,62 +36,4 @@ void IScreenShotApplicationService::SetShimLibraryVersion(HLERequestContext& ctx
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IScreenShotApplicationService::SaveScreenShotEx0(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
ScreenShotAttribute attribute{};
|
||||
AlbumReportOption report_option{};
|
||||
INSERT_PADDING_BYTES(0x4);
|
||||
u64 applet_resource_user_id{};
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x50, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
const auto image_data_buffer = ctx.ReadBuffer();
|
||||
|
||||
LOG_INFO(Service_Capture,
|
||||
"called, report_option={}, image_data_buffer_size={}, applet_resource_user_id={}",
|
||||
parameters.report_option, image_data_buffer.size(),
|
||||
parameters.applet_resource_user_id);
|
||||
|
||||
ApplicationAlbumEntry entry{};
|
||||
const auto result = manager->SaveScreenShot(entry, parameters.attribute, image_data_buffer,
|
||||
parameters.applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 10};
|
||||
rb.Push(result);
|
||||
rb.PushRaw(entry);
|
||||
}
|
||||
|
||||
void IScreenShotApplicationService::SaveScreenShotEx1(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
ScreenShotAttribute attribute{};
|
||||
AlbumReportOption report_option{};
|
||||
INSERT_PADDING_BYTES(0x4);
|
||||
u64 applet_resource_user_id{};
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x50, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
const auto app_data_buffer = ctx.ReadBuffer(0);
|
||||
const auto image_data_buffer = ctx.ReadBuffer(1);
|
||||
|
||||
LOG_INFO(Service_Capture,
|
||||
"called, report_option={}, image_data_buffer_size={}, applet_resource_user_id={}",
|
||||
parameters.report_option, image_data_buffer.size(),
|
||||
parameters.applet_resource_user_id);
|
||||
|
||||
ApplicationAlbumEntry entry{};
|
||||
ApplicationData app_data{};
|
||||
std::memcpy(&app_data, app_data_buffer.data(), sizeof(ApplicationData));
|
||||
const auto result =
|
||||
manager->SaveScreenShot(entry, parameters.attribute, app_data, image_data_buffer,
|
||||
parameters.applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 10};
|
||||
rb.Push(result);
|
||||
rb.PushRaw(entry);
|
||||
}
|
||||
|
||||
} // namespace Service::Capture
|
||||
|
||||
@@ -10,20 +10,14 @@ class System;
|
||||
}
|
||||
|
||||
namespace Service::Capture {
|
||||
class AlbumManager;
|
||||
|
||||
class IScreenShotApplicationService final : public ServiceFramework<IScreenShotApplicationService> {
|
||||
public:
|
||||
explicit IScreenShotApplicationService(Core::System& system_,
|
||||
std::shared_ptr<AlbumManager> album_manager);
|
||||
explicit IScreenShotApplicationService(Core::System& system_);
|
||||
~IScreenShotApplicationService() override;
|
||||
|
||||
private:
|
||||
void SetShimLibraryVersion(HLERequestContext& ctx);
|
||||
void SaveScreenShotEx0(HLERequestContext& ctx);
|
||||
void SaveScreenShotEx1(HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<AlbumManager> manager;
|
||||
};
|
||||
|
||||
} // namespace Service::Capture
|
||||
|
||||
@@ -20,8 +20,6 @@ enum class AlbumImageOrientation {
|
||||
enum class AlbumReportOption : s32 {
|
||||
Disable,
|
||||
Enable,
|
||||
Unknown2,
|
||||
Unknown3,
|
||||
};
|
||||
|
||||
enum class ContentType : u8 {
|
||||
|
||||
@@ -27,12 +27,10 @@ namespace {
|
||||
static thread_local std::array read_buffer_data_a{
|
||||
Common::ScratchBuffer<u8>(),
|
||||
Common::ScratchBuffer<u8>(),
|
||||
Common::ScratchBuffer<u8>(),
|
||||
};
|
||||
static thread_local std::array read_buffer_data_x{
|
||||
Common::ScratchBuffer<u8>(),
|
||||
Common::ScratchBuffer<u8>(),
|
||||
Common::ScratchBuffer<u8>(),
|
||||
};
|
||||
} // Anonymous namespace
|
||||
|
||||
@@ -345,7 +343,6 @@ std::span<const u8> HLERequestContext::ReadBufferA(std::size_t buffer_index) con
|
||||
static thread_local std::array read_buffer_a{
|
||||
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
|
||||
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
|
||||
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
|
||||
};
|
||||
|
||||
ASSERT_OR_EXECUTE_MSG(
|
||||
@@ -361,7 +358,6 @@ std::span<const u8> HLERequestContext::ReadBufferX(std::size_t buffer_index) con
|
||||
static thread_local std::array read_buffer_x{
|
||||
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
|
||||
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
|
||||
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
|
||||
};
|
||||
|
||||
ASSERT_OR_EXECUTE_MSG(
|
||||
@@ -377,12 +373,10 @@ std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) cons
|
||||
static thread_local std::array read_buffer_a{
|
||||
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
|
||||
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
|
||||
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
|
||||
};
|
||||
static thread_local std::array read_buffer_x{
|
||||
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
|
||||
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
|
||||
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
|
||||
};
|
||||
|
||||
const bool is_buffer_a{BufferDescriptorA().size() > buffer_index &&
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
#include <vector>
|
||||
|
||||
#include "common/concepts.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvdevice.h"
|
||||
|
||||
namespace Service::Nvidia::Devices {
|
||||
|
||||
struct IoctlOneArgTraits {
|
||||
template <typename T, typename R, typename A, typename... B>
|
||||
static A GetFirstArgImpl(R (T::*)(A, B...));
|
||||
};
|
||||
|
||||
struct IoctlTwoArgTraits {
|
||||
template <typename T, typename R, typename A, typename B, typename... C>
|
||||
static A GetFirstArgImpl(R (T::*)(A, B, C...));
|
||||
|
||||
template <typename T, typename R, typename A, typename B, typename... C>
|
||||
static B GetSecondArgImpl(R (T::*)(A, B, C...));
|
||||
};
|
||||
|
||||
struct Null {};
|
||||
|
||||
// clang-format off
|
||||
|
||||
template <typename FixedArg, typename VarArg, typename InlInVarArg, typename InlOutVarArg, typename F>
|
||||
NvResult WrapGeneric(F&& callable, std::span<const u8> input, std::span<const u8> inline_input, std::span<u8> output, std::span<u8> inline_output) {
|
||||
constexpr bool HasFixedArg = !std::is_same_v<FixedArg, Null>;
|
||||
constexpr bool HasVarArg = !std::is_same_v<VarArg, Null>;
|
||||
constexpr bool HasInlInVarArg = !std::is_same_v<InlInVarArg, Null>;
|
||||
constexpr bool HasInlOutVarArg = !std::is_same_v<InlOutVarArg, Null>;
|
||||
|
||||
// Declare the fixed-size input value.
|
||||
FixedArg fixed{};
|
||||
size_t var_offset = 0;
|
||||
|
||||
if constexpr (HasFixedArg) {
|
||||
// Read the fixed-size input value.
|
||||
var_offset = std::min(sizeof(FixedArg), input.size());
|
||||
if (var_offset > 0) {
|
||||
std::memcpy(&fixed, input.data(), var_offset);
|
||||
}
|
||||
}
|
||||
|
||||
// Read the variable-sized inputs.
|
||||
const size_t num_var_args = HasVarArg ? ((input.size() - var_offset) / sizeof(VarArg)) : 0;
|
||||
std::vector<VarArg> var_args(num_var_args);
|
||||
if constexpr (HasVarArg) {
|
||||
if (num_var_args > 0) {
|
||||
std::memcpy(var_args.data(), input.data() + var_offset, num_var_args * sizeof(VarArg));
|
||||
}
|
||||
}
|
||||
|
||||
const size_t num_inl_in_var_args = HasInlInVarArg ? (inline_input.size() / sizeof(InlInVarArg)) : 0;
|
||||
std::vector<InlInVarArg> inl_in_var_args(num_inl_in_var_args);
|
||||
if constexpr (HasInlInVarArg) {
|
||||
if (num_inl_in_var_args > 0) {
|
||||
std::memcpy(inl_in_var_args.data(), inline_input.data(), num_inl_in_var_args * sizeof(InlInVarArg));
|
||||
}
|
||||
}
|
||||
|
||||
// Construct inline output data.
|
||||
const size_t num_inl_out_var_args = HasInlOutVarArg ? (inline_output.size() / sizeof(InlOutVarArg)) : 0;
|
||||
std::vector<InlOutVarArg> inl_out_var_args(num_inl_out_var_args);
|
||||
|
||||
// Perform the call.
|
||||
NvResult result = callable(fixed, var_args, inl_in_var_args, inl_out_var_args);
|
||||
|
||||
// Copy outputs.
|
||||
if constexpr (HasFixedArg) {
|
||||
if (output.size() > 0) {
|
||||
std::memcpy(output.data(), &fixed, std::min(output.size(), sizeof(FixedArg)));
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (HasVarArg) {
|
||||
if (num_var_args > 0 && output.size() > var_offset) {
|
||||
const size_t max_var_size = output.size() - var_offset;
|
||||
std::memcpy(output.data() + var_offset, var_args.data(), std::min(max_var_size, num_var_args * sizeof(VarArg)));
|
||||
}
|
||||
}
|
||||
|
||||
// Copy inline outputs.
|
||||
if constexpr (HasInlOutVarArg) {
|
||||
if (num_inl_out_var_args > 0) {
|
||||
std::memcpy(inline_output.data(), inl_out_var_args.data(), num_inl_out_var_args * sizeof(InlOutVarArg));
|
||||
}
|
||||
}
|
||||
|
||||
// We're done.
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename Self, typename F, typename... Rest>
|
||||
NvResult WrapFixed(Self* self, F&& callable, std::span<const u8> input, std::span<u8> output, Rest&&... rest) {
|
||||
using FixedArg = typename std::remove_reference_t<decltype(IoctlOneArgTraits::GetFirstArgImpl(callable))>;
|
||||
|
||||
const auto Callable = [&](auto& fixed, auto& var, auto& inl_in, auto& inl_out) -> NvResult {
|
||||
return (self->*callable)(fixed, std::forward<Rest>(rest)...);
|
||||
};
|
||||
|
||||
return WrapGeneric<FixedArg, Null, Null, Null>(std::move(Callable), input, {}, output, {});
|
||||
}
|
||||
|
||||
template <typename Self, typename F, typename... Rest>
|
||||
NvResult WrapFixedInlOut(Self* self, F&& callable, std::span<const u8> input, std::span<u8> output, std::span<u8> inline_output, Rest&&... rest) {
|
||||
using FixedArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetFirstArgImpl(callable))>;
|
||||
using InlOutVarArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetSecondArgImpl(callable))>::value_type;
|
||||
|
||||
const auto Callable = [&](auto& fixed, auto& var, auto& inl_in, auto& inl_out) -> NvResult {
|
||||
return (self->*callable)(fixed, inl_out, std::forward<Rest>(rest)...);
|
||||
};
|
||||
|
||||
return WrapGeneric<FixedArg, Null, Null, InlOutVarArg>(std::move(Callable), input, {}, output, inline_output);
|
||||
}
|
||||
|
||||
template <typename Self, typename F, typename... Rest>
|
||||
NvResult WrapVariable(Self* self, F&& callable, std::span<const u8> input, std::span<u8> output, Rest&&... rest) {
|
||||
using VarArg = typename std::remove_reference_t<decltype(IoctlOneArgTraits::GetFirstArgImpl(callable))>::value_type;
|
||||
|
||||
const auto Callable = [&](auto& fixed, auto& var, auto& inl_in, auto& inl_out) -> NvResult {
|
||||
return (self->*callable)(var, std::forward<Rest>(rest)...);
|
||||
};
|
||||
|
||||
return WrapGeneric<Null, VarArg, Null, Null>(std::move(Callable), input, {}, output, {});
|
||||
}
|
||||
|
||||
template <typename Self, typename F, typename... Rest>
|
||||
NvResult WrapFixedVariable(Self* self, F&& callable, std::span<const u8> input, std::span<u8> output, Rest&&... rest) {
|
||||
using FixedArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetFirstArgImpl(callable))>;
|
||||
using VarArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetSecondArgImpl(callable))>::value_type;
|
||||
|
||||
const auto Callable = [&](auto& fixed, auto& var, auto& inl_in, auto& inl_out) -> NvResult {
|
||||
return (self->*callable)(fixed, var, std::forward<Rest>(rest)...);
|
||||
};
|
||||
|
||||
return WrapGeneric<FixedArg, VarArg, Null, Null>(std::move(Callable), input, {}, output, {});
|
||||
}
|
||||
|
||||
template <typename Self, typename F, typename... Rest>
|
||||
NvResult WrapFixedInlIn(Self* self, F&& callable, std::span<const u8> input, std::span<const u8> inline_input, std::span<u8> output, Rest&&... rest) {
|
||||
using FixedArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetFirstArgImpl(callable))>;
|
||||
using InlInVarArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetSecondArgImpl(callable))>::value_type;
|
||||
|
||||
const auto Callable = [&](auto& fixed, auto& var, auto& inl_in, auto& inl_out) -> NvResult {
|
||||
return (self->*callable)(fixed, inl_in, std::forward<Rest>(rest)...);
|
||||
};
|
||||
|
||||
return WrapGeneric<FixedArg, Null, InlInVarArg, Null>(std::move(Callable), input, inline_input, output, {});
|
||||
}
|
||||
|
||||
// clang-format on
|
||||
|
||||
} // namespace Service::Nvidia::Devices
|
||||
@@ -11,7 +11,6 @@
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/nvdrv/core/container.h"
|
||||
#include "core/hle/service/nvdrv/core/nvmap.h"
|
||||
#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvhost_gpu.h"
|
||||
#include "core/hle/service/nvdrv/nvdrv.h"
|
||||
@@ -34,21 +33,21 @@ NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> i
|
||||
case 'A':
|
||||
switch (command.cmd) {
|
||||
case 0x1:
|
||||
return WrapFixed(this, &nvhost_as_gpu::BindChannel, input, output);
|
||||
return BindChannel(input, output);
|
||||
case 0x2:
|
||||
return WrapFixed(this, &nvhost_as_gpu::AllocateSpace, input, output);
|
||||
return AllocateSpace(input, output);
|
||||
case 0x3:
|
||||
return WrapFixed(this, &nvhost_as_gpu::FreeSpace, input, output);
|
||||
return FreeSpace(input, output);
|
||||
case 0x5:
|
||||
return WrapFixed(this, &nvhost_as_gpu::UnmapBuffer, input, output);
|
||||
return UnmapBuffer(input, output);
|
||||
case 0x6:
|
||||
return WrapFixed(this, &nvhost_as_gpu::MapBufferEx, input, output);
|
||||
return MapBufferEx(input, output);
|
||||
case 0x8:
|
||||
return WrapFixed(this, &nvhost_as_gpu::GetVARegions1, input, output);
|
||||
return GetVARegions(input, output);
|
||||
case 0x9:
|
||||
return WrapFixed(this, &nvhost_as_gpu::AllocAsEx, input, output);
|
||||
return AllocAsEx(input, output);
|
||||
case 0x14:
|
||||
return WrapVariable(this, &nvhost_as_gpu::Remap, input, output);
|
||||
return Remap(input, output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -73,8 +72,7 @@ NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> i
|
||||
case 'A':
|
||||
switch (command.cmd) {
|
||||
case 0x8:
|
||||
return WrapFixedInlOut(this, &nvhost_as_gpu::GetVARegions3, input, output,
|
||||
inline_output);
|
||||
return GetVARegions(input, output, inline_output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -89,7 +87,10 @@ NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> i
|
||||
void nvhost_as_gpu::OnOpen(DeviceFD fd) {}
|
||||
void nvhost_as_gpu::OnClose(DeviceFD fd) {}
|
||||
|
||||
NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) {
|
||||
NvResult nvhost_as_gpu::AllocAsEx(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlAllocAsEx params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
LOG_DEBUG(Service_NVDRV, "called, big_page_size=0x{:X}", params.big_page_size);
|
||||
|
||||
std::scoped_lock lock(mutex);
|
||||
@@ -140,7 +141,10 @@ NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) {
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::AllocateSpace(IoctlAllocSpace& params) {
|
||||
NvResult nvhost_as_gpu::AllocateSpace(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlAllocSpace params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
LOG_DEBUG(Service_NVDRV, "called, pages={:X}, page_size={:X}, flags={:X}", params.pages,
|
||||
params.page_size, params.flags);
|
||||
|
||||
@@ -190,6 +194,7 @@ NvResult nvhost_as_gpu::AllocateSpace(IoctlAllocSpace& params) {
|
||||
.big_pages = params.page_size != VM::YUZU_PAGESIZE,
|
||||
};
|
||||
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
@@ -217,7 +222,10 @@ void nvhost_as_gpu::FreeMappingLocked(u64 offset) {
|
||||
mapping_map.erase(offset);
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::FreeSpace(IoctlFreeSpace& params) {
|
||||
NvResult nvhost_as_gpu::FreeSpace(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlFreeSpace params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
LOG_DEBUG(Service_NVDRV, "called, offset={:X}, pages={:X}, page_size={:X}", params.offset,
|
||||
params.pages, params.page_size);
|
||||
|
||||
@@ -256,11 +264,18 @@ NvResult nvhost_as_gpu::FreeSpace(IoctlFreeSpace& params) {
|
||||
return NvResult::BadValue;
|
||||
}
|
||||
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::Remap(std::span<IoctlRemapEntry> entries) {
|
||||
LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", entries.size());
|
||||
NvResult nvhost_as_gpu::Remap(std::span<const u8> input, std::span<u8> output) {
|
||||
const auto num_entries = input.size() / sizeof(IoctlRemapEntry);
|
||||
|
||||
LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries);
|
||||
|
||||
std::scoped_lock lock(mutex);
|
||||
entries.resize_destructive(num_entries);
|
||||
std::memcpy(entries.data(), input.data(), input.size());
|
||||
|
||||
if (!vm.initialised) {
|
||||
return NvResult::BadValue;
|
||||
@@ -302,10 +317,14 @@ NvResult nvhost_as_gpu::Remap(std::span<IoctlRemapEntry> entries) {
|
||||
}
|
||||
}
|
||||
|
||||
std::memcpy(output.data(), entries.data(), output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) {
|
||||
NvResult nvhost_as_gpu::MapBufferEx(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlMapBufferEx params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
LOG_DEBUG(Service_NVDRV,
|
||||
"called, flags={:X}, nvmap_handle={:X}, buffer_offset={}, mapping_size={}"
|
||||
", offset={}",
|
||||
@@ -402,10 +421,14 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) {
|
||||
mapping_map[params.offset] = mapping;
|
||||
}
|
||||
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::UnmapBuffer(IoctlUnmapBuffer& params) {
|
||||
NvResult nvhost_as_gpu::UnmapBuffer(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlUnmapBuffer params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
LOG_DEBUG(Service_NVDRV, "called, offset=0x{:X}", params.offset);
|
||||
|
||||
std::scoped_lock lock(mutex);
|
||||
@@ -441,7 +464,9 @@ NvResult nvhost_as_gpu::UnmapBuffer(IoctlUnmapBuffer& params) {
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::BindChannel(IoctlBindChannel& params) {
|
||||
NvResult nvhost_as_gpu::BindChannel(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlBindChannel params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd);
|
||||
|
||||
auto gpu_channel_device = module.GetDevice<nvhost_gpu>(params.fd);
|
||||
@@ -468,7 +493,10 @@ void nvhost_as_gpu::GetVARegionsImpl(IoctlGetVaRegions& params) {
|
||||
};
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::GetVARegions1(IoctlGetVaRegions& params) {
|
||||
NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlGetVaRegions params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
LOG_DEBUG(Service_NVDRV, "called, buf_addr={:X}, buf_size={:X}", params.buf_addr,
|
||||
params.buf_size);
|
||||
|
||||
@@ -480,10 +508,15 @@ NvResult nvhost_as_gpu::GetVARegions1(IoctlGetVaRegions& params) {
|
||||
|
||||
GetVARegionsImpl(params);
|
||||
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::GetVARegions3(IoctlGetVaRegions& params, std::span<VaRegion> regions) {
|
||||
NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::span<u8> output,
|
||||
std::span<u8> inline_output) {
|
||||
IoctlGetVaRegions params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
LOG_DEBUG(Service_NVDRV, "called, buf_addr={:X}, buf_size={:X}", params.buf_addr,
|
||||
params.buf_size);
|
||||
|
||||
@@ -495,10 +528,9 @@ NvResult nvhost_as_gpu::GetVARegions3(IoctlGetVaRegions& params, std::span<VaReg
|
||||
|
||||
GetVARegionsImpl(params);
|
||||
|
||||
const size_t num_regions = std::min(params.regions.size(), regions.size());
|
||||
for (size_t i = 0; i < num_regions; i++) {
|
||||
regions[i] = params.regions[i];
|
||||
}
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
std::memcpy(inline_output.data(), ¶ms.regions[0], sizeof(VaRegion));
|
||||
std::memcpy(inline_output.data() + sizeof(VaRegion), ¶ms.regions[1], sizeof(VaRegion));
|
||||
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
@@ -139,17 +139,18 @@ private:
|
||||
static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(VaRegion) * 2,
|
||||
"IoctlGetVaRegions is incorrect size");
|
||||
|
||||
NvResult AllocAsEx(IoctlAllocAsEx& params);
|
||||
NvResult AllocateSpace(IoctlAllocSpace& params);
|
||||
NvResult Remap(std::span<IoctlRemapEntry> params);
|
||||
NvResult MapBufferEx(IoctlMapBufferEx& params);
|
||||
NvResult UnmapBuffer(IoctlUnmapBuffer& params);
|
||||
NvResult FreeSpace(IoctlFreeSpace& params);
|
||||
NvResult BindChannel(IoctlBindChannel& params);
|
||||
NvResult AllocAsEx(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult AllocateSpace(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult Remap(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult MapBufferEx(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult UnmapBuffer(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult FreeSpace(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult BindChannel(std::span<const u8> input, std::span<u8> output);
|
||||
|
||||
void GetVARegionsImpl(IoctlGetVaRegions& params);
|
||||
NvResult GetVARegions1(IoctlGetVaRegions& params);
|
||||
NvResult GetVARegions3(IoctlGetVaRegions& params, std::span<VaRegion> regions);
|
||||
NvResult GetVARegions(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult GetVARegions(std::span<const u8> input, std::span<u8> output,
|
||||
std::span<u8> inline_output);
|
||||
|
||||
void FreeMappingLocked(u64 offset);
|
||||
|
||||
@@ -212,6 +213,7 @@ private:
|
||||
bool initialised{};
|
||||
} vm;
|
||||
std::shared_ptr<Tegra::MemoryManager> gmmu;
|
||||
Common::ScratchBuffer<IoctlRemapEntry> entries;
|
||||
|
||||
// s32 channel{};
|
||||
// u32 big_page_size{VM::DEFAULT_BIG_PAGE_SIZE};
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/service/nvdrv/core/container.h"
|
||||
#include "core/hle/service/nvdrv/core/syncpoint_manager.h"
|
||||
#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvhost_ctrl.h"
|
||||
#include "video_core/gpu.h"
|
||||
#include "video_core/host1x/host1x.h"
|
||||
@@ -41,19 +40,19 @@ NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inp
|
||||
case 0x0:
|
||||
switch (command.cmd) {
|
||||
case 0x1b:
|
||||
return WrapFixed(this, &nvhost_ctrl::NvOsGetConfigU32, input, output);
|
||||
return NvOsGetConfigU32(input, output);
|
||||
case 0x1c:
|
||||
return WrapFixed(this, &nvhost_ctrl::IocCtrlClearEventWait, input, output);
|
||||
return IocCtrlClearEventWait(input, output);
|
||||
case 0x1d:
|
||||
return WrapFixed(this, &nvhost_ctrl::IocCtrlEventWait, input, output, true);
|
||||
return IocCtrlEventWait(input, output, true);
|
||||
case 0x1e:
|
||||
return WrapFixed(this, &nvhost_ctrl::IocCtrlEventWait, input, output, false);
|
||||
return IocCtrlEventWait(input, output, false);
|
||||
case 0x1f:
|
||||
return WrapFixed(this, &nvhost_ctrl::IocCtrlEventRegister, input, output);
|
||||
return IocCtrlEventRegister(input, output);
|
||||
case 0x20:
|
||||
return WrapFixed(this, &nvhost_ctrl::IocCtrlEventUnregister, input, output);
|
||||
return IocCtrlEventUnregister(input, output);
|
||||
case 0x21:
|
||||
return WrapFixed(this, &nvhost_ctrl::IocCtrlEventUnregisterBatch, input, output);
|
||||
return IocCtrlEventUnregisterBatch(input, output);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -80,19 +79,25 @@ void nvhost_ctrl::OnOpen(DeviceFD fd) {}
|
||||
|
||||
void nvhost_ctrl::OnClose(DeviceFD fd) {}
|
||||
|
||||
NvResult nvhost_ctrl::NvOsGetConfigU32(IocGetConfigParams& params) {
|
||||
NvResult nvhost_ctrl::NvOsGetConfigU32(std::span<const u8> input, std::span<u8> output) {
|
||||
IocGetConfigParams params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
LOG_TRACE(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(),
|
||||
params.param_str.data());
|
||||
return NvResult::ConfigVarNotFound; // Returns error on production mode
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl::IocCtrlEventWait(IocCtrlEventWaitParams& params, bool is_allocation) {
|
||||
NvResult nvhost_ctrl::IocCtrlEventWait(std::span<const u8> input, std::span<u8> output,
|
||||
bool is_allocation) {
|
||||
IocCtrlEventWaitParams params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_allocation={}",
|
||||
params.fence.id, params.fence.value, params.timeout, is_allocation);
|
||||
|
||||
bool must_unmark_fail = !is_allocation;
|
||||
const u32 event_id = params.value.raw;
|
||||
SCOPE_EXIT({
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
if (must_unmark_fail) {
|
||||
events[event_id].fails = 0;
|
||||
}
|
||||
@@ -226,7 +231,9 @@ NvResult nvhost_ctrl::FreeEvent(u32 slot) {
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl::IocCtrlEventRegister(IocCtrlEventRegisterParams& params) {
|
||||
NvResult nvhost_ctrl::IocCtrlEventRegister(std::span<const u8> input, std::span<u8> output) {
|
||||
IocCtrlEventRegisterParams params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
const u32 event_id = params.user_event_id;
|
||||
LOG_DEBUG(Service_NVDRV, " called, user_event_id: {:X}", event_id);
|
||||
if (event_id >= MaxNvEvents) {
|
||||
@@ -245,7 +252,9 @@ NvResult nvhost_ctrl::IocCtrlEventRegister(IocCtrlEventRegisterParams& params) {
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl::IocCtrlEventUnregister(IocCtrlEventUnregisterParams& params) {
|
||||
NvResult nvhost_ctrl::IocCtrlEventUnregister(std::span<const u8> input, std::span<u8> output) {
|
||||
IocCtrlEventUnregisterParams params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
const u32 event_id = params.user_event_id & 0x00FF;
|
||||
LOG_DEBUG(Service_NVDRV, " called, user_event_id: {:X}", event_id);
|
||||
|
||||
@@ -253,7 +262,9 @@ NvResult nvhost_ctrl::IocCtrlEventUnregister(IocCtrlEventUnregisterParams& param
|
||||
return FreeEvent(event_id);
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(IocCtrlEventUnregisterBatchParams& params) {
|
||||
NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(std::span<const u8> input, std::span<u8> output) {
|
||||
IocCtrlEventUnregisterBatchParams params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
u64 event_mask = params.user_events;
|
||||
LOG_DEBUG(Service_NVDRV, " called, event_mask: {:X}", event_mask);
|
||||
|
||||
@@ -269,7 +280,10 @@ NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(IocCtrlEventUnregisterBatchPar
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl::IocCtrlClearEventWait(IocCtrlEventClearParams& params) {
|
||||
NvResult nvhost_ctrl::IocCtrlClearEventWait(std::span<const u8> input, std::span<u8> output) {
|
||||
IocCtrlEventClearParams params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
|
||||
u32 event_id = params.event_id.slot;
|
||||
LOG_DEBUG(Service_NVDRV, "called, event_id: {:X}", event_id);
|
||||
|
||||
|
||||
@@ -186,12 +186,12 @@ private:
|
||||
static_assert(sizeof(IocCtrlEventUnregisterBatchParams) == 8,
|
||||
"IocCtrlEventKill is incorrect size");
|
||||
|
||||
NvResult NvOsGetConfigU32(IocGetConfigParams& params);
|
||||
NvResult IocCtrlEventRegister(IocCtrlEventRegisterParams& params);
|
||||
NvResult IocCtrlEventUnregister(IocCtrlEventUnregisterParams& params);
|
||||
NvResult IocCtrlEventUnregisterBatch(IocCtrlEventUnregisterBatchParams& params);
|
||||
NvResult IocCtrlEventWait(IocCtrlEventWaitParams& params, bool is_allocation);
|
||||
NvResult IocCtrlClearEventWait(IocCtrlEventClearParams& params);
|
||||
NvResult NvOsGetConfigU32(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult IocCtrlEventWait(std::span<const u8> input, std::span<u8> output, bool is_allocation);
|
||||
NvResult IocCtrlEventRegister(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult IocCtrlEventUnregister(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult IocCtrlEventUnregisterBatch(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult IocCtrlClearEventWait(std::span<const u8> input, std::span<u8> output);
|
||||
|
||||
NvResult FreeEvent(u32 slot);
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h"
|
||||
#include "core/hle/service/nvdrv/nvdrv.h"
|
||||
|
||||
@@ -28,23 +27,23 @@ NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8>
|
||||
case 'G':
|
||||
switch (command.cmd) {
|
||||
case 0x1:
|
||||
return WrapFixed(this, &nvhost_ctrl_gpu::ZCullGetCtxSize, input, output);
|
||||
return ZCullGetCtxSize(input, output);
|
||||
case 0x2:
|
||||
return WrapFixed(this, &nvhost_ctrl_gpu::ZCullGetInfo, input, output);
|
||||
return ZCullGetInfo(input, output);
|
||||
case 0x3:
|
||||
return WrapFixed(this, &nvhost_ctrl_gpu::ZBCSetTable, input, output);
|
||||
return ZBCSetTable(input, output);
|
||||
case 0x4:
|
||||
return WrapFixed(this, &nvhost_ctrl_gpu::ZBCQueryTable, input, output);
|
||||
return ZBCQueryTable(input, output);
|
||||
case 0x5:
|
||||
return WrapFixed(this, &nvhost_ctrl_gpu::GetCharacteristics1, input, output);
|
||||
return GetCharacteristics(input, output);
|
||||
case 0x6:
|
||||
return WrapFixed(this, &nvhost_ctrl_gpu::GetTPCMasks1, input, output);
|
||||
return GetTPCMasks(input, output);
|
||||
case 0x7:
|
||||
return WrapFixed(this, &nvhost_ctrl_gpu::FlushL2, input, output);
|
||||
return FlushL2(input, output);
|
||||
case 0x14:
|
||||
return WrapFixed(this, &nvhost_ctrl_gpu::GetActiveSlotMask, input, output);
|
||||
return GetActiveSlotMask(input, output);
|
||||
case 0x1c:
|
||||
return WrapFixed(this, &nvhost_ctrl_gpu::GetGpuTime, input, output);
|
||||
return GetGpuTime(input, output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -66,11 +65,9 @@ NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8>
|
||||
case 'G':
|
||||
switch (command.cmd) {
|
||||
case 0x5:
|
||||
return WrapFixedInlOut(this, &nvhost_ctrl_gpu::GetCharacteristics3, input, output,
|
||||
inline_output);
|
||||
return GetCharacteristics(input, output, inline_output);
|
||||
case 0x6:
|
||||
return WrapFixedInlOut(this, &nvhost_ctrl_gpu::GetTPCMasks3, input, output,
|
||||
inline_output);
|
||||
return GetTPCMasks(input, output, inline_output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -85,8 +82,10 @@ NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8>
|
||||
void nvhost_ctrl_gpu::OnOpen(DeviceFD fd) {}
|
||||
void nvhost_ctrl_gpu::OnClose(DeviceFD fd) {}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::GetCharacteristics1(IoctlCharacteristics& params) {
|
||||
NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::span<u8> output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
IoctlCharacteristics params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
params.gc.arch = 0x120;
|
||||
params.gc.impl = 0xb;
|
||||
params.gc.rev = 0xa1;
|
||||
@@ -124,13 +123,15 @@ NvResult nvhost_ctrl_gpu::GetCharacteristics1(IoctlCharacteristics& params) {
|
||||
params.gc.gr_compbit_store_base_hw = 0x0;
|
||||
params.gpu_characteristics_buf_size = 0xA0;
|
||||
params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED)
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::GetCharacteristics3(
|
||||
IoctlCharacteristics& params, std::span<IoctlGpuCharacteristics> gpu_characteristics) {
|
||||
NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::span<u8> output,
|
||||
std::span<u8> inline_output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlCharacteristics params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
params.gc.arch = 0x120;
|
||||
params.gc.impl = 0xb;
|
||||
params.gc.rev = 0xa1;
|
||||
@@ -168,47 +169,70 @@ NvResult nvhost_ctrl_gpu::GetCharacteristics3(
|
||||
params.gc.gr_compbit_store_base_hw = 0x0;
|
||||
params.gpu_characteristics_buf_size = 0xA0;
|
||||
params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED)
|
||||
if (!gpu_characteristics.empty()) {
|
||||
gpu_characteristics.front() = params.gc;
|
||||
}
|
||||
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
std::memcpy(inline_output.data(), ¶ms.gc, inline_output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::GetTPCMasks1(IoctlGpuGetTpcMasksArgs& params) {
|
||||
NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlGpuGetTpcMasksArgs params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size);
|
||||
if (params.mask_buffer_size != 0) {
|
||||
params.tcp_mask = 3;
|
||||
}
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::GetTPCMasks3(IoctlGpuGetTpcMasksArgs& params, std::span<u32> tpc_mask) {
|
||||
NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span<const u8> input, std::span<u8> output,
|
||||
std::span<u8> inline_output) {
|
||||
IoctlGpuGetTpcMasksArgs params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size);
|
||||
if (params.mask_buffer_size != 0) {
|
||||
params.tcp_mask = 3;
|
||||
}
|
||||
if (!tpc_mask.empty()) {
|
||||
tpc_mask.front() = params.tcp_mask;
|
||||
}
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
std::memcpy(inline_output.data(), ¶ms.tcp_mask, inline_output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::GetActiveSlotMask(IoctlActiveSlotMask& params) {
|
||||
NvResult nvhost_ctrl_gpu::GetActiveSlotMask(std::span<const u8> input, std::span<u8> output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlActiveSlotMask params{};
|
||||
if (input.size() > 0) {
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
}
|
||||
params.slot = 0x07;
|
||||
params.mask = 0x01;
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(IoctlZcullGetCtxSize& params) {
|
||||
NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(std::span<const u8> input, std::span<u8> output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlZcullGetCtxSize params{};
|
||||
if (input.size() > 0) {
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
}
|
||||
params.size = 0x1;
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::ZCullGetInfo(IoctlNvgpuGpuZcullGetInfoArgs& params) {
|
||||
NvResult nvhost_ctrl_gpu::ZCullGetInfo(std::span<const u8> input, std::span<u8> output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlNvgpuGpuZcullGetInfoArgs params{};
|
||||
|
||||
if (input.size() > 0) {
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
}
|
||||
|
||||
params.width_align_pixels = 0x20;
|
||||
params.height_align_pixels = 0x20;
|
||||
params.pixel_squares_by_aliquots = 0x400;
|
||||
@@ -219,28 +243,53 @@ NvResult nvhost_ctrl_gpu::ZCullGetInfo(IoctlNvgpuGpuZcullGetInfoArgs& params) {
|
||||
params.subregion_width_align_pixels = 0x20;
|
||||
params.subregion_height_align_pixels = 0x40;
|
||||
params.subregion_count = 0x10;
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::ZBCSetTable(IoctlZbcSetTable& params) {
|
||||
NvResult nvhost_ctrl_gpu::ZBCSetTable(std::span<const u8> input, std::span<u8> output) {
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
|
||||
IoctlZbcSetTable params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
// TODO(ogniK): What does this even actually do?
|
||||
|
||||
// Prevent null pointer being passed as arg 1
|
||||
if (output.empty()) {
|
||||
LOG_WARNING(Service_NVDRV, "Avoiding passing null pointer to memcpy");
|
||||
} else {
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
}
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::ZBCQueryTable(IoctlZbcQueryTable& params) {
|
||||
NvResult nvhost_ctrl_gpu::ZBCQueryTable(std::span<const u8> input, std::span<u8> output) {
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
|
||||
IoctlZbcQueryTable params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
// TODO : To implement properly
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::FlushL2(IoctlFlushL2& params) {
|
||||
NvResult nvhost_ctrl_gpu::FlushL2(std::span<const u8> input, std::span<u8> output) {
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
|
||||
IoctlFlushL2 params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
// TODO : To implement properly
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::GetGpuTime(IoctlGetGpuTime& params) {
|
||||
NvResult nvhost_ctrl_gpu::GetGpuTime(std::span<const u8> input, std::span<u8> output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlGetGpuTime params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
params.gpu_time = static_cast<u64_le>(system.CoreTiming().GetGlobalTimeNs().count());
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
|
||||
@@ -151,20 +151,21 @@ private:
|
||||
};
|
||||
static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size");
|
||||
|
||||
NvResult GetCharacteristics1(IoctlCharacteristics& params);
|
||||
NvResult GetCharacteristics3(IoctlCharacteristics& params,
|
||||
std::span<IoctlGpuCharacteristics> gpu_characteristics);
|
||||
NvResult GetCharacteristics(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult GetCharacteristics(std::span<const u8> input, std::span<u8> output,
|
||||
std::span<u8> inline_output);
|
||||
|
||||
NvResult GetTPCMasks1(IoctlGpuGetTpcMasksArgs& params);
|
||||
NvResult GetTPCMasks3(IoctlGpuGetTpcMasksArgs& params, std::span<u32> tpc_mask);
|
||||
NvResult GetTPCMasks(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult GetTPCMasks(std::span<const u8> input, std::span<u8> output,
|
||||
std::span<u8> inline_output);
|
||||
|
||||
NvResult GetActiveSlotMask(IoctlActiveSlotMask& params);
|
||||
NvResult ZCullGetCtxSize(IoctlZcullGetCtxSize& params);
|
||||
NvResult ZCullGetInfo(IoctlNvgpuGpuZcullGetInfoArgs& params);
|
||||
NvResult ZBCSetTable(IoctlZbcSetTable& params);
|
||||
NvResult ZBCQueryTable(IoctlZbcQueryTable& params);
|
||||
NvResult FlushL2(IoctlFlushL2& params);
|
||||
NvResult GetGpuTime(IoctlGetGpuTime& params);
|
||||
NvResult GetActiveSlotMask(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult ZCullGetCtxSize(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult ZCullGetInfo(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult ZBCSetTable(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult ZBCQueryTable(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult FlushL2(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult GetGpuTime(std::span<const u8> input, std::span<u8> output);
|
||||
|
||||
EventInterface& events_interface;
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include "core/hle/service/nvdrv/core/container.h"
|
||||
#include "core/hle/service/nvdrv/core/nvmap.h"
|
||||
#include "core/hle/service/nvdrv/core/syncpoint_manager.h"
|
||||
#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvhost_gpu.h"
|
||||
#include "core/hle/service/nvdrv/nvdrv.h"
|
||||
#include "core/memory.h"
|
||||
@@ -53,7 +52,7 @@ NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
|
||||
case 0x0:
|
||||
switch (command.cmd) {
|
||||
case 0x3:
|
||||
return WrapFixed(this, &nvhost_gpu::GetWaitbase, input, output);
|
||||
return GetWaitbase(input, output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -61,25 +60,25 @@ NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
|
||||
case 'H':
|
||||
switch (command.cmd) {
|
||||
case 0x1:
|
||||
return WrapFixed(this, &nvhost_gpu::SetNVMAPfd, input, output);
|
||||
return SetNVMAPfd(input, output);
|
||||
case 0x3:
|
||||
return WrapFixed(this, &nvhost_gpu::ChannelSetTimeout, input, output);
|
||||
return ChannelSetTimeout(input, output);
|
||||
case 0x8:
|
||||
return WrapFixedVariable(this, &nvhost_gpu::SubmitGPFIFOBase1, input, output, false);
|
||||
return SubmitGPFIFOBase(input, output, false);
|
||||
case 0x9:
|
||||
return WrapFixed(this, &nvhost_gpu::AllocateObjectContext, input, output);
|
||||
return AllocateObjectContext(input, output);
|
||||
case 0xb:
|
||||
return WrapFixed(this, &nvhost_gpu::ZCullBind, input, output);
|
||||
return ZCullBind(input, output);
|
||||
case 0xc:
|
||||
return WrapFixed(this, &nvhost_gpu::SetErrorNotifier, input, output);
|
||||
return SetErrorNotifier(input, output);
|
||||
case 0xd:
|
||||
return WrapFixed(this, &nvhost_gpu::SetChannelPriority, input, output);
|
||||
return SetChannelPriority(input, output);
|
||||
case 0x1a:
|
||||
return WrapFixed(this, &nvhost_gpu::AllocGPFIFOEx2, input, output);
|
||||
return AllocGPFIFOEx2(input, output);
|
||||
case 0x1b:
|
||||
return WrapFixedVariable(this, &nvhost_gpu::SubmitGPFIFOBase1, input, output, true);
|
||||
return SubmitGPFIFOBase(input, output, true);
|
||||
case 0x1d:
|
||||
return WrapFixed(this, &nvhost_gpu::ChannelSetTimeslice, input, output);
|
||||
return ChannelSetTimeslice(input, output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -87,9 +86,9 @@ NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
|
||||
case 'G':
|
||||
switch (command.cmd) {
|
||||
case 0x14:
|
||||
return WrapFixed(this, &nvhost_gpu::SetClientData, input, output);
|
||||
return SetClientData(input, output);
|
||||
case 0x15:
|
||||
return WrapFixed(this, &nvhost_gpu::GetClientData, input, output);
|
||||
return GetClientData(input, output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -105,8 +104,7 @@ NvResult nvhost_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> inpu
|
||||
case 'H':
|
||||
switch (command.cmd) {
|
||||
case 0x1b:
|
||||
return WrapFixedInlIn(this, &nvhost_gpu::SubmitGPFIFOBase2, input, inline_input,
|
||||
output);
|
||||
return SubmitGPFIFOBase(input, inline_input, output);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -123,45 +121,63 @@ NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> inpu
|
||||
void nvhost_gpu::OnOpen(DeviceFD fd) {}
|
||||
void nvhost_gpu::OnClose(DeviceFD fd) {}
|
||||
|
||||
NvResult nvhost_gpu::SetNVMAPfd(IoctlSetNvmapFD& params) {
|
||||
NvResult nvhost_gpu::SetNVMAPfd(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlSetNvmapFD params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
|
||||
|
||||
nvmap_fd = params.nvmap_fd;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::SetClientData(IoctlClientData& params) {
|
||||
NvResult nvhost_gpu::SetClientData(std::span<const u8> input, std::span<u8> output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlClientData params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
user_data = params.data;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::GetClientData(IoctlClientData& params) {
|
||||
NvResult nvhost_gpu::GetClientData(std::span<const u8> input, std::span<u8> output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlClientData params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
params.data = user_data;
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::ZCullBind(IoctlZCullBind& params) {
|
||||
zcull_params = params;
|
||||
NvResult nvhost_gpu::ZCullBind(std::span<const u8> input, std::span<u8> output) {
|
||||
std::memcpy(&zcull_params, input.data(), input.size());
|
||||
LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va,
|
||||
zcull_params.mode);
|
||||
|
||||
std::memcpy(output.data(), &zcull_params, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::SetErrorNotifier(IoctlSetErrorNotifier& params) {
|
||||
NvResult nvhost_gpu::SetErrorNotifier(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlSetErrorNotifier params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset,
|
||||
params.size, params.mem);
|
||||
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::SetChannelPriority(IoctlChannelSetPriority& params) {
|
||||
channel_priority = params.priority;
|
||||
NvResult nvhost_gpu::SetChannelPriority(std::span<const u8> input, std::span<u8> output) {
|
||||
std::memcpy(&channel_priority, input.data(), input.size());
|
||||
LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority);
|
||||
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::AllocGPFIFOEx2(IoctlAllocGpfifoEx2& params) {
|
||||
NvResult nvhost_gpu::AllocGPFIFOEx2(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlAllocGpfifoEx2 params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_WARNING(Service_NVDRV,
|
||||
"(STUBBED) called, num_entries={:X}, flags={:X}, unk0={:X}, "
|
||||
"unk1={:X}, unk2={:X}, unk3={:X}",
|
||||
@@ -177,14 +193,18 @@ NvResult nvhost_gpu::AllocGPFIFOEx2(IoctlAllocGpfifoEx2& params) {
|
||||
|
||||
params.fence_out = syncpoint_manager.GetSyncpointFence(channel_syncpoint);
|
||||
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::AllocateObjectContext(IoctlAllocObjCtx& params) {
|
||||
NvResult nvhost_gpu::AllocateObjectContext(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlAllocObjCtx params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num,
|
||||
params.flags);
|
||||
|
||||
params.obj_id = 0x0;
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
@@ -228,7 +248,8 @@ static boost::container::small_vector<Tegra::CommandHeader, 512> BuildIncrementW
|
||||
return result;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandList&& entries) {
|
||||
NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::span<u8> output,
|
||||
Tegra::CommandList&& entries) {
|
||||
LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address,
|
||||
params.num_entries, params.flags.raw);
|
||||
|
||||
@@ -269,55 +290,65 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandL
|
||||
|
||||
flags.raw = 0;
|
||||
|
||||
std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmitGpfifo));
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::SubmitGPFIFOBase1(IoctlSubmitGpfifo& params,
|
||||
std::span<Tegra::CommandListHeader> commands, bool kickoff) {
|
||||
if (params.num_entries > commands.size()) {
|
||||
NvResult nvhost_gpu::SubmitGPFIFOBase(std::span<const u8> input, std::span<u8> output,
|
||||
bool kickoff) {
|
||||
if (input.size() < sizeof(IoctlSubmitGpfifo)) {
|
||||
UNIMPLEMENTED();
|
||||
return NvResult::InvalidSize;
|
||||
}
|
||||
|
||||
IoctlSubmitGpfifo params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo));
|
||||
Tegra::CommandList entries(params.num_entries);
|
||||
|
||||
if (kickoff) {
|
||||
system.ApplicationMemory().ReadBlock(params.address, entries.command_lists.data(),
|
||||
params.num_entries * sizeof(Tegra::CommandListHeader));
|
||||
} else {
|
||||
std::memcpy(entries.command_lists.data(), commands.data(),
|
||||
std::memcpy(entries.command_lists.data(), &input[sizeof(IoctlSubmitGpfifo)],
|
||||
params.num_entries * sizeof(Tegra::CommandListHeader));
|
||||
}
|
||||
|
||||
return SubmitGPFIFOImpl(params, std::move(entries));
|
||||
return SubmitGPFIFOImpl(params, output, std::move(entries));
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::SubmitGPFIFOBase2(IoctlSubmitGpfifo& params,
|
||||
std::span<const Tegra::CommandListHeader> commands) {
|
||||
if (params.num_entries > commands.size()) {
|
||||
NvResult nvhost_gpu::SubmitGPFIFOBase(std::span<const u8> input, std::span<const u8> input_inline,
|
||||
std::span<u8> output) {
|
||||
if (input.size() < sizeof(IoctlSubmitGpfifo)) {
|
||||
UNIMPLEMENTED();
|
||||
return NvResult::InvalidSize;
|
||||
}
|
||||
|
||||
IoctlSubmitGpfifo params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo));
|
||||
Tegra::CommandList entries(params.num_entries);
|
||||
std::memcpy(entries.command_lists.data(), commands.data(),
|
||||
params.num_entries * sizeof(Tegra::CommandListHeader));
|
||||
return SubmitGPFIFOImpl(params, std::move(entries));
|
||||
std::memcpy(entries.command_lists.data(), input_inline.data(), input_inline.size());
|
||||
return SubmitGPFIFOImpl(params, output, std::move(entries));
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::GetWaitbase(IoctlGetWaitbase& params) {
|
||||
NvResult nvhost_gpu::GetWaitbase(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlGetWaitbase params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase));
|
||||
LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
|
||||
|
||||
params.value = 0; // Seems to be hard coded at 0
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::ChannelSetTimeout(IoctlChannelSetTimeout& params) {
|
||||
NvResult nvhost_gpu::ChannelSetTimeout(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlChannelSetTimeout params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlChannelSetTimeout));
|
||||
LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout);
|
||||
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::ChannelSetTimeslice(IoctlSetTimeslice& params) {
|
||||
NvResult nvhost_gpu::ChannelSetTimeslice(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlSetTimeslice params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlSetTimeslice));
|
||||
LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice);
|
||||
|
||||
channel_timeslice = params.timeslice;
|
||||
|
||||
@@ -186,24 +186,23 @@ private:
|
||||
u32_le channel_priority{};
|
||||
u32_le channel_timeslice{};
|
||||
|
||||
NvResult SetNVMAPfd(IoctlSetNvmapFD& params);
|
||||
NvResult SetClientData(IoctlClientData& params);
|
||||
NvResult GetClientData(IoctlClientData& params);
|
||||
NvResult ZCullBind(IoctlZCullBind& params);
|
||||
NvResult SetErrorNotifier(IoctlSetErrorNotifier& params);
|
||||
NvResult SetChannelPriority(IoctlChannelSetPriority& params);
|
||||
NvResult AllocGPFIFOEx2(IoctlAllocGpfifoEx2& params);
|
||||
NvResult AllocateObjectContext(IoctlAllocObjCtx& params);
|
||||
|
||||
NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandList&& entries);
|
||||
NvResult SubmitGPFIFOBase1(IoctlSubmitGpfifo& params,
|
||||
std::span<Tegra::CommandListHeader> commands, bool kickoff = false);
|
||||
NvResult SubmitGPFIFOBase2(IoctlSubmitGpfifo& params,
|
||||
std::span<const Tegra::CommandListHeader> commands);
|
||||
|
||||
NvResult GetWaitbase(IoctlGetWaitbase& params);
|
||||
NvResult ChannelSetTimeout(IoctlChannelSetTimeout& params);
|
||||
NvResult ChannelSetTimeslice(IoctlSetTimeslice& params);
|
||||
NvResult SetNVMAPfd(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult SetClientData(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult GetClientData(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult ZCullBind(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult SetErrorNotifier(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult SetChannelPriority(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult AllocGPFIFOEx2(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult AllocateObjectContext(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::span<u8> output,
|
||||
Tegra::CommandList&& entries);
|
||||
NvResult SubmitGPFIFOBase(std::span<const u8> input, std::span<u8> output,
|
||||
bool kickoff = false);
|
||||
NvResult SubmitGPFIFOBase(std::span<const u8> input, std::span<const u8> input_inline,
|
||||
std::span<u8> output);
|
||||
NvResult GetWaitbase(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult ChannelSetTimeout(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult ChannelSetTimeslice(std::span<const u8> input, std::span<u8> output);
|
||||
|
||||
EventInterface& events_interface;
|
||||
NvCore::Container& core;
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/nvdrv/core/container.h"
|
||||
#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
|
||||
@@ -26,18 +25,18 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> in
|
||||
if (!host1x_file.fd_to_id.contains(fd)) {
|
||||
host1x_file.fd_to_id[fd] = host1x_file.nvdec_next_id++;
|
||||
}
|
||||
return WrapFixedVariable(this, &nvhost_nvdec::Submit, input, output, fd);
|
||||
return Submit(fd, input, output);
|
||||
}
|
||||
case 0x2:
|
||||
return WrapFixed(this, &nvhost_nvdec::GetSyncpoint, input, output);
|
||||
return GetSyncpoint(input, output);
|
||||
case 0x3:
|
||||
return WrapFixed(this, &nvhost_nvdec::GetWaitbase, input, output);
|
||||
return GetWaitbase(input, output);
|
||||
case 0x7:
|
||||
return WrapFixed(this, &nvhost_nvdec::SetSubmitTimeout, input, output);
|
||||
return SetSubmitTimeout(input, output);
|
||||
case 0x9:
|
||||
return WrapFixedVariable(this, &nvhost_nvdec::MapBuffer, input, output);
|
||||
return MapBuffer(input, output);
|
||||
case 0xa:
|
||||
return WrapFixedVariable(this, &nvhost_nvdec::UnmapBuffer, input, output);
|
||||
return UnmapBuffer(input, output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -45,7 +44,7 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> in
|
||||
case 'H':
|
||||
switch (command.cmd) {
|
||||
case 0x1:
|
||||
return WrapFixed(this, &nvhost_nvdec::SetNVMAPfd, input, output);
|
||||
return SetNVMAPfd(input);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -29,9 +29,6 @@ std::size_t SliceVectors(std::span<const u8> input, std::vector<T>& dst, std::si
|
||||
return 0;
|
||||
}
|
||||
const size_t bytes_copied = count * sizeof(T);
|
||||
if (input.size() < offset + bytes_copied) {
|
||||
return 0;
|
||||
}
|
||||
std::memcpy(dst.data(), input.data() + offset, bytes_copied);
|
||||
return bytes_copied;
|
||||
}
|
||||
@@ -44,9 +41,6 @@ std::size_t WriteVectors(std::span<u8> dst, const std::vector<T>& src, std::size
|
||||
return 0;
|
||||
}
|
||||
const size_t bytes_copied = src.size() * sizeof(T);
|
||||
if (dst.size() < offset + bytes_copied) {
|
||||
return 0;
|
||||
}
|
||||
std::memcpy(dst.data() + offset, src.data(), bytes_copied);
|
||||
return bytes_copied;
|
||||
}
|
||||
@@ -69,14 +63,18 @@ nvhost_nvdec_common::~nvhost_nvdec_common() {
|
||||
core.Host1xDeviceFile().syncpts_accumulated.push_back(channel_syncpoint);
|
||||
}
|
||||
|
||||
NvResult nvhost_nvdec_common::SetNVMAPfd(IoctlSetNvmapFD& params) {
|
||||
NvResult nvhost_nvdec_common::SetNVMAPfd(std::span<const u8> input) {
|
||||
IoctlSetNvmapFD params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlSetNvmapFD));
|
||||
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
|
||||
|
||||
nvmap_fd = params.nvmap_fd;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_nvdec_common::Submit(IoctlSubmit& params, std::span<u8> data, DeviceFD fd) {
|
||||
NvResult nvhost_nvdec_common::Submit(DeviceFD fd, std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlSubmit params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlSubmit));
|
||||
LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count);
|
||||
|
||||
// Instantiate param buffers
|
||||
@@ -87,12 +85,12 @@ NvResult nvhost_nvdec_common::Submit(IoctlSubmit& params, std::span<u8> data, De
|
||||
std::vector<u32> fence_thresholds(params.fence_count);
|
||||
|
||||
// Slice input into their respective buffers
|
||||
std::size_t offset = 0;
|
||||
offset += SliceVectors(data, command_buffers, params.cmd_buffer_count, offset);
|
||||
offset += SliceVectors(data, relocs, params.relocation_count, offset);
|
||||
offset += SliceVectors(data, reloc_shifts, params.relocation_count, offset);
|
||||
offset += SliceVectors(data, syncpt_increments, params.syncpoint_count, offset);
|
||||
offset += SliceVectors(data, fence_thresholds, params.fence_count, offset);
|
||||
std::size_t offset = sizeof(IoctlSubmit);
|
||||
offset += SliceVectors(input, command_buffers, params.cmd_buffer_count, offset);
|
||||
offset += SliceVectors(input, relocs, params.relocation_count, offset);
|
||||
offset += SliceVectors(input, reloc_shifts, params.relocation_count, offset);
|
||||
offset += SliceVectors(input, syncpt_increments, params.syncpoint_count, offset);
|
||||
offset += SliceVectors(input, fence_thresholds, params.fence_count, offset);
|
||||
|
||||
auto& gpu = system.GPU();
|
||||
if (gpu.UseNvdec()) {
|
||||
@@ -110,51 +108,72 @@ NvResult nvhost_nvdec_common::Submit(IoctlSubmit& params, std::span<u8> data, De
|
||||
cmdlist.size() * sizeof(u32));
|
||||
gpu.PushCommandBuffer(core.Host1xDeviceFile().fd_to_id[fd], cmdlist);
|
||||
}
|
||||
std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmit));
|
||||
// Some games expect command_buffers to be written back
|
||||
offset = 0;
|
||||
offset += WriteVectors(data, command_buffers, offset);
|
||||
offset += WriteVectors(data, relocs, offset);
|
||||
offset += WriteVectors(data, reloc_shifts, offset);
|
||||
offset += WriteVectors(data, syncpt_increments, offset);
|
||||
offset += WriteVectors(data, fence_thresholds, offset);
|
||||
offset = sizeof(IoctlSubmit);
|
||||
offset += WriteVectors(output, command_buffers, offset);
|
||||
offset += WriteVectors(output, relocs, offset);
|
||||
offset += WriteVectors(output, reloc_shifts, offset);
|
||||
offset += WriteVectors(output, syncpt_increments, offset);
|
||||
offset += WriteVectors(output, fence_thresholds, offset);
|
||||
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_nvdec_common::GetSyncpoint(IoctlGetSyncpoint& params) {
|
||||
NvResult nvhost_nvdec_common::GetSyncpoint(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlGetSyncpoint params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlGetSyncpoint));
|
||||
LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param);
|
||||
|
||||
// const u32 id{NvCore::SyncpointManager::channel_syncpoints[static_cast<u32>(channel_type)]};
|
||||
params.value = channel_syncpoint;
|
||||
std::memcpy(output.data(), ¶ms, sizeof(IoctlGetSyncpoint));
|
||||
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_nvdec_common::GetWaitbase(IoctlGetWaitbase& params) {
|
||||
NvResult nvhost_nvdec_common::GetWaitbase(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlGetWaitbase params{};
|
||||
LOG_CRITICAL(Service_NVDRV, "called WAITBASE");
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase));
|
||||
params.value = 0; // Seems to be hard coded at 0
|
||||
std::memcpy(output.data(), ¶ms, sizeof(IoctlGetWaitbase));
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_nvdec_common::MapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries) {
|
||||
const size_t num_entries = std::min(params.num_entries, static_cast<u32>(entries.size()));
|
||||
for (size_t i = 0; i < num_entries; i++) {
|
||||
entries[i].map_address = nvmap.PinHandle(entries[i].map_handle);
|
||||
NvResult nvhost_nvdec_common::MapBuffer(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlMapBuffer params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer));
|
||||
std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
|
||||
|
||||
SliceVectors(input, cmd_buffer_handles, params.num_entries, sizeof(IoctlMapBuffer));
|
||||
|
||||
for (auto& cmd_buffer : cmd_buffer_handles) {
|
||||
cmd_buffer.map_address = nvmap.PinHandle(cmd_buffer.map_handle);
|
||||
}
|
||||
std::memcpy(output.data(), ¶ms, sizeof(IoctlMapBuffer));
|
||||
std::memcpy(output.data() + sizeof(IoctlMapBuffer), cmd_buffer_handles.data(),
|
||||
cmd_buffer_handles.size() * sizeof(MapBufferEntry));
|
||||
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_nvdec_common::UnmapBuffer(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlMapBuffer params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer));
|
||||
std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
|
||||
|
||||
SliceVectors(input, cmd_buffer_handles, params.num_entries, sizeof(IoctlMapBuffer));
|
||||
for (auto& cmd_buffer : cmd_buffer_handles) {
|
||||
nvmap.UnpinHandle(cmd_buffer.map_handle);
|
||||
}
|
||||
|
||||
std::memset(output.data(), 0, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_nvdec_common::UnmapBuffer(IoctlMapBuffer& params,
|
||||
std::span<MapBufferEntry> entries) {
|
||||
const size_t num_entries = std::min(params.num_entries, static_cast<u32>(entries.size()));
|
||||
for (size_t i = 0; i < num_entries; i++) {
|
||||
nvmap.UnpinHandle(entries[i].map_handle);
|
||||
entries[i] = {};
|
||||
}
|
||||
|
||||
params = {};
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_nvdec_common::SetSubmitTimeout(u32 timeout) {
|
||||
NvResult nvhost_nvdec_common::SetSubmitTimeout(std::span<const u8> input, std::span<u8> output) {
|
||||
std::memcpy(&submit_timeout, input.data(), input.size());
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
@@ -107,13 +107,13 @@ protected:
|
||||
static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size");
|
||||
|
||||
/// Ioctl command implementations
|
||||
NvResult SetNVMAPfd(IoctlSetNvmapFD&);
|
||||
NvResult Submit(IoctlSubmit& params, std::span<u8> input, DeviceFD fd);
|
||||
NvResult GetSyncpoint(IoctlGetSyncpoint& params);
|
||||
NvResult GetWaitbase(IoctlGetWaitbase& params);
|
||||
NvResult MapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries);
|
||||
NvResult UnmapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries);
|
||||
NvResult SetSubmitTimeout(u32 timeout);
|
||||
NvResult SetNVMAPfd(std::span<const u8> input);
|
||||
NvResult Submit(DeviceFD fd, std::span<const u8> input, std::span<u8> output);
|
||||
NvResult GetSyncpoint(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult GetWaitbase(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult MapBuffer(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult UnmapBuffer(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult SetSubmitTimeout(std::span<const u8> input, std::span<u8> output);
|
||||
|
||||
Kernel::KEvent* QueryEvent(u32 event_id) override;
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvhost_nvjpg.h"
|
||||
|
||||
namespace Service::Nvidia::Devices {
|
||||
@@ -19,7 +18,7 @@ NvResult nvhost_nvjpg::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> in
|
||||
case 'H':
|
||||
switch (command.cmd) {
|
||||
case 0x1:
|
||||
return WrapFixed(this, &nvhost_nvjpg::SetNVMAPfd, input, output);
|
||||
return SetNVMAPfd(input, output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -47,7 +46,9 @@ NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in
|
||||
void nvhost_nvjpg::OnOpen(DeviceFD fd) {}
|
||||
void nvhost_nvjpg::OnClose(DeviceFD fd) {}
|
||||
|
||||
NvResult nvhost_nvjpg::SetNVMAPfd(IoctlSetNvmapFD& params) {
|
||||
NvResult nvhost_nvjpg::SetNVMAPfd(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlSetNvmapFD params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
|
||||
|
||||
nvmap_fd = params.nvmap_fd;
|
||||
|
||||
@@ -33,7 +33,7 @@ private:
|
||||
|
||||
s32_le nvmap_fd{};
|
||||
|
||||
NvResult SetNVMAPfd(IoctlSetNvmapFD& params);
|
||||
NvResult SetNVMAPfd(std::span<const u8> input, std::span<u8> output);
|
||||
};
|
||||
|
||||
} // namespace Service::Nvidia::Devices
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/nvdrv/core/container.h"
|
||||
#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvhost_vic.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
|
||||
@@ -26,16 +25,16 @@ NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
|
||||
if (!host1x_file.fd_to_id.contains(fd)) {
|
||||
host1x_file.fd_to_id[fd] = host1x_file.vic_next_id++;
|
||||
}
|
||||
return WrapFixedVariable(this, &nvhost_vic::Submit, input, output, fd);
|
||||
return Submit(fd, input, output);
|
||||
}
|
||||
case 0x2:
|
||||
return WrapFixed(this, &nvhost_vic::GetSyncpoint, input, output);
|
||||
return GetSyncpoint(input, output);
|
||||
case 0x3:
|
||||
return WrapFixed(this, &nvhost_vic::GetWaitbase, input, output);
|
||||
return GetWaitbase(input, output);
|
||||
case 0x9:
|
||||
return WrapFixedVariable(this, &nvhost_vic::MapBuffer, input, output);
|
||||
return MapBuffer(input, output);
|
||||
case 0xa:
|
||||
return WrapFixedVariable(this, &nvhost_vic::UnmapBuffer, input, output);
|
||||
return UnmapBuffer(input, output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -43,7 +42,7 @@ NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
|
||||
case 'H':
|
||||
switch (command.cmd) {
|
||||
case 0x1:
|
||||
return WrapFixed(this, &nvhost_vic::SetNVMAPfd, input, output);
|
||||
return SetNVMAPfd(input);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/service/nvdrv/core/container.h"
|
||||
#include "core/hle/service/nvdrv/core/nvmap.h"
|
||||
#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvmap.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
@@ -32,17 +31,17 @@ NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
case 0x1:
|
||||
switch (command.cmd) {
|
||||
case 0x1:
|
||||
return WrapFixed(this, &nvmap::IocCreate, input, output);
|
||||
return IocCreate(input, output);
|
||||
case 0x3:
|
||||
return WrapFixed(this, &nvmap::IocFromId, input, output);
|
||||
return IocFromId(input, output);
|
||||
case 0x4:
|
||||
return WrapFixed(this, &nvmap::IocAlloc, input, output);
|
||||
return IocAlloc(input, output);
|
||||
case 0x5:
|
||||
return WrapFixed(this, &nvmap::IocFree, input, output);
|
||||
return IocFree(input, output);
|
||||
case 0x9:
|
||||
return WrapFixed(this, &nvmap::IocParam, input, output);
|
||||
return IocParam(input, output);
|
||||
case 0xe:
|
||||
return WrapFixed(this, &nvmap::IocGetId, input, output);
|
||||
return IocGetId(input, output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -70,7 +69,9 @@ NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, st
|
||||
void nvmap::OnOpen(DeviceFD fd) {}
|
||||
void nvmap::OnClose(DeviceFD fd) {}
|
||||
|
||||
NvResult nvmap::IocCreate(IocCreateParams& params) {
|
||||
NvResult nvmap::IocCreate(std::span<const u8> input, std::span<u8> output) {
|
||||
IocCreateParams params;
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
LOG_DEBUG(Service_NVDRV, "called, size=0x{:08X}", params.size);
|
||||
|
||||
std::shared_ptr<NvCore::NvMap::Handle> handle_description{};
|
||||
@@ -84,10 +85,13 @@ NvResult nvmap::IocCreate(IocCreateParams& params) {
|
||||
params.handle = handle_description->id;
|
||||
LOG_DEBUG(Service_NVDRV, "handle: {}, size: 0x{:X}", handle_description->id, params.size);
|
||||
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvmap::IocAlloc(IocAllocParams& params) {
|
||||
NvResult nvmap::IocAlloc(std::span<const u8> input, std::span<u8> output) {
|
||||
IocAllocParams params;
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.address);
|
||||
|
||||
if (!params.handle) {
|
||||
@@ -129,10 +133,14 @@ NvResult nvmap::IocAlloc(IocAllocParams& params) {
|
||||
handle_description->size,
|
||||
Kernel::KMemoryPermission::None, true, false)
|
||||
.IsSuccess());
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
return result;
|
||||
}
|
||||
|
||||
NvResult nvmap::IocGetId(IocGetIdParams& params) {
|
||||
NvResult nvmap::IocGetId(std::span<const u8> input, std::span<u8> output) {
|
||||
IocGetIdParams params;
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
// See the comment in FromId for extra info on this function
|
||||
@@ -149,10 +157,14 @@ NvResult nvmap::IocGetId(IocGetIdParams& params) {
|
||||
}
|
||||
|
||||
params.id = handle_description->id;
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvmap::IocFromId(IocFromIdParams& params) {
|
||||
NvResult nvmap::IocFromId(std::span<const u8> input, std::span<u8> output) {
|
||||
IocFromIdParams params;
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
|
||||
LOG_DEBUG(Service_NVDRV, "called, id:{}", params.id);
|
||||
|
||||
// Handles and IDs are always the same value in nvmap however IDs can be used globally given the
|
||||
@@ -176,12 +188,16 @@ NvResult nvmap::IocFromId(IocFromIdParams& params) {
|
||||
return result;
|
||||
}
|
||||
params.handle = handle_description->id;
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvmap::IocParam(IocParamParams& params) {
|
||||
NvResult nvmap::IocParam(std::span<const u8> input, std::span<u8> output) {
|
||||
enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 };
|
||||
|
||||
IocParamParams params;
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
|
||||
LOG_DEBUG(Service_NVDRV, "called type={}", params.param);
|
||||
|
||||
if (!params.handle) {
|
||||
@@ -221,10 +237,14 @@ NvResult nvmap::IocParam(IocParamParams& params) {
|
||||
return NvResult::BadValue;
|
||||
}
|
||||
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvmap::IocFree(IocFreeParams& params) {
|
||||
NvResult nvmap::IocFree(std::span<const u8> input, std::span<u8> output) {
|
||||
IocFreeParams params;
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
if (!params.handle) {
|
||||
@@ -247,6 +267,7 @@ NvResult nvmap::IocFree(IocFreeParams& params) {
|
||||
// This is possible when there's internal dups or other duplicates.
|
||||
}
|
||||
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
|
||||
@@ -99,12 +99,12 @@ public:
|
||||
};
|
||||
static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");
|
||||
|
||||
NvResult IocCreate(IocCreateParams& params);
|
||||
NvResult IocAlloc(IocAllocParams& params);
|
||||
NvResult IocGetId(IocGetIdParams& params);
|
||||
NvResult IocFromId(IocFromIdParams& params);
|
||||
NvResult IocParam(IocParamParams& params);
|
||||
NvResult IocFree(IocFreeParams& params);
|
||||
NvResult IocCreate(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult IocAlloc(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult IocGetId(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult IocFromId(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult IocParam(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult IocFree(std::span<const u8> input, std::span<u8> output);
|
||||
|
||||
private:
|
||||
/// Id to use for the next handle that is created.
|
||||
|
||||
@@ -41,7 +41,7 @@ bool BufferQueueCore::WaitForDequeueCondition(std::unique_lock<std::mutex>& lk)
|
||||
s32 BufferQueueCore::GetMinUndequeuedBufferCountLocked(bool async) const {
|
||||
// If DequeueBuffer is allowed to error out, we don't have to add an extra buffer.
|
||||
if (!use_async_buffer) {
|
||||
return max_acquired_buffer_count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dequeue_buffer_cannot_block || async) {
|
||||
@@ -52,7 +52,7 @@ s32 BufferQueueCore::GetMinUndequeuedBufferCountLocked(bool async) const {
|
||||
}
|
||||
|
||||
s32 BufferQueueCore::GetMinMaxBufferCountLocked(bool async) const {
|
||||
return GetMinUndequeuedBufferCountLocked(async) + 1;
|
||||
return GetMinUndequeuedBufferCountLocked(async);
|
||||
}
|
||||
|
||||
s32 BufferQueueCore::GetMaxBufferCountLocked(bool async) const {
|
||||
@@ -61,7 +61,7 @@ s32 BufferQueueCore::GetMaxBufferCountLocked(bool async) const {
|
||||
|
||||
if (override_max_buffer_count != 0) {
|
||||
ASSERT(override_max_buffer_count >= min_buffer_count);
|
||||
max_buffer_count = override_max_buffer_count;
|
||||
return override_max_buffer_count;
|
||||
}
|
||||
|
||||
// Any buffers that are dequeued by the producer or sitting in the queue waiting to be consumed
|
||||
|
||||
@@ -134,7 +134,7 @@ Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, St
|
||||
const s32 max_buffer_count = core->GetMaxBufferCountLocked(async);
|
||||
if (async && core->override_max_buffer_count) {
|
||||
if (core->override_max_buffer_count < max_buffer_count) {
|
||||
LOG_ERROR(Service_Nvnflinger, "async mode is invalid with buffer count override");
|
||||
*found = BufferQueueCore::INVALID_BUFFER_SLOT;
|
||||
return Status::BadValue;
|
||||
}
|
||||
}
|
||||
@@ -142,7 +142,8 @@ Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, St
|
||||
// Free up any buffers that are in slots beyond the max buffer count
|
||||
for (s32 s = max_buffer_count; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
|
||||
ASSERT(slots[s].buffer_state == BufferState::Free);
|
||||
if (slots[s].graphic_buffer != nullptr) {
|
||||
if (slots[s].graphic_buffer != nullptr && slots[s].buffer_state == BufferState::Free &&
|
||||
!slots[s].is_preallocated) {
|
||||
core->FreeBufferLocked(s);
|
||||
*return_flags |= Status::ReleaseAllBuffers;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ Result AllocateIoForProcessAddressSpace(Common::ProcessAddress* out_map_address,
|
||||
// Get bounds of where mapping is possible.
|
||||
const VAddr alias_code_begin = GetInteger(page_table.GetAliasCodeRegionStart());
|
||||
const VAddr alias_code_size = page_table.GetAliasCodeRegionSize() / YUZU_PAGESIZE;
|
||||
const auto state = Kernel::KMemoryState::IoMemory;
|
||||
const auto state = Kernel::KMemoryState::Io;
|
||||
const auto perm = Kernel::KMemoryPermission::UserReadWrite;
|
||||
std::mt19937_64 rng{process->GetRandomEntropy(0)};
|
||||
|
||||
@@ -71,17 +71,24 @@ Result AllocateIoForProcessAddressSpace(Common::ProcessAddress* out_map_address,
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::span<u8> SerializeIoc(T& params) {
|
||||
return std::span(reinterpret_cast<u8*>(std::addressof(params)), sizeof(T));
|
||||
}
|
||||
|
||||
Result CreateNvMapHandle(u32* out_nv_map_handle, Nvidia::Devices::nvmap& nvmap, u32 size) {
|
||||
// Create a handle.
|
||||
Nvidia::Devices::nvmap::IocCreateParams create_params{
|
||||
Nvidia::Devices::nvmap::IocCreateParams create_in_params{
|
||||
.size = size,
|
||||
.handle = 0,
|
||||
};
|
||||
R_UNLESS(nvmap.IocCreate(create_params) == Nvidia::NvResult::Success,
|
||||
Nvidia::Devices::nvmap::IocCreateParams create_out_params{};
|
||||
R_UNLESS(nvmap.IocCreate(SerializeIoc(create_in_params), SerializeIoc(create_out_params)) ==
|
||||
Nvidia::NvResult::Success,
|
||||
VI::ResultOperationFailed);
|
||||
|
||||
// Assign the output handle.
|
||||
*out_nv_map_handle = create_params.handle;
|
||||
*out_nv_map_handle = create_out_params.handle;
|
||||
|
||||
// We succeeded.
|
||||
R_SUCCEED();
|
||||
@@ -89,10 +96,13 @@ Result CreateNvMapHandle(u32* out_nv_map_handle, Nvidia::Devices::nvmap& nvmap,
|
||||
|
||||
Result FreeNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle) {
|
||||
// Free the handle.
|
||||
Nvidia::Devices::nvmap::IocFreeParams free_params{
|
||||
Nvidia::Devices::nvmap::IocFreeParams free_in_params{
|
||||
.handle = handle,
|
||||
};
|
||||
R_UNLESS(nvmap.IocFree(free_params) == Nvidia::NvResult::Success, VI::ResultOperationFailed);
|
||||
Nvidia::Devices::nvmap::IocFreeParams free_out_params{};
|
||||
R_UNLESS(nvmap.IocFree(SerializeIoc(free_in_params), SerializeIoc(free_out_params)) ==
|
||||
Nvidia::NvResult::Success,
|
||||
VI::ResultOperationFailed);
|
||||
|
||||
// We succeeded.
|
||||
R_SUCCEED();
|
||||
@@ -101,7 +111,7 @@ Result FreeNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle) {
|
||||
Result AllocNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Common::ProcessAddress buffer,
|
||||
u32 size) {
|
||||
// Assign the allocated memory to the handle.
|
||||
Nvidia::Devices::nvmap::IocAllocParams alloc_params{
|
||||
Nvidia::Devices::nvmap::IocAllocParams alloc_in_params{
|
||||
.handle = handle,
|
||||
.heap_mask = 0,
|
||||
.flags = {},
|
||||
@@ -109,7 +119,10 @@ Result AllocNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Common::Proce
|
||||
.kind = 0,
|
||||
.address = GetInteger(buffer),
|
||||
};
|
||||
R_UNLESS(nvmap.IocAlloc(alloc_params) == Nvidia::NvResult::Success, VI::ResultOperationFailed);
|
||||
Nvidia::Devices::nvmap::IocAllocParams alloc_out_params{};
|
||||
R_UNLESS(nvmap.IocAlloc(SerializeIoc(alloc_in_params), SerializeIoc(alloc_out_params)) ==
|
||||
Nvidia::NvResult::Success,
|
||||
VI::ResultOperationFailed);
|
||||
|
||||
// We succeeded.
|
||||
R_SUCCEED();
|
||||
|
||||
@@ -9,35 +9,6 @@
|
||||
|
||||
namespace Service::PTM {
|
||||
|
||||
enum class Location : u8 {
|
||||
Internal,
|
||||
External,
|
||||
};
|
||||
|
||||
class ISession : public ServiceFramework<ISession> {
|
||||
public:
|
||||
explicit ISession(Core::System& system_) : ServiceFramework{system_, "ISession"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetTemperatureRange"},
|
||||
{2, nullptr, "SetMeasurementMode"},
|
||||
{4, &ISession::GetTemperature, "GetTemperature"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
private:
|
||||
void GetTemperature(HLERequestContext& ctx) {
|
||||
constexpr f32 temperature = 35;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(temperature);
|
||||
}
|
||||
};
|
||||
|
||||
TS::TS(Core::System& system_) : ServiceFramework{system_, "ts"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
@@ -45,7 +16,7 @@ TS::TS(Core::System& system_) : ServiceFramework{system_, "ts"} {
|
||||
{1, &TS::GetTemperature, "GetTemperature"},
|
||||
{2, nullptr, "SetMeasurementMode"},
|
||||
{3, &TS::GetTemperatureMilliC, "GetTemperatureMilliC"},
|
||||
{4, &TS::OpenSession, "OpenSession"},
|
||||
{4, nullptr, "OpenSession"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -76,13 +47,4 @@ void TS::GetTemperatureMilliC(HLERequestContext& ctx) {
|
||||
rb.Push(temperature);
|
||||
}
|
||||
|
||||
void TS::OpenSession(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
[[maybe_unused]] const u32 device_code = rp.Pop<u32>();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ISession>(system);
|
||||
}
|
||||
|
||||
} // namespace Service::PTM
|
||||
|
||||
@@ -14,9 +14,13 @@ public:
|
||||
~TS() override;
|
||||
|
||||
private:
|
||||
enum class Location : u8 {
|
||||
Internal,
|
||||
External,
|
||||
};
|
||||
|
||||
void GetTemperature(HLERequestContext& ctx);
|
||||
void GetTemperatureMilliC(HLERequestContext& ctx);
|
||||
void OpenSession(HLERequestContext& ctx);
|
||||
};
|
||||
|
||||
} // namespace Service::PTM
|
||||
|
||||
@@ -5,13 +5,8 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "common/settings.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/content_archive.h"
|
||||
#include "core/file_sys/errors.h"
|
||||
#include "core/file_sys/nca_metadata.h"
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
#include "core/file_sys/romfs.h"
|
||||
#include "core/file_sys/system_archive/system_archive.h"
|
||||
#include "core/file_sys/system_archive/system_version.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/set/set.h"
|
||||
@@ -27,30 +22,18 @@ enum class GetFirmwareVersionType {
|
||||
Version2,
|
||||
};
|
||||
|
||||
void GetFirmwareVersionImpl(Core::System& system, HLERequestContext& ctx,
|
||||
GetFirmwareVersionType type) {
|
||||
void GetFirmwareVersionImpl(HLERequestContext& ctx, GetFirmwareVersionType type) {
|
||||
LOG_WARNING(Service_SET, "called - Using hardcoded firmware version '{}'",
|
||||
FileSys::SystemArchive::GetLongDisplayVersion());
|
||||
|
||||
ASSERT_MSG(ctx.GetWriteBufferSize() == 0x100,
|
||||
"FirmwareVersion output buffer must be 0x100 bytes in size!");
|
||||
|
||||
constexpr u64 FirmwareVersionSystemDataId = 0x0100000000000809;
|
||||
auto& fsc = system.GetFileSystemController();
|
||||
|
||||
// Attempt to load version data from disk
|
||||
const FileSys::RegisteredCache* bis_system{};
|
||||
std::unique_ptr<FileSys::NCA> nca{};
|
||||
FileSys::VirtualDir romfs{};
|
||||
|
||||
bis_system = fsc.GetSystemNANDContents();
|
||||
if (bis_system) {
|
||||
nca = bis_system->GetEntry(FirmwareVersionSystemDataId, FileSys::ContentRecordType::Data);
|
||||
}
|
||||
if (nca) {
|
||||
romfs = FileSys::ExtractRomFS(nca->GetRomFS());
|
||||
}
|
||||
if (!romfs) {
|
||||
romfs = FileSys::ExtractRomFS(
|
||||
FileSys::SystemArchive::SynthesizeSystemArchive(FirmwareVersionSystemDataId));
|
||||
}
|
||||
// Instead of using the normal procedure of checking for the real system archive and if it
|
||||
// doesn't exist, synthesizing one, I feel that that would lead to strange bugs because a
|
||||
// used is using a really old or really new SystemVersion title. The synthesized one ensures
|
||||
// consistence (currently reports as 5.1.0-0.0)
|
||||
const auto archive = FileSys::SystemArchive::SystemVersion();
|
||||
|
||||
const auto early_exit_failure = [&ctx](std::string_view desc, Result code) {
|
||||
LOG_ERROR(Service_SET, "General failure while attempting to resolve firmware version ({}).",
|
||||
@@ -59,7 +42,13 @@ void GetFirmwareVersionImpl(Core::System& system, HLERequestContext& ctx,
|
||||
rb.Push(code);
|
||||
};
|
||||
|
||||
const auto ver_file = romfs->GetFile("file");
|
||||
if (archive == nullptr) {
|
||||
early_exit_failure("The system version archive couldn't be synthesized.",
|
||||
FileSys::ERROR_FAILED_MOUNT_ARCHIVE);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto ver_file = archive->GetFile("file");
|
||||
if (ver_file == nullptr) {
|
||||
early_exit_failure("The system version archive didn't contain the file 'file'.",
|
||||
FileSys::ERROR_INVALID_ARGUMENT);
|
||||
@@ -98,12 +87,12 @@ void SET_SYS::SetLanguageCode(HLERequestContext& ctx) {
|
||||
|
||||
void SET_SYS::GetFirmwareVersion(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
GetFirmwareVersionImpl(system, ctx, GetFirmwareVersionType::Version1);
|
||||
GetFirmwareVersionImpl(ctx, GetFirmwareVersionType::Version1);
|
||||
}
|
||||
|
||||
void SET_SYS::GetFirmwareVersion2(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
GetFirmwareVersionImpl(system, ctx, GetFirmwareVersionType::Version2);
|
||||
GetFirmwareVersionImpl(ctx, GetFirmwareVersionType::Version2);
|
||||
}
|
||||
|
||||
void SET_SYS::GetAccountSettings(HLERequestContext& ctx) {
|
||||
|
||||
@@ -19,23 +19,16 @@ namespace Core::Memory {
|
||||
namespace {
|
||||
constexpr auto CHEAT_ENGINE_NS = std::chrono::nanoseconds{1000000000 / 12};
|
||||
|
||||
std::string_view ExtractName(std::size_t& out_name_size, std::string_view data,
|
||||
std::size_t start_index, char match) {
|
||||
std::string_view ExtractName(std::string_view data, std::size_t start_index, char match) {
|
||||
auto end_index = start_index;
|
||||
while (data[end_index] != match) {
|
||||
++end_index;
|
||||
if (end_index > data.size()) {
|
||||
if (end_index > data.size() ||
|
||||
(end_index - start_index - 1) > sizeof(CheatDefinition::readable_name)) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
out_name_size = end_index - start_index;
|
||||
|
||||
// Clamp name if it's too big
|
||||
if (out_name_size > sizeof(CheatDefinition::readable_name)) {
|
||||
end_index = start_index + sizeof(CheatDefinition::readable_name);
|
||||
}
|
||||
|
||||
return data.substr(start_index, end_index - start_index);
|
||||
}
|
||||
} // Anonymous namespace
|
||||
@@ -120,8 +113,7 @@ std::vector<CheatEntry> TextCheatParser::Parse(std::string_view data) const {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::size_t name_size{};
|
||||
const auto name = ExtractName(name_size, data, i + 1, '}');
|
||||
const auto name = ExtractName(data, i + 1, '}');
|
||||
if (name.empty()) {
|
||||
return {};
|
||||
}
|
||||
@@ -133,13 +125,12 @@ std::vector<CheatEntry> TextCheatParser::Parse(std::string_view data) const {
|
||||
.definition.readable_name[out[*current_entry].definition.readable_name.size() - 1] =
|
||||
'\0';
|
||||
|
||||
i += name_size + 1;
|
||||
i += name.length() + 1;
|
||||
} else if (data[i] == '[') {
|
||||
current_entry = out.size();
|
||||
out.emplace_back();
|
||||
|
||||
std::size_t name_size{};
|
||||
const auto name = ExtractName(name_size, data, i + 1, ']');
|
||||
const auto name = ExtractName(data, i + 1, ']');
|
||||
if (name.empty()) {
|
||||
return {};
|
||||
}
|
||||
@@ -151,7 +142,7 @@ std::vector<CheatEntry> TextCheatParser::Parse(std::string_view data) const {
|
||||
.definition.readable_name[out[*current_entry].definition.readable_name.size() - 1] =
|
||||
'\0';
|
||||
|
||||
i += name_size + 1;
|
||||
i += name.length() + 1;
|
||||
} else if (::isxdigit(data[i])) {
|
||||
if (!current_entry || out[*current_entry].definition.num_opcodes >=
|
||||
out[*current_entry].definition.opcodes.size()) {
|
||||
|
||||
@@ -242,7 +242,6 @@ std::string EmitGLSL(const Profile& profile, const RuntimeInfo& runtime_info, IR
|
||||
}
|
||||
if (program.info.uses_subgroup_shuffles) {
|
||||
ctx.header += "bool shfl_in_bounds;";
|
||||
ctx.header += "uint shfl_result;";
|
||||
}
|
||||
ctx.code.insert(0, ctx.header);
|
||||
ctx.code += '}';
|
||||
|
||||
@@ -141,8 +141,7 @@ void EmitShuffleIndex(EmitContext& ctx, IR::Inst& inst, std::string_view value,
|
||||
const auto src_thread_id{fmt::format("({})|({})", lhs, min_thread_id)};
|
||||
ctx.Add("shfl_in_bounds=int({})<=int({});", src_thread_id, max_thread_id);
|
||||
SetInBoundsFlag(ctx, inst);
|
||||
ctx.Add("shfl_result=readInvocationARB({},{});", value, src_thread_id);
|
||||
ctx.AddU32("{}=shfl_in_bounds?shfl_result:{};", inst, value);
|
||||
ctx.AddU32("{}=shfl_in_bounds?readInvocationARB({},{}):{};", inst, value, src_thread_id, value);
|
||||
}
|
||||
|
||||
void EmitShuffleUp(EmitContext& ctx, IR::Inst& inst, std::string_view value, std::string_view index,
|
||||
@@ -159,8 +158,7 @@ void EmitShuffleUp(EmitContext& ctx, IR::Inst& inst, std::string_view value, std
|
||||
const auto src_thread_id{fmt::format("({}-{})", THREAD_ID, index)};
|
||||
ctx.Add("shfl_in_bounds=int({})>=int({});", src_thread_id, max_thread_id);
|
||||
SetInBoundsFlag(ctx, inst);
|
||||
ctx.Add("shfl_result=readInvocationARB({},{});", value, src_thread_id);
|
||||
ctx.AddU32("{}=shfl_in_bounds?shfl_result:{};", inst, value);
|
||||
ctx.AddU32("{}=shfl_in_bounds?readInvocationARB({},{}):{};", inst, value, src_thread_id, value);
|
||||
}
|
||||
|
||||
void EmitShuffleDown(EmitContext& ctx, IR::Inst& inst, std::string_view value,
|
||||
@@ -177,8 +175,7 @@ void EmitShuffleDown(EmitContext& ctx, IR::Inst& inst, std::string_view value,
|
||||
const auto src_thread_id{fmt::format("({}+{})", THREAD_ID, index)};
|
||||
ctx.Add("shfl_in_bounds=int({})<=int({});", src_thread_id, max_thread_id);
|
||||
SetInBoundsFlag(ctx, inst);
|
||||
ctx.Add("shfl_result=readInvocationARB({},{});", value, src_thread_id);
|
||||
ctx.AddU32("{}=shfl_in_bounds?shfl_result:{};", inst, value);
|
||||
ctx.AddU32("{}=shfl_in_bounds?readInvocationARB({},{}):{};", inst, value, src_thread_id, value);
|
||||
}
|
||||
|
||||
void EmitShuffleButterfly(EmitContext& ctx, IR::Inst& inst, std::string_view value,
|
||||
@@ -196,8 +193,7 @@ void EmitShuffleButterfly(EmitContext& ctx, IR::Inst& inst, std::string_view val
|
||||
const auto src_thread_id{fmt::format("({}^{})", THREAD_ID, index)};
|
||||
ctx.Add("shfl_in_bounds=int({})<=int({});", src_thread_id, max_thread_id);
|
||||
SetInBoundsFlag(ctx, inst);
|
||||
ctx.Add("shfl_result=readInvocationARB({},{});", value, src_thread_id);
|
||||
ctx.AddU32("{}=shfl_in_bounds?shfl_result:{};", inst, value);
|
||||
ctx.AddU32("{}=shfl_in_bounds?readInvocationARB({},{}):{};", inst, value, src_thread_id, value);
|
||||
}
|
||||
|
||||
void EmitFSwizzleAdd(EmitContext& ctx, IR::Inst& inst, std::string_view op_a, std::string_view op_b,
|
||||
|
||||
@@ -111,33 +111,16 @@ Id GetCbuf(EmitContext& ctx, Id result_type, Id UniformDefinitions::*member_ptr,
|
||||
} else if (element_size > 1) {
|
||||
const u32 log2_element_size{static_cast<u32>(std::countr_zero(element_size))};
|
||||
const Id shift{ctx.Const(log2_element_size)};
|
||||
buffer_offset = ctx.OpShiftRightLogical(ctx.U32[1], ctx.Def(offset), shift);
|
||||
buffer_offset = ctx.OpShiftRightArithmetic(ctx.U32[1], ctx.Def(offset), shift);
|
||||
} else {
|
||||
buffer_offset = ctx.Def(offset);
|
||||
}
|
||||
if (!binding.IsImmediate()) {
|
||||
return ctx.OpFunctionCall(result_type, indirect_func, ctx.Def(binding), buffer_offset);
|
||||
}
|
||||
|
||||
const Id cbuf{ctx.cbufs[binding.U32()].*member_ptr};
|
||||
const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, ctx.u32_zero_value, buffer_offset)};
|
||||
const Id val = ctx.OpLoad(result_type, access_chain);
|
||||
|
||||
if (offset.IsImmediate() || !ctx.profile.has_broken_robust) {
|
||||
return val;
|
||||
}
|
||||
|
||||
const auto is_float = UniformDefinitions::IsFloat(member_ptr);
|
||||
const auto num_elements = UniformDefinitions::NumElements(member_ptr);
|
||||
const std::array zero_vec{
|
||||
is_float ? ctx.Const(0.0f) : ctx.Const(0u),
|
||||
is_float ? ctx.Const(0.0f) : ctx.Const(0u),
|
||||
is_float ? ctx.Const(0.0f) : ctx.Const(0u),
|
||||
is_float ? ctx.Const(0.0f) : ctx.Const(0u),
|
||||
};
|
||||
const Id cond = ctx.OpULessThanEqual(ctx.TypeBool(), buffer_offset, ctx.Const(0xFFFFu));
|
||||
const Id zero = ctx.OpCompositeConstruct(result_type, std::span(zero_vec.data(), num_elements));
|
||||
return ctx.OpSelect(result_type, cond, val, zero);
|
||||
return ctx.OpLoad(result_type, access_chain);
|
||||
}
|
||||
|
||||
Id GetCbufU32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
|
||||
@@ -155,7 +138,7 @@ Id GetCbufElement(EmitContext& ctx, Id vector, const IR::Value& offset, u32 inde
|
||||
const u32 element{(offset.U32() / 4) % 4 + index_offset};
|
||||
return ctx.OpCompositeExtract(ctx.U32[1], vector, element);
|
||||
}
|
||||
const Id shift{ctx.OpShiftRightLogical(ctx.U32[1], ctx.Def(offset), ctx.Const(2u))};
|
||||
const Id shift{ctx.OpShiftRightArithmetic(ctx.U32[1], ctx.Def(offset), ctx.Const(2u))};
|
||||
Id element{ctx.OpBitwiseAnd(ctx.U32[1], shift, ctx.Const(3u))};
|
||||
if (index_offset > 0) {
|
||||
element = ctx.OpIAdd(ctx.U32[1], element, ctx.Const(index_offset));
|
||||
|
||||
@@ -64,42 +64,6 @@ struct UniformDefinitions {
|
||||
Id F32{};
|
||||
Id U32x2{};
|
||||
Id U32x4{};
|
||||
|
||||
constexpr static size_t NumElements(Id UniformDefinitions::*member_ptr) {
|
||||
if (member_ptr == &UniformDefinitions::U8) {
|
||||
return 1;
|
||||
}
|
||||
if (member_ptr == &UniformDefinitions::S8) {
|
||||
return 1;
|
||||
}
|
||||
if (member_ptr == &UniformDefinitions::U16) {
|
||||
return 1;
|
||||
}
|
||||
if (member_ptr == &UniformDefinitions::S16) {
|
||||
return 1;
|
||||
}
|
||||
if (member_ptr == &UniformDefinitions::U32) {
|
||||
return 1;
|
||||
}
|
||||
if (member_ptr == &UniformDefinitions::F32) {
|
||||
return 1;
|
||||
}
|
||||
if (member_ptr == &UniformDefinitions::U32x2) {
|
||||
return 2;
|
||||
}
|
||||
if (member_ptr == &UniformDefinitions::U32x4) {
|
||||
return 4;
|
||||
}
|
||||
ASSERT(false);
|
||||
return 1;
|
||||
}
|
||||
|
||||
constexpr static bool IsFloat(Id UniformDefinitions::*member_ptr) {
|
||||
if (member_ptr == &UniformDefinitions::F32) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct StorageTypeDefinition {
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace Shader {
|
||||
|
||||
struct Profile {
|
||||
u32 supported_spirv{0x00010000};
|
||||
|
||||
bool unified_descriptor_binding{};
|
||||
bool support_descriptor_aliasing{};
|
||||
bool support_int8{};
|
||||
@@ -81,9 +82,6 @@ struct Profile {
|
||||
bool has_broken_spirv_subgroup_mask_vector_extract_dynamic{};
|
||||
|
||||
u32 gl_max_compute_smem_size{};
|
||||
|
||||
/// Maxwell and earlier nVidia architectures have broken robust support
|
||||
bool has_broken_robust{};
|
||||
};
|
||||
|
||||
} // namespace Shader
|
||||
|
||||
@@ -86,10 +86,7 @@ public:
|
||||
uncommitted_operations.emplace_back(std::move(func));
|
||||
}
|
||||
pending_operations.emplace_back(std::move(uncommitted_operations));
|
||||
{
|
||||
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
|
||||
QueueFence(new_fence);
|
||||
}
|
||||
QueueFence(new_fence);
|
||||
if (!delay_fence) {
|
||||
func();
|
||||
}
|
||||
|
||||
@@ -132,16 +132,12 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
|
||||
const bool use_accelerated =
|
||||
rasterizer.AccelerateDisplay(*framebuffer, framebuffer_addr, framebuffer->stride);
|
||||
const bool is_srgb = use_accelerated && screen_info.is_srgb;
|
||||
RenderScreenshot(*framebuffer, use_accelerated);
|
||||
|
||||
{
|
||||
std::scoped_lock lock{rasterizer.LockCaches()};
|
||||
RenderScreenshot(*framebuffer, use_accelerated);
|
||||
|
||||
Frame* frame = present_manager.GetRenderFrame();
|
||||
blit_screen.DrawToSwapchain(frame, *framebuffer, use_accelerated, is_srgb);
|
||||
scheduler.Flush(*frame->render_ready);
|
||||
present_manager.Present(frame);
|
||||
}
|
||||
Frame* frame = present_manager.GetRenderFrame();
|
||||
blit_screen.DrawToSwapchain(frame, *framebuffer, use_accelerated, is_srgb);
|
||||
scheduler.Flush(*frame->render_ready);
|
||||
present_manager.Present(frame);
|
||||
|
||||
gpu.RendererFrameEndNotify();
|
||||
rasterizer.TickFrame();
|
||||
|
||||
@@ -356,11 +356,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device
|
||||
.has_broken_fp16_float_controls = driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY,
|
||||
.ignore_nan_fp_comparisons = false,
|
||||
.has_broken_spirv_subgroup_mask_vector_extract_dynamic =
|
||||
driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY,
|
||||
.has_broken_robust =
|
||||
device.IsNvidia() && device.GetNvidiaArch() <= NvidiaArchitecture::Arch_Maxwell,
|
||||
};
|
||||
|
||||
driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY};
|
||||
host_info = Shader::HostTranslateInfo{
|
||||
.support_float64 = device.IsFloat64Supported(),
|
||||
.support_float16 = device.IsFloat16Supported(),
|
||||
|
||||
@@ -198,7 +198,7 @@ void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) {
|
||||
if (!pipeline) {
|
||||
return;
|
||||
}
|
||||
std::scoped_lock lock{LockCaches()};
|
||||
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
|
||||
// update engine as channel may be different.
|
||||
pipeline->SetEngine(maxwell3d, gpu_memory);
|
||||
pipeline->Configure(is_indexed);
|
||||
@@ -708,7 +708,6 @@ void RasterizerVulkan::TiledCacheBarrier() {
|
||||
}
|
||||
|
||||
void RasterizerVulkan::FlushCommands() {
|
||||
std::scoped_lock lock{LockCaches()};
|
||||
if (draw_counter == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -806,7 +805,6 @@ void RasterizerVulkan::FlushWork() {
|
||||
if ((++draw_counter & 7) != 7) {
|
||||
return;
|
||||
}
|
||||
std::scoped_lock lock{LockCaches()};
|
||||
if (draw_counter < DRAWS_TO_DISPATCH) {
|
||||
// Send recorded tasks to the worker thread
|
||||
scheduler.DispatchWork();
|
||||
@@ -1501,7 +1499,7 @@ void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs)
|
||||
void RasterizerVulkan::InitializeChannel(Tegra::Control::ChannelState& channel) {
|
||||
CreateChannel(channel);
|
||||
{
|
||||
std::scoped_lock lock{LockCaches()};
|
||||
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
|
||||
texture_cache.CreateChannel(channel);
|
||||
buffer_cache.CreateChannel(channel);
|
||||
}
|
||||
@@ -1514,7 +1512,7 @@ void RasterizerVulkan::BindChannel(Tegra::Control::ChannelState& channel) {
|
||||
const s32 channel_id = channel.bind_id;
|
||||
BindToChannel(channel_id);
|
||||
{
|
||||
std::scoped_lock lock{LockCaches()};
|
||||
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
|
||||
texture_cache.BindToChannel(channel_id);
|
||||
buffer_cache.BindToChannel(channel_id);
|
||||
}
|
||||
@@ -1527,7 +1525,7 @@ void RasterizerVulkan::BindChannel(Tegra::Control::ChannelState& channel) {
|
||||
void RasterizerVulkan::ReleaseChannel(s32 channel_id) {
|
||||
EraseChannel(channel_id);
|
||||
{
|
||||
std::scoped_lock lock{LockCaches()};
|
||||
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
|
||||
texture_cache.EraseChannel(channel_id);
|
||||
buffer_cache.EraseChannel(channel_id);
|
||||
}
|
||||
|
||||
@@ -133,10 +133,6 @@ public:
|
||||
|
||||
void ReleaseChannel(s32 channel_id) override;
|
||||
|
||||
std::scoped_lock<std::recursive_mutex, std::recursive_mutex> LockCaches() {
|
||||
return std::scoped_lock{buffer_cache.mutex, texture_cache.mutex};
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr size_t MAX_TEXTURES = 192;
|
||||
static constexpr size_t MAX_IMAGES = 48;
|
||||
|
||||
@@ -83,6 +83,15 @@ constexpr std::array VK_FORMAT_A4B4G4R4_UNORM_PACK16{
|
||||
|
||||
} // namespace Alternatives
|
||||
|
||||
enum class NvidiaArchitecture {
|
||||
KeplerOrOlder,
|
||||
Maxwell,
|
||||
Pascal,
|
||||
Volta,
|
||||
Turing,
|
||||
AmpereOrNewer,
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void SetNext(void**& next, T& data) {
|
||||
*next = &data;
|
||||
@@ -317,9 +326,9 @@ NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical,
|
||||
if (shading_rate_props.primitiveFragmentShadingRateWithMultipleViewports) {
|
||||
// Only Ampere and newer support this feature
|
||||
// TODO: Find a way to differentiate Ampere and Ada
|
||||
return NvidiaArchitecture::Arch_AmpereOrNewer;
|
||||
return NvidiaArchitecture::AmpereOrNewer;
|
||||
}
|
||||
return NvidiaArchitecture::Arch_Turing;
|
||||
return NvidiaArchitecture::Turing;
|
||||
}
|
||||
|
||||
if (exts.contains(VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME)) {
|
||||
@@ -331,7 +340,7 @@ NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical,
|
||||
physical_properties.pNext = &advanced_blending_props;
|
||||
physical.GetProperties2(physical_properties);
|
||||
if (advanced_blending_props.advancedBlendMaxColorAttachments == 1) {
|
||||
return NvidiaArchitecture::Arch_Maxwell;
|
||||
return NvidiaArchitecture::Maxwell;
|
||||
}
|
||||
|
||||
if (exts.contains(VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME)) {
|
||||
@@ -341,13 +350,13 @@ NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical,
|
||||
physical_properties.pNext = &conservative_raster_props;
|
||||
physical.GetProperties2(physical_properties);
|
||||
if (conservative_raster_props.degenerateLinesRasterized) {
|
||||
return NvidiaArchitecture::Arch_Volta;
|
||||
return NvidiaArchitecture::Volta;
|
||||
}
|
||||
return NvidiaArchitecture::Arch_Pascal;
|
||||
return NvidiaArchitecture::Pascal;
|
||||
}
|
||||
}
|
||||
|
||||
return NvidiaArchitecture::Arch_KeplerOrOlder;
|
||||
return NvidiaArchitecture::KeplerOrOlder;
|
||||
}
|
||||
|
||||
std::vector<const char*> ExtensionListForVulkan(
|
||||
@@ -427,10 +436,6 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||
throw vk::Exception(VK_ERROR_INCOMPATIBLE_DRIVER);
|
||||
}
|
||||
|
||||
if (is_nvidia) {
|
||||
nvidia_arch = GetNvidiaArchitecture(physical, supported_extensions);
|
||||
}
|
||||
|
||||
SetupFamilies(surface);
|
||||
const auto queue_cis = GetDeviceQueueCreateInfos();
|
||||
|
||||
@@ -527,11 +532,11 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||
|
||||
if (is_nvidia) {
|
||||
const u32 nv_major_version = (properties.properties.driverVersion >> 22) & 0x3ff;
|
||||
const auto arch = GetNvidiaArch();
|
||||
if (arch >= NvidiaArchitecture::Arch_AmpereOrNewer) {
|
||||
const auto arch = GetNvidiaArchitecture(physical, supported_extensions);
|
||||
if (arch >= NvidiaArchitecture::AmpereOrNewer) {
|
||||
LOG_WARNING(Render_Vulkan, "Ampere and newer have broken float16 math");
|
||||
features.shader_float16_int8.shaderFloat16 = false;
|
||||
} else if (arch <= NvidiaArchitecture::Arch_Volta) {
|
||||
} else if (arch <= NvidiaArchitecture::Volta) {
|
||||
if (nv_major_version < 527) {
|
||||
LOG_WARNING(Render_Vulkan, "Volta and older have broken VK_KHR_push_descriptor");
|
||||
RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
|
||||
@@ -681,8 +686,8 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||
RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
|
||||
}
|
||||
} else if (extensions.push_descriptor && is_nvidia) {
|
||||
const auto arch = GetNvidiaArch();
|
||||
if (arch <= NvidiaArchitecture::Arch_Pascal) {
|
||||
const auto arch = GetNvidiaArchitecture(physical, supported_extensions);
|
||||
if (arch <= NvidiaArchitecture::Pascal) {
|
||||
LOG_WARNING(Render_Vulkan,
|
||||
"Pascal and older architectures have broken VK_KHR_push_descriptor");
|
||||
RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
|
||||
|
||||
@@ -177,15 +177,6 @@ enum class FormatType { Linear, Optimal, Buffer };
|
||||
/// Subgroup size of the guest emulated hardware (Nvidia has 32 threads per subgroup).
|
||||
const u32 GuestWarpSize = 32;
|
||||
|
||||
enum class NvidiaArchitecture {
|
||||
Arch_KeplerOrOlder,
|
||||
Arch_Maxwell,
|
||||
Arch_Pascal,
|
||||
Arch_Volta,
|
||||
Arch_Turing,
|
||||
Arch_AmpereOrNewer,
|
||||
};
|
||||
|
||||
/// Handles data specific to a physical device.
|
||||
class Device {
|
||||
public:
|
||||
@@ -679,14 +670,6 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsNvidia() const noexcept {
|
||||
return properties.driver.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY;
|
||||
}
|
||||
|
||||
NvidiaArchitecture GetNvidiaArch() const noexcept {
|
||||
return nvidia_arch;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Checks if the physical device is suitable and configures the object state
|
||||
/// with all necessary info about its properties.
|
||||
@@ -805,7 +788,6 @@ private:
|
||||
bool supports_conditional_barriers{}; ///< Allows barriers in conditional control flow.
|
||||
u64 device_access_memory{}; ///< Total size of device local memory in bytes.
|
||||
u32 sets_per_pool{}; ///< Sets per Description Pool
|
||||
NvidiaArchitecture nvidia_arch{NvidiaArchitecture::Arch_AmpereOrNewer};
|
||||
|
||||
// Telemetry parameters
|
||||
std::set<std::string, std::less<>> supported_extensions; ///< Reported Vulkan extensions.
|
||||
|
||||
@@ -522,7 +522,7 @@ Instance Instance::Create(u32 version, Span<const char*> layers, Span<const char
|
||||
.applicationVersion = VK_MAKE_VERSION(0, 1, 0),
|
||||
.pEngineName = "yuzu Emulator",
|
||||
.engineVersion = VK_MAKE_VERSION(0, 1, 0),
|
||||
.apiVersion = VK_API_VERSION_1_3,
|
||||
.apiVersion = version,
|
||||
};
|
||||
const VkInstanceCreateInfo ci{
|
||||
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
||||
|
||||
@@ -114,7 +114,7 @@ const std::map<Settings::ShaderBackend, QString> Config::shader_backend_texts_ma
|
||||
// This must be in alphabetical order according to action name as it must have the same order as
|
||||
// UISetting::values.shortcuts, which is alphabetically ordered.
|
||||
// clang-format off
|
||||
const std::array<UISettings::Shortcut, 23> Config::default_hotkeys{{
|
||||
const std::array<UISettings::Shortcut, 22> Config::default_hotkeys{{
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+M"), QStringLiteral("Home+Dpad_Right"), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("-"), QStringLiteral("Home+Dpad_Down"), Qt::ApplicationShortcut, true}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("="), QStringLiteral("Home+Dpad_Up"), Qt::ApplicationShortcut, true}},
|
||||
@@ -136,7 +136,6 @@ const std::array<UISettings::Shortcut, 23> Config::default_hotkeys{{
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Filter Bar")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F"), QStringLiteral(""), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Framerate Limit")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+U"), QStringLiteral("Home+Y"), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Mouse Panning")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F9"), QStringLiteral(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Renderdoc Capture")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral(""), QStringLiteral(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Status Bar")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+S"), QStringLiteral(""), Qt::WindowShortcut, false}},
|
||||
}};
|
||||
// clang-format on
|
||||
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
default_mouse_buttons;
|
||||
static const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> default_keyboard_keys;
|
||||
static const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> default_keyboard_mods;
|
||||
static const std::array<UISettings::Shortcut, 23> default_hotkeys;
|
||||
static const std::array<UISettings::Shortcut, 22> default_hotkeys;
|
||||
|
||||
static const std::map<Settings::AntiAliasing, QString> anti_aliasing_texts_map;
|
||||
static const std::map<Settings::ScalingFilter, QString> scaling_filter_texts_map;
|
||||
|
||||
@@ -319,13 +319,6 @@ void ConfigureHotkeys::ApplyConfiguration(HotkeyRegistry& registry) {
|
||||
void ConfigureHotkeys::RestoreDefaults() {
|
||||
for (int r = 0; r < model->rowCount(); ++r) {
|
||||
const QStandardItem* parent = model->item(r, 0);
|
||||
const int hotkey_size = static_cast<int>(Config::default_hotkeys.size());
|
||||
|
||||
if (hotkey_size != parent->rowCount()) {
|
||||
QMessageBox::warning(this, tr("Invalid hotkey settings"),
|
||||
tr("An error occurred. Please report this issue on github."));
|
||||
return;
|
||||
}
|
||||
|
||||
for (int r2 = 0; r2 < parent->rowCount(); ++r2) {
|
||||
model->item(r, 0)
|
||||
|
||||
@@ -89,7 +89,7 @@ void ConfigureVibration::VibrateController(Core::HID::ControllerTriggerType type
|
||||
|
||||
auto& player = Settings::values.players.GetValue()[player_index];
|
||||
auto controller = hid_core.GetEmulatedControllerByIndex(player_index);
|
||||
const int vibration_strength = vibration_spinboxes[player_index]->value();
|
||||
const int vibration_strenght = vibration_spinboxes[player_index]->value();
|
||||
const auto& buttons = controller->GetButtonsValues();
|
||||
|
||||
bool button_is_pressed = false;
|
||||
@@ -105,10 +105,10 @@ void ConfigureVibration::VibrateController(Core::HID::ControllerTriggerType type
|
||||
return;
|
||||
}
|
||||
|
||||
const bool old_vibration_enabled = player.vibration_enabled;
|
||||
const int old_vibration_strength = player.vibration_strength;
|
||||
const int old_vibration_enabled = player.vibration_enabled;
|
||||
const bool old_vibration_strenght = player.vibration_strength;
|
||||
player.vibration_enabled = true;
|
||||
player.vibration_strength = vibration_strength;
|
||||
player.vibration_strength = vibration_strenght;
|
||||
|
||||
const Core::HID::VibrationValue vibration{
|
||||
.low_amplitude = 1.0f,
|
||||
@@ -121,7 +121,7 @@ void ConfigureVibration::VibrateController(Core::HID::ControllerTriggerType type
|
||||
|
||||
// Restore previous values
|
||||
player.vibration_enabled = old_vibration_enabled;
|
||||
player.vibration_strength = old_vibration_strength;
|
||||
player.vibration_strength = old_vibration_strenght;
|
||||
}
|
||||
|
||||
void ConfigureVibration::StopVibrations() {
|
||||
|
||||
Reference in New Issue
Block a user