2019-09-24 22:54:27 +02:00
|
|
|
#include "KProcess.h"
|
2019-10-13 10:04:47 +02:00
|
|
|
#include <nce.h>
|
2019-11-22 15:59:50 +01:00
|
|
|
#include <os.h>
|
2019-09-24 22:54:27 +02:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
2020-01-11 20:28:44 +01:00
|
|
|
#include <sys/uio.h>
|
2019-09-24 22:54:27 +02:00
|
|
|
|
|
|
|
namespace skyline::kernel::type {
|
|
|
|
KProcess::TlsPage::TlsPage(u64 address) : address(address) {}
|
|
|
|
|
|
|
|
u64 KProcess::TlsPage::ReserveSlot() {
|
|
|
|
if (Full())
|
|
|
|
throw exception("Trying to get TLS slot from full page");
|
|
|
|
slot[index] = true;
|
|
|
|
return Get(index++); // ++ on right will cause increment after evaluation of expression
|
|
|
|
}
|
|
|
|
|
|
|
|
u64 KProcess::TlsPage::Get(u8 slotNo) {
|
|
|
|
if (slotNo >= constant::TlsSlots)
|
|
|
|
throw exception("TLS slot is out of range");
|
|
|
|
return address + (constant::TlsSlotSize * slotNo);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KProcess::TlsPage::Full() {
|
|
|
|
return slot[constant::TlsSlots - 1];
|
|
|
|
}
|
|
|
|
|
2019-10-13 10:04:47 +02:00
|
|
|
u64 KProcess::GetTlsSlot() {
|
Framebuffer and NativeActivity
What was added:
* Framebuffer
* NativeActivity
* NV Services
* IOCTL Handler
* NV Devices:
* * /dev/nvmap - 0xC0080101, 0xC0080103, 0xC0200104, 0xC0180105, 0xC00C0109, 0xC008010E
* * /dev/nvhost-as-gpu
* * /dev/nvhost-channel - 0x40044801, 0xC0104809, 0xC010480B, 0xC018480C, 0x4004480D, 0xC020481A, 0x40084714
* * /dev/nvhost-ctrl
* * /dev/nvhost-ctrl-gpu - 0x80044701, 0x80284702, 0xC0184706, 0xC0B04705, 0x80084714
* SVCs:
* * SetMemoryAttribute
* * CreateTransferMemory
* * ResetSignal
* * GetSystemTick
* Addition of Compact Logger
What was fixed:
* SVCs:
* * SetHeapSize
* * SetMemoryAttribute
* * QueryMemory
* A release build would not set CMAKE_BUILD_TYPE to "RELEASE"
* The logger code was simplified
2019-11-13 21:09:31 +01:00
|
|
|
for (auto &tlsPage: tlsPages) {
|
|
|
|
if (!tlsPage->Full())
|
|
|
|
return tlsPage->ReserveSlot();
|
|
|
|
}
|
2020-01-07 03:36:08 +01:00
|
|
|
auto tlsMem = NewHandle<KPrivateMemory>(0, PAGE_SIZE, memory::Permission(true, true, false), memory::Type::ThreadLocal, threadMap.at(pid)).item;
|
2019-09-24 22:54:27 +02:00
|
|
|
memoryMap[tlsMem->address] = tlsMem;
|
|
|
|
tlsPages.push_back(std::make_shared<TlsPage>(tlsMem->address));
|
|
|
|
auto &tlsPage = tlsPages.back();
|
2019-10-13 10:04:47 +02:00
|
|
|
if (tlsPages.empty())
|
2019-09-24 22:54:27 +02:00
|
|
|
tlsPage->ReserveSlot(); // User-mode exception handling
|
|
|
|
return tlsPage->ReserveSlot();
|
|
|
|
}
|
|
|
|
|
2020-01-11 05:52:25 +01:00
|
|
|
KProcess::KProcess(const DeviceState &state, pid_t pid, u64 entryPoint, u64 stackBase, u64 stackSize, std::shared_ptr<type::KSharedMemory> &tlsMemory) : pid(pid), mainThreadStackSz(stackSize), KSyncObject(state, KType::KProcess) {
|
2020-01-07 03:36:08 +01:00
|
|
|
auto thread = NewHandle<KThread>(pid, entryPoint, 0x0, stackBase + stackSize, 0, constant::DefaultPriority, this, tlsMemory).item;
|
|
|
|
// Remove GetTlsSlot from KThread ctor and cleanup ctor in general
|
|
|
|
threadMap[pid] = thread;
|
|
|
|
state.nce->WaitThreadInit(thread);
|
|
|
|
thread->tls = GetTlsSlot();
|
Framebuffer and NativeActivity
What was added:
* Framebuffer
* NativeActivity
* NV Services
* IOCTL Handler
* NV Devices:
* * /dev/nvmap - 0xC0080101, 0xC0080103, 0xC0200104, 0xC0180105, 0xC00C0109, 0xC008010E
* * /dev/nvhost-as-gpu
* * /dev/nvhost-channel - 0x40044801, 0xC0104809, 0xC010480B, 0xC018480C, 0x4004480D, 0xC020481A, 0x40084714
* * /dev/nvhost-ctrl
* * /dev/nvhost-ctrl-gpu - 0x80044701, 0x80284702, 0xC0184706, 0xC0B04705, 0x80084714
* SVCs:
* * SetMemoryAttribute
* * CreateTransferMemory
* * ResetSignal
* * GetSystemTick
* Addition of Compact Logger
What was fixed:
* SVCs:
* * SetHeapSize
* * SetMemoryAttribute
* * QueryMemory
* A release build would not set CMAKE_BUILD_TYPE to "RELEASE"
* The logger code was simplified
2019-11-13 21:09:31 +01:00
|
|
|
MapPrivateRegion(constant::HeapAddr, constant::DefHeapSize, {true, true, false}, memory::Type::Heap, memory::Region::Heap);
|
2020-01-11 05:52:25 +01:00
|
|
|
memFd = open(fmt::format("/proc/{}/mem", pid).c_str(), O_RDWR | O_CLOEXEC);
|
2019-09-24 22:54:27 +02:00
|
|
|
if (memFd == -1)
|
Framebuffer and NativeActivity
What was added:
* Framebuffer
* NativeActivity
* NV Services
* IOCTL Handler
* NV Devices:
* * /dev/nvmap - 0xC0080101, 0xC0080103, 0xC0200104, 0xC0180105, 0xC00C0109, 0xC008010E
* * /dev/nvhost-as-gpu
* * /dev/nvhost-channel - 0x40044801, 0xC0104809, 0xC010480B, 0xC018480C, 0x4004480D, 0xC020481A, 0x40084714
* * /dev/nvhost-ctrl
* * /dev/nvhost-ctrl-gpu - 0x80044701, 0x80284702, 0xC0184706, 0xC0B04705, 0x80084714
* SVCs:
* * SetMemoryAttribute
* * CreateTransferMemory
* * ResetSignal
* * GetSystemTick
* Addition of Compact Logger
What was fixed:
* SVCs:
* * SetHeapSize
* * SetMemoryAttribute
* * QueryMemory
* A release build would not set CMAKE_BUILD_TYPE to "RELEASE"
* The logger code was simplified
2019-11-13 21:09:31 +01:00
|
|
|
throw exception("Cannot open file descriptor to /proc/{}/mem, \"{}\"", pid, strerror(errno));
|
2019-09-24 22:54:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
KProcess::~KProcess() {
|
|
|
|
close(memFd);
|
2020-01-11 05:52:25 +01:00
|
|
|
status = Status::Exiting;
|
2019-09-24 22:54:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-10-13 10:04:47 +02:00
|
|
|
* @brief Function executed by all child threads after cloning
|
2019-09-24 22:54:27 +02:00
|
|
|
*/
|
|
|
|
int ExecuteChild(void *) {
|
2019-09-25 11:32:17 +02:00
|
|
|
asm volatile("BRK #0xFF"); // BRK #constant::brkRdy (So we know when the thread/process is ready)
|
2019-09-24 22:54:27 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
u64 CreateThreadFunc(u64 stackTop) {
|
2020-01-11 05:52:25 +01:00
|
|
|
pid_t pid = clone(&ExecuteChild, reinterpret_cast<void *>(stackTop), CLONE_THREAD | CLONE_SIGHAND | CLONE_PTRACE | CLONE_FS | CLONE_VM | CLONE_FILES | CLONE_IO, nullptr);
|
2019-09-24 22:54:27 +02:00
|
|
|
return static_cast<u64>(pid);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr<KThread> KProcess::CreateThread(u64 entryPoint, u64 entryArg, u64 stackTop, u8 priority) {
|
2020-01-07 03:36:08 +01:00
|
|
|
/*
|
|
|
|
* Future Reference:
|
|
|
|
* https://android.googlesource.com/platform/bionic/+/master/libc/bionic/clone.cpp
|
|
|
|
* https://android.googlesource.com/platform/bionic/+/master/libc/arch-arm64/bionic/__bionic_clone.S
|
|
|
|
Registers fregs{};
|
2019-09-24 22:54:27 +02:00
|
|
|
fregs.regs[0] = entryPoint;
|
|
|
|
fregs.regs[1] = stackTop;
|
2020-01-07 03:36:08 +01:00
|
|
|
fregs.x8 = __NR_clone;
|
|
|
|
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs, state.thread->pid);
|
2019-09-24 22:54:27 +02:00
|
|
|
auto pid = static_cast<pid_t>(fregs.regs[0]);
|
|
|
|
if (pid == -1)
|
Framebuffer and NativeActivity
What was added:
* Framebuffer
* NativeActivity
* NV Services
* IOCTL Handler
* NV Devices:
* * /dev/nvmap - 0xC0080101, 0xC0080103, 0xC0200104, 0xC0180105, 0xC00C0109, 0xC008010E
* * /dev/nvhost-as-gpu
* * /dev/nvhost-channel - 0x40044801, 0xC0104809, 0xC010480B, 0xC018480C, 0x4004480D, 0xC020481A, 0x40084714
* * /dev/nvhost-ctrl
* * /dev/nvhost-ctrl-gpu - 0x80044701, 0x80284702, 0xC0184706, 0xC0B04705, 0x80084714
* SVCs:
* * SetMemoryAttribute
* * CreateTransferMemory
* * ResetSignal
* * GetSystemTick
* Addition of Compact Logger
What was fixed:
* SVCs:
* * SetHeapSize
* * SetMemoryAttribute
* * QueryMemory
* A release build would not set CMAKE_BUILD_TYPE to "RELEASE"
* The logger code was simplified
2019-11-13 21:09:31 +01:00
|
|
|
throw exception("Cannot create thread: Address: 0x{:X}, Stack Top: 0x{:X}", entryPoint, stackTop);
|
2019-11-22 15:59:50 +01:00
|
|
|
auto process = NewHandle<KThread>(pid, entryPoint, entryArg, stackTop, GetTlsSlot(), priority, this).item;
|
|
|
|
threadMap[pid] = process;
|
|
|
|
return process;
|
2020-01-07 03:36:08 +01:00
|
|
|
*/
|
2020-01-11 05:52:25 +01:00
|
|
|
return nullptr;
|
2019-09-24 22:54:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void KProcess::ReadMemory(void *destination, u64 offset, size_t size) const {
|
2020-01-11 21:41:54 +01:00
|
|
|
struct iovec local {
|
|
|
|
.iov_base = destination,
|
|
|
|
.iov_len = size
|
|
|
|
};
|
|
|
|
struct iovec remote {
|
|
|
|
.iov_base = reinterpret_cast<void*>(offset),
|
|
|
|
.iov_len = size
|
|
|
|
};
|
|
|
|
|
|
|
|
if (process_vm_readv(pid, &local, 1, &remote, 1, 0) < 0)
|
2020-01-11 20:28:44 +01:00
|
|
|
pread64(memFd, destination, size, offset);
|
2019-09-24 22:54:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void KProcess::WriteMemory(void *source, u64 offset, size_t size) const {
|
2020-01-11 21:41:54 +01:00
|
|
|
struct iovec local {
|
|
|
|
.iov_base = source,
|
|
|
|
.iov_len = size
|
|
|
|
};
|
|
|
|
struct iovec remote {
|
|
|
|
.iov_base = reinterpret_cast<void*>(offset),
|
|
|
|
.iov_len = size
|
|
|
|
};
|
|
|
|
|
|
|
|
if (process_vm_writev(pid, &local, 1, &remote, 1, 0) < 0)
|
2020-01-11 20:28:44 +01:00
|
|
|
pwrite64(memFd, source, size, offset);
|
2019-09-24 22:54:27 +02:00
|
|
|
}
|
|
|
|
|
2019-10-13 10:04:47 +02:00
|
|
|
KProcess::HandleOut<KPrivateMemory> KProcess::MapPrivateRegion(u64 address, size_t size, const memory::Permission perms, const memory::Type type, const memory::Region region) {
|
2020-01-07 03:36:08 +01:00
|
|
|
auto mem = NewHandle<KPrivateMemory>(address, size, perms, type, threadMap.at(pid));
|
2019-10-13 10:04:47 +02:00
|
|
|
memoryMap[mem.item->address] = mem.item;
|
|
|
|
memoryRegionMap[region] = mem.item;
|
|
|
|
return mem;
|
|
|
|
}
|
|
|
|
|
Framebuffer and NativeActivity
What was added:
* Framebuffer
* NativeActivity
* NV Services
* IOCTL Handler
* NV Devices:
* * /dev/nvmap - 0xC0080101, 0xC0080103, 0xC0200104, 0xC0180105, 0xC00C0109, 0xC008010E
* * /dev/nvhost-as-gpu
* * /dev/nvhost-channel - 0x40044801, 0xC0104809, 0xC010480B, 0xC018480C, 0x4004480D, 0xC020481A, 0x40084714
* * /dev/nvhost-ctrl
* * /dev/nvhost-ctrl-gpu - 0x80044701, 0x80284702, 0xC0184706, 0xC0B04705, 0x80084714
* SVCs:
* * SetMemoryAttribute
* * CreateTransferMemory
* * ResetSignal
* * GetSystemTick
* Addition of Compact Logger
What was fixed:
* SVCs:
* * SetHeapSize
* * SetMemoryAttribute
* * QueryMemory
* A release build would not set CMAKE_BUILD_TYPE to "RELEASE"
* The logger code was simplified
2019-11-13 21:09:31 +01:00
|
|
|
bool KProcess::UnmapPrivateRegion(const skyline::memory::Region region) {
|
|
|
|
if (!memoryRegionMap.count(region))
|
|
|
|
return false;
|
|
|
|
memoryMap.erase(memoryRegionMap.at(region)->address);
|
|
|
|
memoryRegionMap.erase(region);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-10-13 10:04:47 +02:00
|
|
|
size_t KProcess::GetProgramSize() {
|
|
|
|
size_t sharedSize = 0;
|
|
|
|
for (auto ®ion : memoryRegionMap)
|
|
|
|
sharedSize += region.second->size;
|
|
|
|
return sharedSize;
|
2019-09-24 22:54:27 +02:00
|
|
|
}
|
2019-10-16 14:41:30 +02:00
|
|
|
|
|
|
|
void KProcess::MutexLock(u64 address) {
|
2020-01-11 05:52:25 +01:00
|
|
|
try {
|
|
|
|
auto mtx = mutexMap.at(address);
|
|
|
|
pthread_mutex_lock(&mtx);
|
|
|
|
u32 mtxVal = ReadMemory<u32>(address);
|
2020-01-01 14:11:25 +01:00
|
|
|
mtxVal = (mtxVal & ~constant::MtxOwnerMask) | state.thread->handle;
|
2020-01-11 05:52:25 +01:00
|
|
|
WriteMemory(mtxVal, address);
|
|
|
|
} catch (const std::out_of_range &) {
|
|
|
|
mutexMap[address] = PTHREAD_MUTEX_INITIALIZER;
|
2019-10-16 14:41:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KProcess::MutexUnlock(u64 address) {
|
2020-01-11 05:52:25 +01:00
|
|
|
try {
|
|
|
|
auto mtx = mutexMap.at(address);
|
|
|
|
u32 mtxVal = ReadMemory<u32>(address);
|
|
|
|
if ((mtxVal & constant::MtxOwnerMask) != state.thread->handle)
|
|
|
|
throw exception("A non-owner thread tried to release a mutex");
|
2019-10-16 14:41:30 +02:00
|
|
|
mtxVal = 0;
|
2020-01-11 05:52:25 +01:00
|
|
|
WriteMemory(mtxVal, address);
|
|
|
|
pthread_mutex_unlock(&mtx);
|
|
|
|
} catch (const std::out_of_range &) {
|
|
|
|
mutexMap[address] = PTHREAD_MUTEX_INITIALIZER;
|
2019-10-16 14:41:30 +02:00
|
|
|
}
|
Framebuffer and NativeActivity
What was added:
* Framebuffer
* NativeActivity
* NV Services
* IOCTL Handler
* NV Devices:
* * /dev/nvmap - 0xC0080101, 0xC0080103, 0xC0200104, 0xC0180105, 0xC00C0109, 0xC008010E
* * /dev/nvhost-as-gpu
* * /dev/nvhost-channel - 0x40044801, 0xC0104809, 0xC010480B, 0xC018480C, 0x4004480D, 0xC020481A, 0x40084714
* * /dev/nvhost-ctrl
* * /dev/nvhost-ctrl-gpu - 0x80044701, 0x80284702, 0xC0184706, 0xC0B04705, 0x80084714
* SVCs:
* * SetMemoryAttribute
* * CreateTransferMemory
* * ResetSignal
* * GetSystemTick
* Addition of Compact Logger
What was fixed:
* SVCs:
* * SetHeapSize
* * SetMemoryAttribute
* * QueryMemory
* A release build would not set CMAKE_BUILD_TYPE to "RELEASE"
* The logger code was simplified
2019-11-13 21:09:31 +01:00
|
|
|
}
|
2019-09-24 22:54:27 +02:00
|
|
|
}
|