mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-11-25 20:06:56 +01:00
libNX Time Initalization
What was added: * Time service * CNTPCT_EL0 redirected to CNTVCT_EL0
This commit is contained in:
parent
2476c5d48a
commit
e44809355c
@ -34,6 +34,7 @@ add_library(skyline SHARED
|
||||
${source_DIR}/skyline/kernel/services/apm/apm.cpp
|
||||
${source_DIR}/skyline/kernel/services/am/appletOE.cpp
|
||||
${source_DIR}/skyline/kernel/services/hid/hid.cpp
|
||||
${source_DIR}/skyline/kernel/services/time/time.cpp
|
||||
)
|
||||
target_link_libraries(skyline fmt tinyxml2)
|
||||
target_compile_options(skyline PRIVATE -Wno-c++17-extensions)
|
||||
|
@ -49,6 +49,8 @@ namespace skyline {
|
||||
constexpr u16 SvcLast = 0x7F; //!< The index of the last SVC
|
||||
constexpr u16 BrkRdy = 0xFF; //!< This is reserved for our kernel's to know when a process/thread is ready
|
||||
constexpr u32 TpidrroEl0 = 0x5E83; //!< ID of TPIDRRO_EL0 in MRS
|
||||
constexpr u32 CntpctEl0 = 0x5F01; //!< ID of CNTPCT_EL0 in MRS
|
||||
constexpr u32 CntvctEl0 = 0x5F02; //!< ID of CNTVCT_EL0 in MRS
|
||||
// Kernel
|
||||
constexpr u64 MaxSyncHandles = 0x40; //!< The total amount of handles that can be passed to WaitSynchronization
|
||||
constexpr handle_t BaseHandleIndex = 0xD000; // The index of the base handle
|
||||
@ -82,13 +84,13 @@ namespace skyline {
|
||||
*/
|
||||
struct Brk {
|
||||
/**
|
||||
* Creates a BRK instruction with a specific immediate value, used for generating BRK opcodes
|
||||
* @brief Creates a BRK instruction with a specific immediate value, used for generating BRK opcodes
|
||||
* @param val The immediate value of the instruction
|
||||
*/
|
||||
Brk(u16 val) {
|
||||
start = 0x0; // First 5 bits of an BRK instruction are 0
|
||||
start = 0x0; // First 5 bits of a BRK instruction are 0
|
||||
value = val;
|
||||
end = 0x6A1; // Last 11 bits of an BRK instruction stored as u16
|
||||
end = 0x6A1; // Last 11 bits of a BRK instruction stored as u16
|
||||
}
|
||||
|
||||
/**
|
||||
@ -129,6 +131,17 @@ namespace skyline {
|
||||
* @brief A bit-field struct that encapsulates a MRS instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/mrs-move-system-register.
|
||||
*/
|
||||
struct Mrs {
|
||||
/**
|
||||
* @brief Creates a MRS instruction, used for generating BRK opcodes
|
||||
* @param srcReg The source system register
|
||||
* @param dstReg The destination Xn register
|
||||
*/
|
||||
Mrs(u32 srcReg, u8 dstReg) {
|
||||
this->srcReg = srcReg;
|
||||
this->dstReg = dstReg;
|
||||
end = 0xD53; // Last 12 bits of a MRS instruction stored as u16
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns if the opcode is valid or not
|
||||
* @return If the opcode represents a valid MRS instruction
|
||||
|
@ -180,7 +180,7 @@ namespace skyline::kernel::service::am {
|
||||
IApplicationFunctions(const DeviceState &state, ServiceManager &manager);
|
||||
|
||||
/**
|
||||
* @brief This just returns 1 regardless of input (https://switchbrew.org/wiki/Applet_Manager_services#NotifyRunning)
|
||||
* @brief This just returns a boolean true (https://switchbrew.org/wiki/Applet_Manager_services#NotifyRunning)
|
||||
*/
|
||||
void NotifyRunning(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
};
|
||||
|
@ -31,6 +31,9 @@ namespace skyline::kernel::service {
|
||||
am_IDebugFunctions,
|
||||
hid,
|
||||
hid_IAppletResource,
|
||||
time,
|
||||
time_ISystemClock,
|
||||
time_ITimeZoneService,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -54,6 +57,10 @@ namespace skyline::kernel::service {
|
||||
{"am:IDebugFunctions", Service::am_IDebugFunctions},
|
||||
{"hid", Service::hid},
|
||||
{"hid:IAppletResource", Service::hid_IAppletResource},
|
||||
{"time:s", Service::time},
|
||||
{"time:a", Service::time},
|
||||
{"time:ISystemClock", Service::time_ISystemClock},
|
||||
{"time:ITimeZoneService", Service::time_ITimeZoneService},
|
||||
};
|
||||
|
||||
class ServiceManager;
|
||||
|
@ -23,7 +23,8 @@ namespace skyline::kernel::service::hid {
|
||||
}) {}
|
||||
|
||||
void hid::CreateAppletResource(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
resource = std::static_pointer_cast<IAppletResource>(manager.NewService(Service::hid_IAppletResource, session, response));
|
||||
resource = std::make_shared<IAppletResource>(state, manager);
|
||||
manager.RegisterService(resource, session, response);
|
||||
}
|
||||
|
||||
void hid::SetSupportedNpadStyleSet(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "am/appletOE.h"
|
||||
#include "fatal/fatal.h"
|
||||
#include "hid/hid.h"
|
||||
#include "time/timesrv.h"
|
||||
|
||||
namespace skyline::kernel::service {
|
||||
ServiceManager::ServiceManager(const DeviceState &state) : state(state) {}
|
||||
@ -64,13 +65,18 @@ namespace skyline::kernel::service {
|
||||
case Service::hid_IAppletResource:
|
||||
serviceObj = std::make_shared<hid::IAppletResource>(state, *this);
|
||||
break;
|
||||
case Service::time:
|
||||
serviceObj = std::make_shared<time::time>(state, *this);
|
||||
break;
|
||||
default:
|
||||
throw exception("GetService called on missing object");
|
||||
}
|
||||
serviceVec.push_back(serviceObj);
|
||||
return serviceObj;
|
||||
}
|
||||
|
||||
handle_t ServiceManager::NewSession(const Service serviceType) {
|
||||
return state.thisProcess->NewHandle<type::KSession>(GetService(serviceType), serviceType).handle;
|
||||
return state.thisProcess->NewHandle<type::KSession>(GetService(serviceType)).handle;
|
||||
}
|
||||
|
||||
std::shared_ptr<BaseService> ServiceManager::NewService(const Service serviceType, type::KSession &session, ipc::IpcResponse &response) {
|
||||
@ -79,11 +85,21 @@ namespace skyline::kernel::service {
|
||||
session.domainTable[++session.handleIndex] = serviceObject;
|
||||
response.domainObjects.push_back(session.handleIndex);
|
||||
} else
|
||||
response.moveHandles.push_back(state.thisProcess->NewHandle<type::KSession>(serviceObject, serviceType).handle);
|
||||
state.logger->Write(Logger::Debug, "Service has been registered: \"{}\"", serviceObject->getName());
|
||||
response.moveHandles.push_back(state.thisProcess->NewHandle<type::KSession>(serviceObject).handle);
|
||||
state.logger->Write(Logger::Debug, "Service has been created: \"{}\"", serviceObject->getName());
|
||||
return serviceObject;
|
||||
}
|
||||
|
||||
void ServiceManager::RegisterService(std::shared_ptr<BaseService> serviceObject, type::KSession &session, ipc::IpcResponse &response) {
|
||||
serviceVec.push_back(serviceObject);
|
||||
if (response.isDomain) {
|
||||
session.domainTable[++session.handleIndex] = serviceObject;
|
||||
response.domainObjects.push_back(session.handleIndex);
|
||||
} else
|
||||
response.moveHandles.push_back(state.thisProcess->NewHandle<type::KSession>(serviceObject).handle);
|
||||
state.logger->Write(Logger::Debug, "Service has been registered: \"{}\"", serviceObject->getName());
|
||||
}
|
||||
|
||||
void ServiceManager::CloseSession(const handle_t handle) {
|
||||
auto session = state.thisProcess->GetHandle<type::KSession>(handle);
|
||||
if (session->serviceStatus == type::KSession::ServiceStatus::Open) {
|
||||
|
@ -33,13 +33,22 @@ namespace skyline::kernel::service {
|
||||
handle_t NewSession(const Service serviceType);
|
||||
|
||||
/**
|
||||
* @brief Creates a new service and writes it's handle or virtual handle (If it's a domain request) to IpcResponse
|
||||
* @brief Creates a new service using it's type enum and writes it's handle or virtual handle (If it's a domain request) to IpcResponse
|
||||
* @param serviceType The type of the service
|
||||
* @param session The session object of the command
|
||||
* @param response The response object to write the handle or virtual handle to
|
||||
*/
|
||||
std::shared_ptr<BaseService> NewService(const Service serviceType, type::KSession &session, ipc::IpcResponse &response);
|
||||
|
||||
/**
|
||||
* @brief Registers a service object in the manager and writes it's handle or virtual handle (If it's a domain request) to IpcResponse
|
||||
* @param serviceObject An instance of the service
|
||||
* @param session The session object of the command
|
||||
* @param response The response object to write the handle or virtual handle to
|
||||
*/
|
||||
void RegisterService(std::shared_ptr<BaseService> serviceObject, type::KSession &session, ipc::IpcResponse &response);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Closes an existing session to a service
|
||||
* @param service The handle of the KService object
|
||||
|
59
app/src/main/cpp/skyline/kernel/services/time/time.cpp
Normal file
59
app/src/main/cpp/skyline/kernel/services/time/time.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
#include "timesrv.h"
|
||||
|
||||
namespace skyline::kernel::service::time {
|
||||
time::time(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, false, Service::time, {
|
||||
{0x0, SFunc(time::GetStandardUserSystemClock)},
|
||||
{0x1, SFunc(time::GetStandardNetworkSystemClock)},
|
||||
{0x3, SFunc(time::GetTimeZoneService)},
|
||||
{0x4, SFunc(time::GetStandardLocalSystemClock)}
|
||||
}) {}
|
||||
|
||||
void time::GetStandardUserSystemClock(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
manager.RegisterService(std::make_shared<ISystemClock>(SystemClockType::User, state, manager), session, response);
|
||||
}
|
||||
|
||||
void time::GetStandardNetworkSystemClock(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
manager.RegisterService(std::make_shared<ISystemClock>(SystemClockType::Network, state, manager), session, response);
|
||||
}
|
||||
|
||||
void time::GetTimeZoneService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
manager.RegisterService(std::make_shared<ITimeZoneService>(state, manager), session, response);
|
||||
}
|
||||
|
||||
void time::GetStandardLocalSystemClock(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
manager.RegisterService(std::make_shared<ISystemClock>(SystemClockType::Local, state, manager), session, response);
|
||||
}
|
||||
|
||||
ISystemClock::ISystemClock(SystemClockType clockType, const DeviceState &state, ServiceManager &manager) : type(clockType), BaseService(state, manager, false, Service::time_ISystemClock, {
|
||||
{0x0, SFunc(ISystemClock::GetCurrentTime)}
|
||||
}) {}
|
||||
|
||||
void ISystemClock::GetCurrentTime(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
response.WriteValue<u64>(static_cast<u64>(std::time(nullptr)));
|
||||
}
|
||||
|
||||
ITimeZoneService::ITimeZoneService(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, false, Service::time_ITimeZoneService, {
|
||||
{0x65, SFunc(ITimeZoneService::ToCalendarTimeWithMyRule)}
|
||||
}) {}
|
||||
|
||||
void ITimeZoneService::ToCalendarTimeWithMyRule(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
time_t curTime = std::time(nullptr);
|
||||
tm calender = *std::gmtime(&curTime);
|
||||
CalendarTime calendarTime {
|
||||
.year = static_cast<u16>(calender.tm_year),
|
||||
.month = static_cast<u8>(calender.tm_mon),
|
||||
.day = static_cast<u8>(calender.tm_hour),
|
||||
.minute = static_cast<u8>(calender.tm_min),
|
||||
.second = static_cast<u8>(calender.tm_sec)
|
||||
};
|
||||
response.WriteValue(calendarTime);
|
||||
CalendarAdditionalInfo calendarInfo {
|
||||
.day_week = static_cast<u32>(calender.tm_wday),
|
||||
.day_month = static_cast<u32>(calender.tm_mday),
|
||||
.name = *reinterpret_cast<const u64*>(calender.tm_zone),
|
||||
.dst = static_cast<i32>(calender.tm_isdst),
|
||||
.utc_rel = static_cast<u32>(calender.tm_gmtoff)
|
||||
};
|
||||
response.WriteValue(calendarInfo);
|
||||
}
|
||||
}
|
97
app/src/main/cpp/skyline/kernel/services/time/timesrv.h
Normal file
97
app/src/main/cpp/skyline/kernel/services/time/timesrv.h
Normal file
@ -0,0 +1,97 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/services/base_service.h>
|
||||
#include <kernel/services/serviceman.h>
|
||||
|
||||
namespace skyline::kernel::service::time {
|
||||
/**
|
||||
* @brief The type of a SystemClockType
|
||||
*/
|
||||
enum SystemClockType {
|
||||
User, //!< Use time provided by user
|
||||
Network, //!< Use network time
|
||||
Local, //!< Use local time
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief time (This covers both time:a and time:s) is responsible for providing handles to various clock services (https://switchbrew.org/wiki/PSC_services#time:su.2C_time:s)
|
||||
*/
|
||||
class time : public BaseService {
|
||||
public:
|
||||
time(const DeviceState &state, ServiceManager& manager);
|
||||
|
||||
/**
|
||||
* @brief This returns a handle to a ISystemClock for user time (https://switchbrew.org/wiki/Services_API#GetStandardUserSystemClock)
|
||||
*/
|
||||
void GetStandardUserSystemClock(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
|
||||
/**
|
||||
* @brief This returns a handle to a ISystemClock for user time (https://switchbrew.org/wiki/Services_API#GetStandardNetworkSystemClock)
|
||||
*/
|
||||
void GetStandardNetworkSystemClock(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
|
||||
/**
|
||||
* @brief This returns a handle to a ISystemClock for user time (https://switchbrew.org/wiki/Services_API#GetStandardNetworkSystemClock)
|
||||
*/
|
||||
void GetTimeZoneService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
|
||||
/**
|
||||
* @brief This returns a handle to a ISystemClock for user time (https://switchbrew.org/wiki/Services_API#GetStandardNetworkSystemClock)
|
||||
*/
|
||||
void GetStandardLocalSystemClock(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief ISystemClock is used to retrieve and set time (https://switchbrew.org/wiki/PSC_services#ISystemClock)
|
||||
*/
|
||||
class ISystemClock : public BaseService {
|
||||
public:
|
||||
SystemClockType type; //!< The type of the system clock
|
||||
|
||||
ISystemClock(SystemClockType clockType, const DeviceState &state, ServiceManager& manager);
|
||||
|
||||
/**
|
||||
* @brief This returns the amount of seconds since epoch
|
||||
*/
|
||||
void GetCurrentTime(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief ITimeZoneService is used to retrieve and set time (https://switchbrew.org/wiki/PSC_services#ITimeZoneService)
|
||||
*/
|
||||
class ITimeZoneService : public BaseService {
|
||||
public:
|
||||
/**
|
||||
* @brief This holds a particular time point in calendar format
|
||||
*/
|
||||
struct CalendarTime {
|
||||
u16 year;
|
||||
u8 month;
|
||||
u8 day;
|
||||
u8 hour;
|
||||
u8 minute;
|
||||
u8 second;
|
||||
u8 : 8;
|
||||
};
|
||||
static_assert(sizeof(CalendarTime)==8);
|
||||
|
||||
/**
|
||||
* @brief This is passed in addition to CalendarTime
|
||||
*/
|
||||
struct CalendarAdditionalInfo {
|
||||
u32 day_week;
|
||||
u32 day_month;
|
||||
u64 name;
|
||||
i32 dst;
|
||||
u32 utc_rel;
|
||||
};
|
||||
static_assert(sizeof(CalendarAdditionalInfo)==24);
|
||||
|
||||
ITimeZoneService(const DeviceState &state, ServiceManager& manager);
|
||||
|
||||
/**
|
||||
* @brief This receives a u64 #PosixTime (https://switchbrew.org/wiki/PSC_services#PosixTime), and returns a #CalendarTime (https://switchbrew.org/wiki/PSC_services#CalendarTime), #CalendarAdditionalInfo (https://switchbrew.org/wiki/PSC_services#CalendarAdditionalInfo)
|
||||
*/
|
||||
void ToCalendarTimeWithMyRule(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
};
|
||||
}
|
@ -20,9 +20,8 @@ namespace skyline::kernel::type {
|
||||
/**
|
||||
* @param state The state of the device
|
||||
* @param serviceObject A shared pointer to the service class
|
||||
* @param serviceType The type of the service
|
||||
*/
|
||||
KSession(const DeviceState &state, std::shared_ptr<service::BaseService> &serviceObject, const service::Service &serviceType) : serviceObject(serviceObject), serviceType(serviceType), KSyncObject(state, KType::KSession) {}
|
||||
KSession(const DeviceState &state, std::shared_ptr<service::BaseService> &serviceObject) : serviceObject(serviceObject), serviceType(serviceObject->serviceType), KSyncObject(state, KType::KSession) {}
|
||||
|
||||
/**
|
||||
* This converts this session into a domain session (https://switchbrew.org/wiki/IPC_Marshalling#Domains)
|
||||
|
@ -37,9 +37,14 @@ namespace skyline::loader {
|
||||
if (instrSvc->Verify()) {
|
||||
instr::Brk brk(static_cast<u16>(instrSvc->value));
|
||||
*address = *reinterpret_cast<u32 *>(&brk);
|
||||
} else if (instrMrs->Verify() && instrMrs->srcReg == constant::TpidrroEl0) {
|
||||
} else if (instrMrs->Verify()) {
|
||||
if(instrMrs->srcReg == constant::TpidrroEl0) {
|
||||
instr::Brk brk(static_cast<u16>(constant::SvcLast + 1 + instrMrs->dstReg));
|
||||
*address = *reinterpret_cast<u32 *>(&brk);
|
||||
} else if(instrMrs->srcReg == constant::CntpctEl0) {
|
||||
instr::Mrs mrs(constant::CntvctEl0, instrMrs->dstReg);
|
||||
*address = *reinterpret_cast<u32 *>(&mrs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user