Compare commits

..

9 Commits

Author SHA1 Message Date
FernandoS27
6dea93dabc Eliminate G8R8 conversion, native is actualy R8G8 2018-11-27 07:57:28 -04:00
bunnei
1cd40f107f Merge pull request #1806 from ReinUsesLisp/morton-fixup
morton: Fixup compiler warning
2018-11-26 23:22:59 -05:00
bunnei
11c17465d8 Merge pull request #1804 from lioncash/cast
gdbstub: Silence value truncation warning within FpuWrite()
2018-11-26 23:19:40 -05:00
bunnei
852a462df3 Merge pull request #1805 from lioncash/resource
svc: Implement svcCreateResourceLimit, svcGetResourceLimitCurrentValue(), svcGetResourceLimitLimitValue(), and svcSetResourceLimitLimitValue()
2018-11-26 22:59:51 -05:00
Lioncash
5905162e36 svc: Implement svcSetResourceLimitLimitValue()
The opposite of the getter functions, this function sets the limit value
for a particular ResourceLimit resource category, with the restriction
that the  new limit value must be equal to or greater than the current
resource value. If this is violated, then ERR_INVALID_STATE is returned.

e.g.

Assume:

current[Events] = 10;
limit[Events] = 20;

a call to this service function lowering the limit value to 10 would be
fine, however, attempting to lower it to 9 in this case would cause an
invalid state error.
2018-11-26 21:23:15 -05:00
Lioncash
eb5596044d svc: Implement svcGetResourceLimitCurrentValue()
This kernel service function is essentially the exact same as
svcGetResourceLimitLimitValue(), with the only difference being that it
retrieves the current value for a given resource category using the
provided resource limit handle, rather than retrieving the limiting
value of that resource limit instance.

Given these are exactly the same and only differ on returned values, we
can extract the existing code for svcGetResourceLimitLimitValue() to
handle both values.
2018-11-26 21:23:11 -05:00
Lioncash
1d6399c222 svc: Implement svcGetResourceLimitLimitValue()
This kernel service function retrieves the maximum allowable value for
a provided resource category for a given resource limit instance. Given
we already have the functionality added to the resource limit instance
itself, it's sufficient to just hook it up.

The error scenarios for this are:

1. If an invalid resource category type is provided, then ERR_INVALID_ENUM is returned.

2. If an invalid handle is provided, then ERR_INVALID_HANDLE is returned (bad thing goes in, bad thing goes out, as one would expect).

If neither of the above error cases occur, then the out parameter is
provided with the maximum limit value for the given category and success
is returned.
2018-11-26 21:12:13 -05:00
Lioncash
4ef2af8c98 svc: Implement svcCreateResourceLimit()
This function simply creates a ResourceLimit instance and attempts to
create a handle for it within the current process' handle table. If the
kernal fails to either create the ResourceLimit instance or create a
handle for the ResourceLimit instance, it returns a failure code
(OUT_OF_RESOURCE, and HANDLE_TABLE_FULL respectively). Finally, it exits
by providing the output parameter with the handle value for the
ResourceLimit instance and returning that it was successful.

Note: We do not return OUT_OF_RESOURCE because, if yuzu runs out of
available memory, then new will currently throw. We *could* allocate the
kernel instance with std::nothrow, however this would be inconsistent
with how all other kernel objects are currently allocated.
2018-11-26 21:10:31 -05:00
Lioncash
474c745502 gdbstub: Silence value truncation warning within FpuWrite()
Previously this would cause an implicit truncation warning about
assigning a u64 value to a u32 value without an explicit cast.
2018-11-26 19:58:23 -05:00
5 changed files with 131 additions and 24 deletions

View File

@@ -282,7 +282,7 @@ static void FpuWrite(std::size_t id, u128 val, Kernel::Thread* thread = nullptr)
if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
thread_context.vector_registers[id - UC_ARM64_REG_Q0] = val;
} else if (id == FPCR_REGISTER) {
thread_context.fpcr = val[0];
thread_context.fpcr = static_cast<u32>(val[0]);
}
}

View File

@@ -14,7 +14,7 @@ namespace Kernel {
class KernelCore;
enum class ResourceType {
enum class ResourceType : u32 {
PhysicalMemory,
Threads,
Events,
@@ -25,6 +25,10 @@ enum class ResourceType {
ResourceTypeCount
};
constexpr bool IsValidResourceType(ResourceType type) {
return type < ResourceType::ResourceTypeCount;
}
class ResourceLimit final : public Object {
public:
/**

View File

@@ -105,6 +105,38 @@ ResultCode MapUnmapMemorySanityChecks(const VMManager& vm_manager, VAddr dst_add
return RESULT_SUCCESS;
}
enum class ResourceLimitValueType {
CurrentValue,
LimitValue,
};
ResultVal<s64> RetrieveResourceLimitValue(Handle resource_limit, u32 resource_type,
ResourceLimitValueType value_type) {
const auto type = static_cast<ResourceType>(resource_type);
if (!IsValidResourceType(type)) {
LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type);
return ERR_INVALID_ENUM_VALUE;
}
const auto& kernel = Core::System::GetInstance().Kernel();
const auto* const current_process = kernel.CurrentProcess();
ASSERT(current_process != nullptr);
const auto resource_limit_object =
current_process->GetHandleTable().Get<ResourceLimit>(resource_limit);
if (!resource_limit_object) {
LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}",
resource_limit);
return ERR_INVALID_HANDLE;
}
if (value_type == ResourceLimitValueType::CurrentValue) {
return MakeResult(resource_limit_object->GetCurrentResourceValue(type));
}
return MakeResult(resource_limit_object->GetMaxResourceValue(type));
}
} // Anonymous namespace
/// Set the process heap to a given Size. It can both extend and shrink the heap.
@@ -1346,6 +1378,87 @@ static ResultCode GetProcessInfo(u64* out, Handle process_handle, u32 type) {
return RESULT_SUCCESS;
}
static ResultCode CreateResourceLimit(Handle* out_handle) {
LOG_DEBUG(Kernel_SVC, "called");
auto& kernel = Core::System::GetInstance().Kernel();
auto resource_limit = ResourceLimit::Create(kernel);
auto* const current_process = kernel.CurrentProcess();
ASSERT(current_process != nullptr);
const auto handle = current_process->GetHandleTable().Create(std::move(resource_limit));
if (handle.Failed()) {
return handle.Code();
}
*out_handle = *handle;
return RESULT_SUCCESS;
}
static ResultCode GetResourceLimitLimitValue(u64* out_value, Handle resource_limit,
u32 resource_type) {
LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type);
const auto limit_value = RetrieveResourceLimitValue(resource_limit, resource_type,
ResourceLimitValueType::LimitValue);
if (limit_value.Failed()) {
return limit_value.Code();
}
*out_value = static_cast<u64>(*limit_value);
return RESULT_SUCCESS;
}
static ResultCode GetResourceLimitCurrentValue(u64* out_value, Handle resource_limit,
u32 resource_type) {
LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type);
const auto current_value = RetrieveResourceLimitValue(resource_limit, resource_type,
ResourceLimitValueType::CurrentValue);
if (current_value.Failed()) {
return current_value.Code();
}
*out_value = static_cast<u64>(*current_value);
return RESULT_SUCCESS;
}
static ResultCode SetResourceLimitLimitValue(Handle resource_limit, u32 resource_type, u64 value) {
LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}, Value={}", resource_limit,
resource_type, value);
const auto type = static_cast<ResourceType>(resource_type);
if (!IsValidResourceType(type)) {
LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type);
return ERR_INVALID_ENUM_VALUE;
}
auto& kernel = Core::System::GetInstance().Kernel();
auto* const current_process = kernel.CurrentProcess();
ASSERT(current_process != nullptr);
auto resource_limit_object =
current_process->GetHandleTable().Get<ResourceLimit>(resource_limit);
if (!resource_limit_object) {
LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}",
resource_limit);
return ERR_INVALID_HANDLE;
}
const auto set_result = resource_limit_object->SetLimitValue(type, static_cast<s64>(value));
if (set_result.IsError()) {
LOG_ERROR(
Kernel_SVC,
"Attempted to lower resource limit ({}) for category '{}' below its current value ({})",
resource_limit_object->GetMaxResourceValue(type), resource_type,
resource_limit_object->GetCurrentResourceValue(type));
return set_result;
}
return RESULT_SUCCESS;
}
namespace {
struct FunctionDef {
using Func = void();
@@ -1405,8 +1518,8 @@ static const FunctionDef SVC_Table[] = {
{0x2D, nullptr, "UnmapPhysicalMemory"},
{0x2E, nullptr, "GetFutureThreadInfo"},
{0x2F, nullptr, "GetLastThreadInfo"},
{0x30, nullptr, "GetResourceLimitLimitValue"},
{0x31, nullptr, "GetResourceLimitCurrentValue"},
{0x30, SvcWrap<GetResourceLimitLimitValue>, "GetResourceLimitLimitValue"},
{0x31, SvcWrap<GetResourceLimitCurrentValue>, "GetResourceLimitCurrentValue"},
{0x32, SvcWrap<SetThreadActivity>, "SetThreadActivity"},
{0x33, SvcWrap<GetThreadContext>, "GetThreadContext"},
{0x34, SvcWrap<WaitForAddress>, "WaitForAddress"},
@@ -1482,8 +1595,8 @@ static const FunctionDef SVC_Table[] = {
{0x7A, nullptr, "StartProcess"},
{0x7B, nullptr, "TerminateProcess"},
{0x7C, SvcWrap<GetProcessInfo>, "GetProcessInfo"},
{0x7D, nullptr, "CreateResourceLimit"},
{0x7E, nullptr, "SetResourceLimitLimitValue"},
{0x7D, SvcWrap<CreateResourceLimit>, "CreateResourceLimit"},
{0x7E, SvcWrap<SetResourceLimitLimitValue>, "SetResourceLimitLimitValue"},
{0x7F, nullptr, "CallSecureMonitor"},
};

View File

@@ -43,6 +43,14 @@ void SvcWrap() {
FuncReturn(func(static_cast<u32>(Param(0)), static_cast<u32>(Param(1))).raw);
}
template <ResultCode func(u32*)>
void SvcWrap() {
u32 param = 0;
const u32 retval = func(&param).raw;
Core::CurrentArmInterface().SetReg(1, param);
FuncReturn(retval);
}
template <ResultCode func(u32*, u32)>
void SvcWrap() {
u32 param_1 = 0;

View File

@@ -738,18 +738,6 @@ static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height, bo
}
}
static void ConvertG8R8ToR8G8(std::vector<u8>& data, u32 width, u32 height) {
constexpr auto bpp{GetBytesPerPixel(PixelFormat::G8R8U)};
for (std::size_t y = 0; y < height; ++y) {
for (std::size_t x = 0; x < width; ++x) {
const std::size_t offset{bpp * (y * width + x)};
const u8 temp{data[offset]};
data[offset] = data[offset + 1];
data[offset + 1] = temp;
}
}
}
/**
* Helper function to perform software conversion (as needed) when loading a buffer from Switch
* memory. This is for Maxwell pixel formats that cannot be represented as-is in OpenGL or with
@@ -782,12 +770,6 @@ static void ConvertFormatAsNeeded_LoadGLBuffer(std::vector<u8>& data, PixelForma
// Convert the S8Z24 depth format to Z24S8, as OpenGL does not support S8Z24.
ConvertS8Z24ToZ24S8(data, width, height, false);
break;
case PixelFormat::G8R8U:
case PixelFormat::G8R8S:
// Convert the G8R8 color format to R8G8, as OpenGL does not support G8R8.
ConvertG8R8ToR8G8(data, width, height);
break;
}
}