Initial commit

This commit is contained in:
InoriRus
2021-12-01 19:29:27 +10:00
parent b1e7dcdc5d
commit 43f49c8763
1843 changed files with 1111694 additions and 0 deletions
+444
View File
@@ -0,0 +1,444 @@
#include "Emulator/Kernel/EventFlag.h"
#include "Kyty/Core/Common.h"
#include "Kyty/Core/DbgAssert.h"
#include "Kyty/Core/String.h"
#include "Kyty/Core/Threads.h"
#include "Kyty/Core/Timer.h"
#include "Emulator/Libs/Errno.h"
#include "Emulator/Libs/Libs.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Libs::LibKernel::EventFlag {
LIB_NAME("libkernel", "libkernel");
class KernelEventFlagPrivate
{
public:
enum class Result
{
Ok,
AlreadyWaiting,
TimedOut,
Canceled,
Deleted
};
enum class ClearMode
{
None,
All,
Bits
};
enum class WaitMode
{
And,
Or
};
KernelEventFlagPrivate(const String& name, bool flag, uint64_t bits): m_name(name), m_single_thread(flag), m_bits(bits) {};
virtual ~KernelEventFlagPrivate();
KYTY_CLASS_NO_COPY(KernelEventFlagPrivate);
void Set(uint64_t bits);
void Clear(uint64_t bits);
void Cancel(uint64_t bits, int* num_waiting_threads);
Result Wait(uint64_t bits, WaitMode wait_mode, ClearMode clear_mode, uint64_t* result, uint32_t* ptr_micros);
Result Poll(uint64_t bits, WaitMode wait_mode, ClearMode clear_mode, uint64_t* result)
{
uint32_t micros = 0;
return Wait(bits, wait_mode, clear_mode, result, &micros);
}
private:
enum class Status
{
Set,
Canceled,
Deleted
};
Core::Mutex m_mutex;
Core::CondVar m_cond_var;
Status m_status = Status::Set;
int m_waiting_threads = 0;
String m_name;
bool m_single_thread = false;
uint64_t m_bits = 0;
};
KernelEventFlagPrivate::~KernelEventFlagPrivate()
{
Core::LockGuard lock(m_mutex);
while (m_status != Status::Set)
{
m_mutex.Unlock();
Core::Thread::SleepMicro(10);
m_mutex.Lock();
}
m_status = Status::Deleted;
m_cond_var.SignalAll();
while (m_waiting_threads > 0)
{
m_mutex.Unlock();
Core::Thread::SleepMicro(10);
m_mutex.Lock();
}
}
KernelEventFlagPrivate::Result KernelEventFlagPrivate::Wait(uint64_t bits, WaitMode wait_mode, ClearMode clear_mode, uint64_t* result,
uint32_t* ptr_micros)
{
Core::LockGuard lock(m_mutex);
uint32_t micros = 0;
bool infinitely = true;
if (ptr_micros != nullptr)
{
micros = *ptr_micros;
infinitely = false;
}
uint32_t elapsed = 0;
Core::Timer t;
t.Start();
if (m_single_thread && m_waiting_threads > 0)
{
return Result::AlreadyWaiting;
}
while (!((wait_mode == WaitMode::And && (m_bits & bits) == bits) || (wait_mode == WaitMode::Or && (m_bits & bits) != 0)))
{
if ((elapsed >= micros && !infinitely))
{
if (result != nullptr)
{
*result = m_bits;
}
*ptr_micros = 0;
return Result::TimedOut;
}
m_waiting_threads++;
if (infinitely)
{
m_cond_var.Wait(&m_mutex);
} else
{
m_cond_var.WaitFor(&m_mutex, micros - elapsed);
}
m_waiting_threads--;
elapsed = static_cast<uint32_t>(t.GetTimeS() * 1000000.0);
if (m_status == Status::Canceled)
{
if (result != nullptr)
{
*result = m_bits;
}
if (ptr_micros != nullptr)
{
*ptr_micros = (elapsed >= micros ? 0 : micros - elapsed);
}
return Result::Canceled;
}
if (m_status == Status::Deleted)
{
if (result != nullptr)
{
*result = m_bits;
}
if (ptr_micros != nullptr)
{
*ptr_micros = (elapsed >= micros ? 0 : micros - elapsed);
}
return Result::Deleted;
}
}
if (result != nullptr)
{
*result = m_bits;
}
if (clear_mode == ClearMode::All)
{
m_bits = 0;
} else if (clear_mode == ClearMode::Bits)
{
m_bits &= ~bits;
}
if (ptr_micros != nullptr)
{
*ptr_micros = (elapsed >= micros ? 0 : micros - elapsed);
}
return Result::Ok;
}
void KernelEventFlagPrivate::Set(uint64_t bits)
{
Core::LockGuard lock(m_mutex);
EXIT_NOT_IMPLEMENTED(m_status == Status::Deleted);
while (m_status != Status::Set)
{
m_mutex.Unlock();
Core::Thread::SleepMicro(10);
m_mutex.Lock();
}
m_bits |= bits;
m_cond_var.SignalAll();
}
void KernelEventFlagPrivate::Clear(uint64_t bits)
{
Core::LockGuard lock(m_mutex);
EXIT_NOT_IMPLEMENTED(m_status == Status::Deleted);
while (m_status != Status::Set)
{
m_mutex.Unlock();
Core::Thread::SleepMicro(10);
m_mutex.Lock();
}
m_bits &= bits;
}
void KernelEventFlagPrivate::Cancel(uint64_t bits, int* num_waiting_threads)
{
Core::LockGuard lock(m_mutex);
EXIT_NOT_IMPLEMENTED(m_status == Status::Deleted);
while (m_status != Status::Set)
{
m_mutex.Unlock();
Core::Thread::SleepMicro(10);
m_mutex.Lock();
}
if (num_waiting_threads != nullptr)
{
*num_waiting_threads = m_waiting_threads;
}
m_status = Status::Canceled;
m_bits = bits;
m_cond_var.SignalAll();
while (m_waiting_threads > 0)
{
m_mutex.Unlock();
Core::Thread::SleepMicro(10);
m_mutex.Lock();
}
m_status = Status::Set;
}
int KYTY_SYSV_ABI KernelCreateEventFlag(KernelEventFlag* ef, const char* name, uint32_t attr, uint64_t init_pattern, const void* param)
{
PRINT_NAME();
EXIT_NOT_IMPLEMENTED(param != nullptr);
if (ef == nullptr || name == nullptr)
{
return KERNEL_ERROR_EINVAL;
}
bool single = false;
switch (attr)
{
case 0x10: single = true; break;
case 0x20: single = false; break;
default: EXIT("unknown attr: %u\n", attr);
}
*ef = new KernelEventFlagPrivate(String::FromUtf8(name), single, init_pattern);
printf("\tEventFlag create: %s\n", name);
return OK;
}
int KYTY_SYSV_ABI KernelDeleteEventFlag(KernelEventFlag ef)
{
PRINT_NAME();
if (ef == nullptr)
{
return KERNEL_ERROR_ESRCH;
}
delete ef;
return OK;
}
int KYTY_SYSV_ABI KernelWaitEventFlag(KernelEventFlag ef, uint64_t bit_pattern, uint32_t wait_mode, uint64_t* result_pat,
KernelUseconds* timeout)
{
PRINT_NAME();
if (ef == nullptr)
{
return KERNEL_ERROR_ESRCH;
}
if (bit_pattern == 0)
{
return KERNEL_ERROR_EINVAL;
}
KernelEventFlagPrivate::WaitMode wait = KernelEventFlagPrivate::WaitMode::And;
KernelEventFlagPrivate::ClearMode clear = KernelEventFlagPrivate::ClearMode::None;
switch (wait_mode & 0xfu)
{
case 0x01: wait = KernelEventFlagPrivate::WaitMode::And; break;
case 0x02: wait = KernelEventFlagPrivate::WaitMode::Or; break;
default: EXIT("unknown mode: %u\n", wait_mode);
}
switch (wait_mode & 0xf0u)
{
case 0x00: clear = KernelEventFlagPrivate::ClearMode::None; break;
case 0x10: clear = KernelEventFlagPrivate::ClearMode::All; break;
case 0x20: clear = KernelEventFlagPrivate::ClearMode::Bits; break;
default: EXIT("unknown mode: %u\n", wait_mode);
}
auto result = ef->Wait(bit_pattern, wait, clear, result_pat, timeout);
int ret = OK;
switch (result)
{
case KernelEventFlagPrivate::Result::Ok: ret = OK; break;
case KernelEventFlagPrivate::Result::AlreadyWaiting: ret = KERNEL_ERROR_EPERM; break;
case KernelEventFlagPrivate::Result::TimedOut: ret = KERNEL_ERROR_ETIMEDOUT; break;
case KernelEventFlagPrivate::Result::Canceled: ret = KERNEL_ERROR_ECANCELED; break;
case KernelEventFlagPrivate::Result::Deleted: ret = KERNEL_ERROR_EACCES; break;
}
return ret;
}
int KYTY_SYSV_ABI KernelPollEventFlag(KernelEventFlag ef, uint64_t bit_pattern, uint32_t wait_mode, uint64_t* result_pat)
{
PRINT_NAME();
if (ef == nullptr)
{
return KERNEL_ERROR_ESRCH;
}
if (bit_pattern == 0)
{
return KERNEL_ERROR_EINVAL;
}
KernelEventFlagPrivate::WaitMode wait = KernelEventFlagPrivate::WaitMode::And;
KernelEventFlagPrivate::ClearMode clear = KernelEventFlagPrivate::ClearMode::None;
switch (wait_mode & 0xfu)
{
case 0x01: wait = KernelEventFlagPrivate::WaitMode::And; break;
case 0x02: wait = KernelEventFlagPrivate::WaitMode::Or; break;
default: EXIT("unknown mode: %u\n", wait_mode);
}
switch (wait_mode & 0xf0u)
{
case 0x00: clear = KernelEventFlagPrivate::ClearMode::None; break;
case 0x10: clear = KernelEventFlagPrivate::ClearMode::All; break;
case 0x20: clear = KernelEventFlagPrivate::ClearMode::Bits; break;
default: EXIT("unknown mode: %u\n", wait_mode);
}
auto result = ef->Poll(bit_pattern, wait, clear, result_pat);
int ret = OK;
switch (result)
{
case KernelEventFlagPrivate::Result::Ok: ret = OK; break;
case KernelEventFlagPrivate::Result::AlreadyWaiting: ret = KERNEL_ERROR_EPERM; break;
case KernelEventFlagPrivate::Result::TimedOut:
case KernelEventFlagPrivate::Result::Canceled:
case KernelEventFlagPrivate::Result::Deleted: ret = KERNEL_ERROR_EBUSY; break;
}
return ret;
}
int KYTY_SYSV_ABI KernelSetEventFlag(KernelEventFlag ef, uint64_t bit_pattern)
{
PRINT_NAME();
if (ef == nullptr)
{
return KERNEL_ERROR_ESRCH;
}
ef->Set(bit_pattern);
return OK;
}
int KYTY_SYSV_ABI KernelClearEventFlag(KernelEventFlag ef, uint64_t bit_pattern)
{
PRINT_NAME();
if (ef == nullptr)
{
return KERNEL_ERROR_ESRCH;
}
ef->Clear(bit_pattern);
return OK;
}
int KYTY_SYSV_ABI KernelCancelEventFlag(KernelEventFlag ef, uint64_t set_pattern, int* num_wait_threads)
{
PRINT_NAME();
if (ef == nullptr)
{
return KERNEL_ERROR_ESRCH;
}
ef->Cancel(set_pattern, num_wait_threads);
return OK;
}
} // namespace Kyty::Libs::LibKernel::EventFlag
#endif // KYTY_EMU_ENABLED
+389
View File
@@ -0,0 +1,389 @@
#include "Emulator/Kernel/EventQueue.h"
#include "Kyty/Core/Common.h"
#include "Kyty/Core/DbgAssert.h"
#include "Kyty/Core/LinkList.h"
#include "Kyty/Core/String.h"
#include "Kyty/Core/Threads.h"
#include "Kyty/Core/Timer.h"
#include "Emulator/Libs/Errno.h"
#include "Emulator/Libs/Libs.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Libs::LibKernel::EventQueue {
LIB_NAME("libkernel", "libkernel");
class KernelEqueuePrivate
{
public:
KernelEqueuePrivate() = default;
virtual ~KernelEqueuePrivate();
KYTY_CLASS_NO_COPY(KernelEqueuePrivate);
[[nodiscard]] const String& GetName() const { return m_name; }
void SetName(const String& m_name) { this->m_name = m_name; }
void AddEvent(const KernelEqueueEvent& event);
bool TriggerEvent(uintptr_t ident, int16_t filter, void* trigger_data);
bool DeleteEvent(uintptr_t ident, int16_t filter);
int GetTriggeredEvents(KernelEvent* ev, int num);
int WaitForEvents(KernelEvent* ev, int num, uint32_t micros);
private:
Core::List<KernelEqueueEvent> m_events;
Core::Mutex m_mutex;
Core::CondVar m_cond_var;
String m_name;
};
KernelEqueuePrivate::~KernelEqueuePrivate()
{
Core::LockGuard lock(m_mutex);
FOR_LIST(index, m_events)
{
auto& event = m_events[index];
if (event.filter.delete_func != nullptr)
{
event.filter.delete_func(&event);
}
}
}
int KernelEqueuePrivate::GetTriggeredEvents(KernelEvent* ev, int num)
{
Core::LockGuard lock(m_mutex);
EXIT_IF(num < 1);
int ret = 0;
FOR_LIST(index, m_events)
{
auto& event = m_events[index];
if (event.triggered)
{
ev[ret++] = event.event;
if (event.filter.reset_func != nullptr)
{
event.filter.reset_func(&event);
}
if (ret >= num)
{
break;
}
}
}
return ret;
}
int KernelEqueuePrivate::WaitForEvents(KernelEvent* ev, int num, uint32_t micros)
{
Core::LockGuard lock(m_mutex);
EXIT_IF(num < 1);
uint32_t elapsed = 0;
Core::Timer t;
t.Start();
for (;;)
{
int ret = GetTriggeredEvents(ev, num);
if (ret > 0 || (elapsed >= micros && micros != 0))
{
return ret;
}
if (micros == 0)
{
m_cond_var.Wait(&m_mutex);
} else
{
m_cond_var.WaitFor(&m_mutex, micros - elapsed);
}
elapsed = static_cast<uint32_t>(t.GetTimeS() * 1000000.0);
}
return 0;
}
void KernelEqueuePrivate::AddEvent(const KernelEqueueEvent& event)
{
Core::LockGuard lock(m_mutex);
if (auto index = m_events.Find(event.event.ident, event.event.filter,
[](auto e, auto ident, auto filter) { return e.event.ident == ident && e.event.filter == filter; });
m_events.IndexValid(index))
{
m_events[index] = event;
} else
{
m_events.Add(event);
}
if (event.triggered)
{
m_cond_var.Signal();
}
}
bool KernelEqueuePrivate::TriggerEvent(uintptr_t ident, int16_t filter, void* trigger_data)
{
Core::LockGuard lock(m_mutex);
if (auto index = m_events.Find(ident, filter,
[](auto e, auto ident, auto filter) { return e.event.ident == ident && e.event.filter == filter; });
m_events.IndexValid(index))
{
auto& event = m_events[index];
if (event.filter.trigger_func != nullptr)
{
event.filter.trigger_func(&event, trigger_data);
} else
{
event.triggered = true;
}
m_cond_var.Signal();
return true;
}
return false;
}
bool KernelEqueuePrivate::DeleteEvent(uintptr_t ident, int16_t filter)
{
Core::LockGuard lock(m_mutex);
if (auto index = m_events.Find(ident, filter,
[](auto e, auto ident, auto filter) { return e.event.ident == ident && e.event.filter == filter; });
m_events.IndexValid(index))
{
auto& event = m_events[index];
if (event.filter.delete_func != nullptr)
{
event.filter.delete_func(&event);
}
m_events.Remove(index);
return true;
}
return false;
}
int KYTY_SYSV_ABI KernelCreateEqueue(KernelEqueue* eq, const char* name)
{
PRINT_NAME();
if (eq == nullptr || name == nullptr)
{
return KERNEL_ERROR_EINVAL;
}
*eq = new KernelEqueuePrivate;
(*eq)->SetName(String::FromUtf8(name));
printf("\tEqueue create: %s\n", name);
return OK;
}
int KYTY_SYSV_ABI KernelAddEvent(KernelEqueue eq, const KernelEqueueEvent& event)
{
if (eq == nullptr)
{
return KERNEL_ERROR_EBADF;
}
eq->AddEvent(event);
return OK;
}
int KYTY_SYSV_ABI KernelTriggerEvent(KernelEqueue eq, uintptr_t ident, int16_t filter, void* trigger_data)
{
if (eq == nullptr)
{
return KERNEL_ERROR_EBADF;
}
if (!eq->TriggerEvent(ident, filter, trigger_data))
{
return KERNEL_ERROR_ENOENT;
}
return OK;
}
int KYTY_SYSV_ABI KernelDeleteEvent(KernelEqueue eq, uintptr_t ident, int16_t filter)
{
if (eq == nullptr)
{
return KERNEL_ERROR_EBADF;
}
if (!eq->DeleteEvent(ident, filter))
{
return KERNEL_ERROR_ENOENT;
}
return OK;
}
int KYTY_SYSV_ABI KernelDeleteEqueue(KernelEqueue eq)
{
PRINT_NAME();
if (eq == nullptr)
{
return KERNEL_ERROR_EBADF;
}
printf("\tEqueue delete: %s\n", eq->GetName().C_Str());
delete eq;
return OK;
}
int KYTY_SYSV_ABI KernelWaitEqueue(KernelEqueue eq, KernelEvent* ev, int num, int* out, const KernelUseconds* timo)
{
PRINT_NAME();
if (eq == nullptr)
{
return KERNEL_ERROR_EBADF;
}
if (ev == nullptr)
{
return KERNEL_ERROR_EFAULT;
}
if (num < 1)
{
return KERNEL_ERROR_EINVAL;
}
EXIT_NOT_IMPLEMENTED(out == nullptr);
printf("\tEqueue wait: %s\n", eq->GetName().C_Str());
if (timo == nullptr)
{
*out = eq->WaitForEvents(ev, num, 0);
}
if (timo != nullptr)
{
if (*timo == 0)
{
*out = eq->GetTriggeredEvents(ev, num);
} else
{
*out = eq->WaitForEvents(ev, num, *timo);
}
}
if (*out == 0)
{
printf("\ttimedout\n");
return KERNEL_ERROR_ETIMEDOUT;
}
printf("\treceived %u events\n", *out);
return OK;
}
intptr_t KYTY_SYSV_ABI KernelGetEventData(const KernelEvent* ev)
{
PRINT_NAME();
if (ev != nullptr)
{
return ev->data;
}
return 0;
}
intptr_t KYTY_SYSV_ABI KernelGetEventFflags(const KernelEvent* ev)
{
PRINT_NAME();
if (ev != nullptr)
{
return ev->fflags;
}
return 0;
}
int KYTY_SYSV_ABI KernelGetEventFilter(const KernelEvent* ev)
{
PRINT_NAME();
if (ev != nullptr)
{
return ev->filter;
}
return 0;
}
uintptr_t KYTY_SYSV_ABI KernelGetEventId(const KernelEvent* ev)
{
PRINT_NAME();
if (ev != nullptr)
{
return ev->ident;
}
return 0;
}
void* KYTY_SYSV_ABI KernelGetEventUserData(const KernelEvent* ev)
{
PRINT_NAME();
if (ev != nullptr)
{
return ev->udata;
}
return nullptr;
}
int KYTY_SYSV_ABI KernelGetEventError(const KernelEvent* /*ev*/)
{
PRINT_NAME();
KYTY_NOT_IMPLEMENTED;
return 0;
}
} // namespace Kyty::Libs::LibKernel::EventQueue
#endif // KYTY_EMU_ENABLED
+928
View File
@@ -0,0 +1,928 @@
#include "Emulator/Kernel/FileSystem.h"
#include "Kyty/Core/Common.h"
#include "Kyty/Core/DateTime.h"
#include "Kyty/Core/DbgAssert.h"
#include "Kyty/Core/File.h"
#include "Kyty/Core/Threads.h"
#include "Kyty/Core/Vector.h"
#include "Emulator/Libs/Errno.h"
#include "Emulator/Libs/Libs.h"
#include <atomic>
#include <climits>
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Libs::LibKernel::FileSystem {
LIB_NAME("libkernel", "libkernel");
constexpr int DESCRIPTOR_MIN = 3;
class MountPoints
{
public:
struct MountPair
{
String dir;
String point;
};
MountPoints() { EXIT_NOT_IMPLEMENTED(!Core::Thread::IsMainThread()); }
virtual ~MountPoints() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(MountPoints);
void Mount(const String& folder, const String& point);
void Umount(const String& folder_or_point);
[[nodiscard]] String GetRealFilename(const String& mounted_file_name);
[[nodiscard]] String GetRealDirectory(const String& mounted_directory);
private:
Vector<MountPair> m_mount_pairs;
Core::Mutex m_mutex;
};
struct File
{
Core::File f;
String name;
String real_name;
std::atomic_bool opened;
std::atomic_bool directory;
Core::Mutex mutex;
Vector<Core::File::DirEntry> dents;
uint32_t dents_index;
};
class FileDescriptors
{
public:
FileDescriptors() { EXIT_NOT_IMPLEMENTED(!Core::Thread::IsMainThread()); }
virtual ~FileDescriptors() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(FileDescriptors);
int CreateDescriptor();
void DeleteDescriptor(int d);
File* GetFile(int d);
File* GetFile(const String& real_name);
void CloseAll();
private:
Vector<File*> m_files;
Core::Mutex m_mutex;
};
static MountPoints* g_mount_points = nullptr;
static FileDescriptors* g_files = nullptr;
static void sec_to_timespec(KernelTimespec* ts, double sec)
{
ts->tv_sec = static_cast<int64_t>(sec);
ts->tv_nsec = static_cast<int64_t>((sec - static_cast<double>(ts->tv_sec)) * 1000000000.0);
}
int FileDescriptors::CreateDescriptor()
{
Core::LockGuard lock(m_mutex);
auto* file = new File {};
file->opened = false;
file->directory = false;
int files_num = static_cast<int>(m_files.Size());
for (int index = 0; index < files_num; index++)
{
if (m_files.At(index) == nullptr)
{
m_files[index] = file;
return index + DESCRIPTOR_MIN;
}
}
m_files.Add(file);
return static_cast<int>(m_files.Size()) + DESCRIPTOR_MIN - 1;
}
void FileDescriptors::DeleteDescriptor(int d)
{
Core::LockGuard lock(m_mutex);
auto index = static_cast<uint32_t>(d - DESCRIPTOR_MIN);
EXIT_IF(!m_files.IndexValid(index));
EXIT_IF(m_files.At(index) == nullptr);
EXIT_IF(m_files.At(index)->opened);
delete m_files.At(index);
m_files[index] = nullptr;
}
File* FileDescriptors::GetFile(int d)
{
Core::LockGuard lock(m_mutex);
auto index = static_cast<uint32_t>(d - DESCRIPTOR_MIN);
EXIT_IF(!m_files.IndexValid(index));
return m_files.At(index);
}
File* FileDescriptors::GetFile(const String& real_name)
{
Core::LockGuard lock(m_mutex);
for (auto* f: m_files)
{
if (f != nullptr && f->real_name == real_name)
{
return f;
}
}
return nullptr;
}
void FileDescriptors::CloseAll()
{
Core::LockGuard lock(m_mutex);
for (auto& f: m_files)
{
if (f != nullptr && f->opened)
{
f->f.Close();
delete f;
f = nullptr;
}
}
}
void MountPoints::Mount(const String& folder, const String& point)
{
Core::LockGuard lock(m_mutex);
auto folder_str = folder.FixDirectorySlash();
auto point_str = point.FixDirectorySlash();
Umount(folder_str);
Umount(point_str);
MountPair p;
p.dir = folder_str;
p.point = point_str;
m_mount_pairs.Add(p);
}
void MountPoints::Umount(const String& folder_or_point)
{
Core::LockGuard lock(m_mutex);
auto folder_or_point_str = folder_or_point.FixDirectorySlash();
if (auto index =
m_mount_pairs.Find(folder_or_point_str, [](const MountPair& p, const String& s) { return p.dir == s || p.point == s; });
m_mount_pairs.IndexValid(index))
{
m_mount_pairs.RemoveAt(index);
}
}
String MountPoints::GetRealFilename(const String& mounted_file_name)
{
Core::LockGuard lock(m_mutex);
auto mounted_path = mounted_file_name.FixFilenameSlash().DirectoryWithoutFilename();
if (auto index = m_mount_pairs.Find(mounted_path, [](const MountPair& p, const String& s) { return s.StartsWith(p.point); });
m_mount_pairs.IndexValid(index))
{
const auto& p = m_mount_pairs.At(index);
return p.dir + mounted_file_name.RemoveFirst(p.point.Size());
}
return mounted_file_name;
}
String MountPoints::GetRealDirectory(const String& mounted_directory)
{
Core::LockGuard lock(m_mutex);
auto mounted_path = mounted_directory.FixDirectorySlash();
if (auto index = m_mount_pairs.Find(mounted_path, [](const MountPair& p, const String& s) { return s.StartsWith(p.point); });
m_mount_pairs.IndexValid(index))
{
const auto& p = m_mount_pairs.At(index);
return p.dir + mounted_directory.RemoveFirst(p.point.Size());
}
return mounted_directory;
}
KYTY_SUBSYSTEM_INIT(FileSystem)
{
g_mount_points = new MountPoints;
g_files = new FileDescriptors;
}
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(FileSystem)
{
if (g_files != nullptr)
{
g_files->CloseAll();
}
}
KYTY_SUBSYSTEM_DESTROY(FileSystem)
{
if (g_files != nullptr)
{
g_files->CloseAll();
}
}
void Mount(const String& folder, const String& point)
{
EXIT_IF(g_mount_points == nullptr);
g_mount_points->Mount(folder, point);
}
void Umount(const String& folder_or_point)
{
EXIT_IF(g_mount_points == nullptr);
g_mount_points->Umount(folder_or_point);
}
String GetRealFilename(const String& mounted_file_name)
{
EXIT_IF(g_mount_points == nullptr);
return g_mount_points->GetRealFilename(mounted_file_name);
}
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
int KYTY_SYSV_ABI KernelOpen(const char* path, int flags, uint16_t mode)
{
PRINT_NAME();
EXIT_IF(g_mount_points == nullptr || g_files == nullptr);
if (path == nullptr)
{
return KERNEL_ERROR_EINVAL;
}
auto flags_u = static_cast<uint32_t>(flags);
printf("\tpath = %s\n", path);
printf("\tflags = %08" PRIx32 "\n", flags_u);
printf("\tmode = %04" PRIx16 "\n", mode);
bool nonblock = (flags_u & 0x0004u) != 0;
bool append = (flags_u & 0x0008u) != 0;
bool fsync = (flags_u & 0x0080u) != 0;
bool sync = (flags_u & 0x0080u) != 0;
bool creat = (flags_u & 0x0200u) != 0;
bool trunc = (flags_u & 0x0400u) != 0;
bool excl = (flags_u & 0x0800u) != 0;
bool dsync = (flags_u & 0x1000u) != 0;
bool direct = (flags_u & 0x00010000u) != 0;
bool directory = (flags_u & 0x00020000u) != 0;
EXIT_NOT_IMPLEMENTED(append || fsync || sync || excl || dsync || direct);
EXIT_NOT_IMPLEMENTED(nonblock && !directory);
flags_u &= 0x3u;
Core::File::Mode rw_mode = Core::File::Mode::Read;
switch (flags_u)
{
case 0: rw_mode = Core::File::Mode::Read; break;
case 1: rw_mode = Core::File::Mode::Write; break;
case 2: rw_mode = Core::File::Mode::ReadWrite; break;
default: EXIT("invalid flag_u: %u\n", flags_u);
}
EXIT_NOT_IMPLEMENTED(directory && rw_mode != Core::File::Mode::Read);
EXIT_NOT_IMPLEMENTED(directory && (trunc || creat));
int descriptor = g_files->CreateDescriptor();
auto* file = g_files->GetFile(descriptor);
EXIT_IF(file == nullptr || file->opened || file->directory);
file->name = path;
file->real_name = (directory ? g_mount_points->GetRealDirectory(file->name) : g_mount_points->GetRealFilename(file->name));
if (trunc && rw_mode == Core::File::Mode::Read)
{
return KERNEL_ERROR_EACCES;
}
if (directory)
{
if (!Core::File::IsDirectoryExisting(file->real_name))
{
g_files->DeleteDescriptor(descriptor);
return KERNEL_ERROR_ENOTDIR;
}
file->dents = Core::File::GetDirEntries(file->real_name);
file->dents_index = 0;
file->directory = true;
printf("\tOpen dir: " FG_WHITE BOLD "%s" DEFAULT ", entries = %" PRIu32 ", " FG_GREEN "[ok]" FG_DEFAULT "\n",
file->real_name.C_Str(), file->dents.Size());
for (const auto& f: file->dents)
{
printf("\t\t%s %s\n", f.is_file ? "[file]" : "[dir ]", f.name.C_Str());
}
} else
{
bool result = false;
EXIT_NOT_IMPLEMENTED(Core::File::IsDirectoryExisting(file->real_name));
if (creat)
{
result = file->f.Create(file->real_name);
printf("\tCreate: " FG_WHITE BOLD "%s" DEFAULT ", %s\n", file->real_name.C_Str(),
(result ? FG_GREEN "[ok]" FG_DEFAULT : FG_RED "[fail]" FG_DEFAULT));
} else
{
result = file->f.Open(file->real_name, rw_mode);
printf("\tOpen: " FG_WHITE BOLD "%s" DEFAULT ", %s\n", file->real_name.C_Str(),
(result ? FG_GREEN "[ok]" FG_DEFAULT : FG_RED "[fail]" FG_DEFAULT));
}
EXIT_NOT_IMPLEMENTED(creat && !trunc);
if (result && trunc)
{
result = file->f.Truncate(0);
}
if (!result || file->f.IsInvalid())
{
g_files->DeleteDescriptor(descriptor);
return KERNEL_ERROR_EACCES;
}
}
file->opened = true;
return descriptor;
}
int KYTY_SYSV_ABI KernelClose(int d)
{
PRINT_NAME();
EXIT_IF(g_files == nullptr);
if (d < DESCRIPTOR_MIN)
{
return KERNEL_ERROR_EPERM;
}
auto* file = g_files->GetFile(d);
if (file == nullptr)
{
return KERNEL_ERROR_EBADF;
}
EXIT_IF(!file->opened);
if (!file->directory)
{
file->f.Close();
}
file->opened = false;
printf("\tClose: " FG_WHITE BOLD "%s" DEFAULT "\n", file->real_name.C_Str());
g_files->DeleteDescriptor(d);
return OK;
}
int64_t KYTY_SYSV_ABI KernelRead(int d, void* buf, size_t nbytes)
{
PRINT_NAME();
EXIT_IF(g_files == nullptr);
if (d < DESCRIPTOR_MIN)
{
return KERNEL_ERROR_EPERM;
}
if (buf == nullptr)
{
return KERNEL_ERROR_EFAULT;
}
auto* file = g_files->GetFile(d);
if (file == nullptr)
{
return KERNEL_ERROR_EBADF;
}
EXIT_NOT_IMPLEMENTED(file->directory);
EXIT_IF(!file->opened);
EXIT_NOT_IMPLEMENTED(nbytes > UINT_MAX);
file->mutex.Lock();
bool is_invalid = file->f.IsInvalid();
uint32_t bytes_read = 0;
file->f.Read(buf, static_cast<uint32_t>(nbytes), &bytes_read);
file->mutex.Unlock();
if (is_invalid)
{
printf("\tfile is invalid\n");
return KERNEL_ERROR_EIO;
}
printf("\tRead %u bytes from: " FG_WHITE BOLD "%s" DEFAULT "\n", bytes_read, file->real_name.C_Str());
return bytes_read;
}
int64_t KYTY_SYSV_ABI KernelWrite(int d, const void* buf, size_t nbytes)
{
PRINT_NAME();
EXIT_IF(g_files == nullptr);
if (d < DESCRIPTOR_MIN)
{
return KERNEL_ERROR_EPERM;
}
if (buf == nullptr)
{
return KERNEL_ERROR_EFAULT;
}
auto* file = g_files->GetFile(d);
if (file == nullptr)
{
return KERNEL_ERROR_EBADF;
}
EXIT_NOT_IMPLEMENTED(file->directory);
EXIT_IF(!file->opened);
EXIT_NOT_IMPLEMENTED(nbytes > UINT_MAX);
file->mutex.Lock();
bool is_invalid = file->f.IsInvalid();
uint32_t bytes_written = 0;
file->f.Write(buf, static_cast<uint32_t>(nbytes), &bytes_written);
file->mutex.Unlock();
if (is_invalid)
{
printf("\tfile is invalid\n");
return KERNEL_ERROR_EIO;
}
printf("\tWrite %u bytes to: " FG_WHITE BOLD "%s" DEFAULT "\n", bytes_written, file->real_name.C_Str());
return bytes_written;
}
int64_t KYTY_SYSV_ABI KernelPread(int d, void* buf, size_t nbytes, int64_t offset)
{
PRINT_NAME();
EXIT_IF(g_files == nullptr);
if (d < DESCRIPTOR_MIN)
{
return KERNEL_ERROR_EPERM;
}
if (buf == nullptr)
{
return KERNEL_ERROR_EFAULT;
}
if (offset < 0)
{
return KERNEL_ERROR_EINVAL;
}
auto* file = g_files->GetFile(d);
if (file == nullptr)
{
return KERNEL_ERROR_EBADF;
}
EXIT_NOT_IMPLEMENTED(file->directory);
EXIT_IF(!file->opened);
EXIT_NOT_IMPLEMENTED(nbytes > UINT_MAX);
file->mutex.Lock();
bool is_invalid = file->f.IsInvalid();
auto pos = file->f.Tell();
uint32_t bytes_read = 0;
file->f.Seek(offset);
file->f.Read(buf, static_cast<uint32_t>(nbytes), &bytes_read);
file->f.Seek(pos);
file->mutex.Unlock();
if (is_invalid)
{
printf("\tfile is invalid\n");
return KERNEL_ERROR_EIO;
}
printf("\tRead %u bytes (pos = %" PRId64 ") from: " FG_WHITE BOLD "%s" DEFAULT "\n", bytes_read, offset, file->real_name.C_Str());
return bytes_read;
}
int64_t KYTY_SYSV_ABI KernelPwrite(int d, const void* buf, size_t nbytes, int64_t offset)
{
PRINT_NAME();
EXIT_IF(g_files == nullptr);
if (d < DESCRIPTOR_MIN)
{
return KERNEL_ERROR_EPERM;
}
if (buf == nullptr)
{
return KERNEL_ERROR_EFAULT;
}
if (offset < 0)
{
return KERNEL_ERROR_EINVAL;
}
auto* file = g_files->GetFile(d);
if (file == nullptr)
{
return KERNEL_ERROR_EBADF;
}
EXIT_NOT_IMPLEMENTED(file->directory);
EXIT_IF(!file->opened);
EXIT_NOT_IMPLEMENTED(nbytes > UINT_MAX);
file->mutex.Lock();
bool is_invalid = file->f.IsInvalid();
auto pos = file->f.Tell();
uint32_t bytes_written = 0;
file->f.Seek(offset);
file->f.Write(buf, static_cast<uint32_t>(nbytes), &bytes_written);
file->f.Seek(pos);
file->mutex.Unlock();
if (is_invalid)
{
printf("\tfile is invalid\n");
return KERNEL_ERROR_EIO;
}
printf("\tWrite %u bytes (pos = %" PRId64 ") to: " FG_WHITE BOLD "%s" DEFAULT "\n", bytes_written, offset, file->real_name.C_Str());
return bytes_written;
}
int64_t KYTY_SYSV_ABI KernelLseek(int d, int64_t offset, int whence)
{
PRINT_NAME();
EXIT_IF(g_files == nullptr);
if (d < DESCRIPTOR_MIN)
{
return KERNEL_ERROR_EPERM;
}
auto* file = g_files->GetFile(d);
if (file == nullptr)
{
return KERNEL_ERROR_EBADF;
}
EXIT_NOT_IMPLEMENTED(file->directory);
EXIT_IF(!file->opened);
file->mutex.Lock();
bool is_invalid = file->f.IsInvalid();
if (whence == 1)
{
offset = static_cast<int64_t>(file->f.Tell()) + offset;
whence = 0;
}
if (whence == 2)
{
offset = static_cast<int64_t>(file->f.Size()) + offset;
whence = 0;
}
EXIT_NOT_IMPLEMENTED(whence != 0);
if (offset < 0)
{
return KERNEL_ERROR_EINVAL;
}
file->f.Seek(offset);
auto pos = static_cast<int64_t>(file->f.Tell());
EXIT_IF(pos != offset);
file->mutex.Unlock();
if (is_invalid)
{
printf("\tfile is invalid\n");
return KERNEL_ERROR_EIO;
}
printf("\tLseek (pos = %" PRId64 ") to: " FG_WHITE BOLD "%s" DEFAULT "\n", offset, file->real_name.C_Str());
return pos;
}
int KYTY_SYSV_ABI KernelStat(const char* path, FileStat* sb)
{
PRINT_NAME();
EXIT_IF(g_mount_points == nullptr);
if (path == nullptr || sb == nullptr)
{
return KERNEL_ERROR_EINVAL;
}
printf("\tKernelStat: %s\n", path);
String path_s = String::FromUtf8(path);
auto real_file_name = g_mount_points->GetRealFilename(path_s);
auto real_directory = g_mount_points->GetRealDirectory(path_s);
bool is_dir = Core::File::IsDirectoryExisting(real_file_name) || Core::File::IsDirectoryExisting(real_directory);
bool is_file = Core::File::IsFileExisting(real_file_name);
if (!is_dir && !is_file)
{
printf("\tfile not found\n");
return KERNEL_ERROR_ENOENT;
}
EXIT_NOT_IMPLEMENTED(is_dir && is_file);
memset(sb, 0, sizeof(FileStat));
sb->st_mode = 0000777u | (is_dir ? 0040000u : 0100000u);
Core::DateTime at;
Core::DateTime wt;
if (is_dir)
{
sb->st_size = 0;
sb->st_blksize = 512;
sb->st_blocks = 0;
} else
{
sb->st_size = static_cast<int64_t>(Core::File::Size(real_file_name));
sb->st_blksize = 512;
sb->st_blocks = (sb->st_size + 511) / 512;
Core::File::GetLastAccessAndWriteTimeUTC(real_file_name, &at, &wt);
}
sec_to_timespec(&sb->st_atim, at.ToUnix());
sec_to_timespec(&sb->st_mtim, wt.ToUnix());
sb->st_ctim = sb->st_atim;
sb->st_birthtim = sb->st_mtim;
return OK;
}
int KYTY_SYSV_ABI KernelFstat(int d, FileStat* sb)
{
PRINT_NAME();
EXIT_IF(g_files == nullptr);
if (d < DESCRIPTOR_MIN)
{
return KERNEL_ERROR_EPERM;
}
if (sb == nullptr)
{
return KERNEL_ERROR_EFAULT;
}
auto* file = g_files->GetFile(d);
if (file == nullptr)
{
return KERNEL_ERROR_EBADF;
}
EXIT_IF(!file->opened);
printf("\tKernelFstat: %s\n", file->real_name.C_Str());
memset(sb, 0, sizeof(FileStat));
sb->st_mode = 0000777u | (file->directory ? 0040000u : 0100000u);
Core::DateTime at;
Core::DateTime wt;
if (!file->directory)
{
file->mutex.Lock();
bool is_invalid = file->f.IsInvalid();
auto size = file->f.Size();
file->f.GetLastAccessAndWriteTimeUTC(&at, &wt);
file->mutex.Unlock();
if (is_invalid)
{
printf("\tfile is invalid\n");
return KERNEL_ERROR_EIO;
}
sb->st_size = static_cast<int64_t>(size);
sb->st_blksize = 512;
sb->st_blocks = (sb->st_size + 511) / 512;
} else
{
sb->st_size = 0;
sb->st_blksize = 512;
sb->st_blocks = 0;
}
sec_to_timespec(&sb->st_atim, at.ToUnix());
sec_to_timespec(&sb->st_mtim, wt.ToUnix());
sb->st_ctim = sb->st_atim;
sb->st_birthtim = sb->st_mtim;
return OK;
}
int KYTY_SYSV_ABI KernelUnlink(const char* path)
{
PRINT_NAME();
EXIT_IF(g_mount_points == nullptr);
EXIT_IF(g_files == nullptr);
if (path == nullptr)
{
return KERNEL_ERROR_EINVAL;
}
auto path_s = String::FromUtf8(path);
auto real_file_name = g_mount_points->GetRealFilename(path_s);
auto real_directory = g_mount_points->GetRealDirectory(path_s);
EXIT_NOT_IMPLEMENTED(g_files->GetFile(real_file_name) != nullptr);
EXIT_NOT_IMPLEMENTED(g_files->GetFile(real_directory) != nullptr);
bool is_dir = Core::File::IsDirectoryExisting(real_file_name) || Core::File::IsDirectoryExisting(real_directory);
bool is_file = Core::File::IsFileExisting(real_file_name);
if (is_dir)
{
return KERNEL_ERROR_EPERM;
}
if (!is_file)
{
return KERNEL_ERROR_ENOENT;
}
bool ok = Core::File::DeleteFile(real_file_name);
if (!ok)
{
return KERNEL_ERROR_EIO;
}
printf("\tKernelUnlink: %s\n", path);
return OK;
}
int KYTY_SYSV_ABI KernelGetdirentries(int fd, char* buf, int nbytes, int64_t* basep)
{
PRINT_NAME();
EXIT_IF(g_files == nullptr);
if (fd < DESCRIPTOR_MIN)
{
return KERNEL_ERROR_EBADF;
}
if (buf == nullptr)
{
return KERNEL_ERROR_EFAULT;
}
auto* file = g_files->GetFile(fd);
if (file == nullptr)
{
return KERNEL_ERROR_EBADF;
}
if (!file->directory || nbytes < 512 || file->dents_index > file->dents.Size())
{
return KERNEL_ERROR_EINVAL;
}
EXIT_IF(!file->opened);
printf("\tdir = %s\n", file->real_name.C_Str());
printf("\tnbytes = %d\n", nbytes);
printf("\tindex = %d\n", file->dents_index);
if (basep != nullptr)
{
*basep = file->dents_index;
}
if (file->dents_index == file->dents.Size())
{
return 0;
}
const auto& entry = file->dents.At(file->dents_index++);
auto str = entry.name.utf8_str();
auto str_size = str.Size() - 1;
EXIT_NOT_IMPLEMENTED(str_size > 255);
printf("\tname = %s\n", str.GetDataConst());
*reinterpret_cast<uint32_t*>(buf + 0) = entry.name.Hash();
*reinterpret_cast<uint16_t*>(buf + 4) = 512;
*reinterpret_cast<uint8_t*>(buf + 6) = (entry.is_file ? 8 : 4);
*reinterpret_cast<uint8_t*>(buf + 7) = static_cast<uint8_t>(str_size);
strncpy(buf + 8, str.GetDataConst(), 255);
buf[8 + 255] = '\0';
return 512;
}
} // namespace Kyty::Libs::LibKernel::FileSystem
#endif // KYTY_EMU_ENABLED
+604
View File
@@ -0,0 +1,604 @@
#include "Emulator/Kernel/Memory.h"
#include "Kyty/Core/DbgAssert.h"
#include "Kyty/Core/MagicEnum.h"
#include "Kyty/Core/String.h"
#include "Kyty/Core/Threads.h"
#include "Kyty/Core/Vector.h"
#include "Emulator/Graphics/GpuMemory.h"
#include "Emulator/Graphics/GraphicsRun.h"
#include "Emulator/Graphics/Window.h"
#include "Emulator/Libs/Errno.h"
#include "Emulator/Libs/Libs.h"
#include "Emulator/VirtualMemory.h"
#include <algorithm>
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Libs::LibKernel::Memory {
namespace VirtualMemory = Loader::VirtualMemory;
LIB_NAME("libkernel", "libkernel");
class PhysicalMemory
{
public:
struct AllocatedBlock
{
uint64_t start_addr;
uint64_t size;
uint64_t map_vaddr;
uint64_t map_size;
int prot;
VirtualMemory::Mode mode;
Graphics::GpuMemoryMode gpu_mode;
};
PhysicalMemory() { EXIT_NOT_IMPLEMENTED(!Core::Thread::IsMainThread()); }
virtual ~PhysicalMemory() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(PhysicalMemory);
static uint64_t Size() { return static_cast<uint64_t>(5376) * 1024 * 1024; }
bool Alloc(uint64_t search_start, uint64_t search_end, size_t len, size_t alignment, uint64_t* phys_addr_out);
bool Release(uint64_t start, size_t len, uint64_t* vaddr, uint64_t* size, Graphics::GpuMemoryMode* gpu_mode);
bool Map(uint64_t vaddr, uint64_t phys_addr, size_t len, int prot, VirtualMemory::Mode mode, Graphics::GpuMemoryMode gpu_mode);
bool Unmap(uint64_t vaddr, uint64_t size, Graphics::GpuMemoryMode* gpu_mode);
bool Find(uint64_t vaddr, uint64_t* base_addr, size_t* len, int* prot, VirtualMemory::Mode* mode, Graphics::GpuMemoryMode* gpu_mode);
private:
Vector<AllocatedBlock> m_allocated;
Core::Mutex m_mutex;
};
class FlexibleMemory
{
public:
struct AllocatedBlock
{
uint64_t map_vaddr;
uint64_t map_size;
int prot;
VirtualMemory::Mode mode;
Graphics::GpuMemoryMode gpu_mode;
};
FlexibleMemory() { EXIT_NOT_IMPLEMENTED(!Core::Thread::IsMainThread()); }
virtual ~FlexibleMemory() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(FlexibleMemory);
bool Map(uint64_t vaddr, size_t len, int prot, VirtualMemory::Mode mode, Graphics::GpuMemoryMode gpu_mode);
bool Unmap(uint64_t vaddr, uint64_t size, Graphics::GpuMemoryMode* gpu_mode);
bool Find(uint64_t vaddr, uint64_t* base_addr, size_t* len, int* prot, VirtualMemory::Mode* mode, Graphics::GpuMemoryMode* gpu_mode);
private:
Vector<AllocatedBlock> m_allocated;
Core::Mutex m_mutex;
};
static PhysicalMemory* g_physical_memory = nullptr;
static FlexibleMemory* g_flexible_memory = nullptr;
KYTY_SUBSYSTEM_INIT(Memory)
{
g_physical_memory = new PhysicalMemory;
g_flexible_memory = new FlexibleMemory;
}
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Memory) {}
KYTY_SUBSYSTEM_DESTROY(Memory) {}
static uint64_t get_aligned_pos(uint64_t pos, size_t align)
{
return (align != 0 ? (pos + (align - 1)) & ~(align - 1) : pos);
}
bool PhysicalMemory::Alloc(uint64_t search_start, uint64_t search_end, size_t len, size_t alignment, uint64_t* phys_addr_out)
{
if (phys_addr_out == nullptr)
{
return false;
}
Core::LockGuard lock(m_mutex);
uint64_t free_pos = 0;
for (const auto& b: m_allocated)
{
uint64_t n = b.start_addr + b.size;
if (n > free_pos)
{
free_pos = n;
}
}
free_pos = get_aligned_pos(free_pos, alignment);
if (free_pos >= search_start && free_pos + len <= search_end)
{
AllocatedBlock b {};
b.size = len;
b.start_addr = free_pos;
b.gpu_mode = Graphics::GpuMemoryMode::NoAccess;
b.map_size = 0;
b.map_vaddr = 0;
b.prot = 0;
b.mode = VirtualMemory::Mode::NoAccess;
m_allocated.Add(b);
*phys_addr_out = free_pos;
return true;
}
return false;
}
bool PhysicalMemory::Release(uint64_t start, size_t len, uint64_t* vaddr, uint64_t* size, Graphics::GpuMemoryMode* gpu_mode)
{
EXIT_IF(vaddr == nullptr);
EXIT_IF(size == nullptr);
EXIT_IF(gpu_mode == nullptr);
Core::LockGuard lock(m_mutex);
uint32_t index = 0;
for (auto& b: m_allocated)
{
if (start == b.start_addr && len == b.size)
{
*vaddr = b.map_vaddr;
*size = b.map_size;
*gpu_mode = b.gpu_mode;
m_allocated.RemoveAt(index);
return true;
}
index++;
}
return false;
}
bool PhysicalMemory::Map(uint64_t vaddr, uint64_t phys_addr, size_t len, int prot, VirtualMemory::Mode mode,
Graphics::GpuMemoryMode gpu_mode)
{
Core::LockGuard lock(m_mutex);
for (auto& b: m_allocated)
{
if (phys_addr >= b.start_addr && phys_addr < b.start_addr + b.size)
{
if (b.map_vaddr != 0 || b.map_size != 0)
{
return false;
}
b.map_vaddr = vaddr;
b.map_size = len;
b.prot = prot;
b.mode = mode;
b.gpu_mode = gpu_mode;
return true;
}
}
return false;
}
bool PhysicalMemory::Unmap(uint64_t vaddr, uint64_t size, Graphics::GpuMemoryMode* gpu_mode)
{
EXIT_IF(gpu_mode == nullptr);
Core::LockGuard lock(m_mutex);
for (auto& b: m_allocated)
{
if (b.map_vaddr == vaddr && b.map_size == size)
{
*gpu_mode = b.gpu_mode;
b.gpu_mode = Graphics::GpuMemoryMode::NoAccess;
b.map_size = 0;
b.map_vaddr = 0;
b.prot = 0;
b.mode = VirtualMemory::Mode::NoAccess;
return true;
}
}
return false;
}
bool PhysicalMemory::Find(uint64_t vaddr, uint64_t* base_addr, size_t* len, int* prot, VirtualMemory::Mode* mode,
Graphics::GpuMemoryMode* gpu_mode)
{
Core::LockGuard lock(m_mutex);
return std::any_of(m_allocated.begin(), m_allocated.end(),
[vaddr, base_addr, len, prot, mode, gpu_mode](auto& b)
{
if (vaddr >= b.map_vaddr && vaddr < b.map_vaddr + b.map_size)
{
if (base_addr != nullptr)
{
*base_addr = b.map_vaddr;
}
if (len != nullptr)
{
*len = b.map_size;
}
if (prot != nullptr)
{
*prot = b.prot;
}
if (mode != nullptr)
{
*mode = b.mode;
}
if (gpu_mode != nullptr)
{
*gpu_mode = b.gpu_mode;
}
return true;
}
return false;
});
}
bool FlexibleMemory::Map(uint64_t vaddr, size_t len, int prot, VirtualMemory::Mode mode, Graphics::GpuMemoryMode gpu_mode)
{
Core::LockGuard lock(m_mutex);
AllocatedBlock b {};
b.map_vaddr = vaddr;
b.map_size = len;
b.prot = prot;
b.mode = mode;
b.gpu_mode = gpu_mode;
m_allocated.Add(b);
return true;
}
bool FlexibleMemory::Unmap(uint64_t vaddr, uint64_t size, Graphics::GpuMemoryMode* gpu_mode)
{
EXIT_IF(gpu_mode == nullptr);
Core::LockGuard lock(m_mutex);
uint32_t index = 0;
for (auto& b: m_allocated)
{
if (b.map_vaddr == vaddr && b.map_size == size)
{
*gpu_mode = b.gpu_mode;
m_allocated.RemoveAt(index);
return true;
}
index++;
}
return false;
}
bool FlexibleMemory::Find(uint64_t vaddr, uint64_t* base_addr, size_t* len, int* prot, VirtualMemory::Mode* mode,
Graphics::GpuMemoryMode* gpu_mode)
{
Core::LockGuard lock(m_mutex);
return std::any_of(m_allocated.begin(), m_allocated.end(),
[vaddr, base_addr, len, prot, mode, gpu_mode](auto& b)
{
if (vaddr >= b.map_vaddr && vaddr < b.map_vaddr + b.map_size)
{
if (base_addr != nullptr)
{
*base_addr = b.map_vaddr;
}
if (len != nullptr)
{
*len = b.map_size;
}
if (prot != nullptr)
{
*prot = b.prot;
}
if (mode != nullptr)
{
*mode = b.mode;
}
if (gpu_mode != nullptr)
{
*gpu_mode = b.gpu_mode;
}
return true;
}
return false;
});
}
int32_t KYTY_SYSV_ABI KernelMapNamedFlexibleMemory(void** addr_in_out, size_t len, int prot, int flags, const char* name)
{
PRINT_NAME();
EXIT_IF(g_flexible_memory == nullptr);
EXIT_NOT_IMPLEMENTED(addr_in_out == nullptr);
EXIT_NOT_IMPLEMENTED(flags != 0);
VirtualMemory::Mode mode = VirtualMemory::Mode::NoAccess;
Graphics::GpuMemoryMode gpu_mode = Graphics::GpuMemoryMode::NoAccess;
switch (prot)
{
case 0: mode = VirtualMemory::Mode::NoAccess; break;
case 1: mode = VirtualMemory::Mode::Read; break;
case 2:
case 3: mode = VirtualMemory::Mode::ReadWrite; break;
case 4: mode = VirtualMemory::Mode::Execute; break;
case 5: mode = VirtualMemory::Mode::ExecuteRead; break;
case 6:
case 7: mode = VirtualMemory::Mode::ExecuteReadWrite; break;
default: EXIT("unknown prot: %d\n", prot);
}
auto in_addr = reinterpret_cast<uint64_t>(*addr_in_out);
auto out_addr = VirtualMemory::Alloc(in_addr, len, mode);
*addr_in_out = reinterpret_cast<void*>(out_addr);
if (!g_flexible_memory->Map(out_addr, len, prot, mode, gpu_mode))
{
printf(FG_RED "\t[Fail]\n" FG_DEFAULT);
VirtualMemory::Free(out_addr);
return KERNEL_ERROR_ENOMEM;
}
printf("\tin_addr = 0x%016" PRIx64 "\n", in_addr);
printf("\tout_addr = 0x%016" PRIx64 "\n", out_addr);
printf("\tsize = %" PRIu64 "\n", len);
printf("\tmode = %s\n", Core::EnumName(mode).C_Str());
printf("\tname = %s\n", name);
if (out_addr == 0)
{
return KERNEL_ERROR_ENOMEM;
}
return OK;
}
int KYTY_SYSV_ABI KernelMunmap(uint64_t vaddr, size_t len)
{
PRINT_NAME();
printf("\t start = 0x%016" PRIx64 "\n", vaddr);
printf("\t len = 0x%016" PRIx64 "\n", len);
EXIT_IF(g_physical_memory == nullptr);
EXIT_IF(g_flexible_memory == nullptr);
if (vaddr < 0 || len == 0)
{
return KERNEL_ERROR_EINVAL;
}
Graphics::GpuMemoryMode gpu_mode = Graphics::GpuMemoryMode::NoAccess;
bool result = g_physical_memory->Unmap(vaddr, len, &gpu_mode);
if (!result)
{
result = g_flexible_memory->Unmap(vaddr, len, &gpu_mode);
}
EXIT_NOT_IMPLEMENTED(!result);
if (vaddr != 0 || len != 0)
{
VirtualMemory::Free(vaddr);
}
if (gpu_mode != Graphics::GpuMemoryMode::NoAccess)
{
Graphics::GraphicsRunWait();
Graphics::GpuMemoryFree(Graphics::WindowGetGraphicContext(), vaddr, len);
}
return OK;
}
size_t KYTY_SYSV_ABI KernelGetDirectMemorySize()
{
PRINT_NAME();
return PhysicalMemory::Size();
}
int KYTY_SYSV_ABI KernelAllocateDirectMemory(int64_t search_start, int64_t search_end, size_t len, size_t alignment, int memory_type,
int64_t* phys_addr_out)
{
PRINT_NAME();
EXIT_IF(g_physical_memory == nullptr);
printf("\t search_start = 0x%016" PRIx64 "\n", search_start);
printf("\t search_end = 0x%016" PRIx64 "\n", search_end);
printf("\t len = 0x%016" PRIx64 "\n", len);
printf("\t alignment = 0x%016" PRIx64 "\n", alignment);
printf("\t memory_type = %d\n", memory_type);
if (search_start < 0 || search_end <= search_start || len == 0 || phys_addr_out == nullptr)
{
return KERNEL_ERROR_EINVAL;
}
uint64_t addr = 0;
if (!g_physical_memory->Alloc(search_start, search_end, len, alignment, &addr))
{
printf(FG_RED "\t[Fail]\n" FG_DEFAULT);
return KERNEL_ERROR_EAGAIN;
}
*phys_addr_out = static_cast<int64_t>(addr);
printf("\tphys_addr = %016" PRIx64 "\n", addr);
printf(FG_GREEN "\t[Ok]\n" FG_DEFAULT);
return OK;
}
int KYTY_SYSV_ABI KernelReleaseDirectMemory(int64_t start, size_t len)
{
PRINT_NAME();
printf("\t start = 0x%016" PRIx64 "\n", start);
printf("\t len = 0x%016" PRIx64 "\n", len);
EXIT_IF(g_physical_memory == nullptr);
if (start < 0 || len == 0)
{
return KERNEL_ERROR_EINVAL;
}
uint64_t vaddr = 0;
uint64_t size = 0;
Graphics::GpuMemoryMode gpu_mode = Graphics::GpuMemoryMode::NoAccess;
bool result = g_physical_memory->Release(start, len, &vaddr, &size, &gpu_mode);
EXIT_NOT_IMPLEMENTED(!result);
if (vaddr != 0 || size != 0)
{
VirtualMemory::Free(vaddr);
}
if (gpu_mode != Graphics::GpuMemoryMode::NoAccess)
{
Graphics::GraphicsRunWait();
Graphics::GpuMemoryFree(Graphics::WindowGetGraphicContext(), vaddr, size);
}
return OK;
}
int KYTY_SYSV_ABI KernelMapDirectMemory(void** addr, size_t len, int prot, int flags, int64_t direct_memory_start, size_t alignment)
{
PRINT_NAME();
EXIT_IF(g_physical_memory == nullptr);
// EXIT_NOT_IMPLEMENTED(!Core::Thread::IsMainThread());
EXIT_NOT_IMPLEMENTED(addr == nullptr);
EXIT_NOT_IMPLEMENTED(flags != 0);
VirtualMemory::Mode mode = VirtualMemory::Mode::NoAccess;
Graphics::GpuMemoryMode gpu_mode = Graphics::GpuMemoryMode::NoAccess;
switch (prot)
{
case 0x00: mode = VirtualMemory::Mode::NoAccess; break;
case 0x01: mode = VirtualMemory::Mode::Read; break;
case 0x02:
case 0x03: mode = VirtualMemory::Mode::ReadWrite; break;
case 0x04: mode = VirtualMemory::Mode::Execute; break;
case 0x05: mode = VirtualMemory::Mode::ExecuteRead; break;
case 0x06:
case 0x07: mode = VirtualMemory::Mode::ExecuteReadWrite; break;
case 0x32:
case 0x33:
mode = VirtualMemory::Mode::ReadWrite;
gpu_mode = Graphics::GpuMemoryMode::ReadWrite;
break;
default: EXIT("unknown prot: %d\n", prot);
}
auto in_addr = reinterpret_cast<uint64_t>(*addr);
auto out_addr = VirtualMemory::AllocAligned(in_addr, len, mode, alignment);
*addr = reinterpret_cast<void*>(out_addr);
printf("\tin_addr = 0x%016" PRIx64 "\n", in_addr);
printf("\tout_addr = 0x%016" PRIx64 "\n", out_addr);
printf("\tsize = 0x%016" PRIx64 "\n", len);
printf("\tmode = %s\n", Core::EnumName(mode).C_Str());
printf("\talign = 0x%016" PRIx64 "\n", alignment);
printf("\tgpu_mode = %s\n", Core::EnumName(gpu_mode).C_Str());
if (out_addr == 0)
{
return KERNEL_ERROR_ENOMEM;
}
if (!g_physical_memory->Map(out_addr, direct_memory_start, len, prot, mode, gpu_mode))
{
printf(FG_RED "\t[Fail]\n" FG_DEFAULT);
VirtualMemory::Free(out_addr);
return KERNEL_ERROR_EBUSY;
}
if (gpu_mode != Graphics::GpuMemoryMode::NoAccess)
{
Graphics::GpuMemorySetAllocatedRange(out_addr, len);
}
printf(FG_GREEN "\t[Ok]\n" FG_DEFAULT);
return OK;
}
int KYTY_SYSV_ABI KernelQueryMemoryProtection(void* addr, void** start, void** end, int* prot)
{
PRINT_NAME();
EXIT_IF(g_physical_memory == nullptr);
EXIT_IF(g_flexible_memory == nullptr);
EXIT_NOT_IMPLEMENTED(addr == nullptr);
size_t len = 0;
int p = 0;
uint64_t base = 0;
if (!g_physical_memory->Find(reinterpret_cast<uint64_t>(addr), &base, &len, &p, nullptr, nullptr))
{
if (!g_flexible_memory->Find(reinterpret_cast<uint64_t>(addr), &base, &len, &p, nullptr, nullptr))
{
return KERNEL_ERROR_EACCES;
}
}
if (start != nullptr)
{
*start = reinterpret_cast<void*>(base);
}
if (end != nullptr)
{
*end = reinterpret_cast<void*>(base + len - 1);
}
if (prot != nullptr)
{
*prot = p;
}
return OK;
}
} // namespace Kyty::Libs::LibKernel::Memory
#endif // KYTY_EMU_ENABLED
File diff suppressed because it is too large Load Diff