From 77cf607cdabfdf9231767556b86e85be0f40b20b Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 15 Dec 2019 21:29:26 +0100 Subject: [PATCH] Kernel+LibC: Publish a "kernel info page" and use it for gettimeofday() This patch adds a single "kernel info page" that is mappable read-only by any process and contains the current time of day. This is then used to implement a version of gettimeofday() that doesn't have to make a syscall. To protect against race condition issues, the info page also has a serial number which is incremented whenever the kernel updates the contents of the page. Make sure to verify that the serial number is the same before and after reading the information you want from the page. --- Kernel/KernelInfoPage.h | 14 ++++++++++++++ Kernel/Process.cpp | 30 +++++++++++++++++++++++++----- Kernel/Process.h | 3 +++ Kernel/Scheduler.cpp | 5 +++++ Kernel/Syscall.h | 3 ++- Libraries/LibC/time.cpp | 16 +++++++++++++--- 6 files changed, 62 insertions(+), 9 deletions(-) create mode 100644 Kernel/KernelInfoPage.h diff --git a/Kernel/KernelInfoPage.h b/Kernel/KernelInfoPage.h new file mode 100644 index 0000000000..d5b583d575 --- /dev/null +++ b/Kernel/KernelInfoPage.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +#ifdef KERNEL +# include +#else +# include +#endif + +struct KernelInfoPage { + volatile u32 serial; + volatile struct timeval now; +}; diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 93b661ce8e..b3d37d92ed 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -51,11 +52,13 @@ //#define SHARED_BUFFER_DEBUG static void create_signal_trampolines(); +static void create_kernel_info_page(); static pid_t next_pid; InlineLinkedList* g_processes; static String* s_hostname; static Lock* s_hostname_lock; +static VirtualAddress s_info_page_address; VirtualAddress g_return_to_ring3_from_signal_trampoline; VirtualAddress g_return_to_ring0_from_signal_trampoline; HashMap>* g_modules; @@ -70,6 +73,14 @@ void Process::initialize() s_hostname_lock = new Lock; create_signal_trampolines(); + create_kernel_info_page(); +} + +void Process::update_info_page_timestamp(const timeval& tv) +{ + auto* info_page = (KernelInfoPage*)s_info_page_address.as_ptr(); + info_page->serial++; + const_cast(info_page->now) = tv; } Vector Process::all_pids() @@ -981,6 +992,13 @@ void create_signal_trampolines() trampoline_region->remap(); } +void create_kernel_info_page() +{ + auto* info_page_region = MM.allocate_user_accessible_kernel_region(PAGE_SIZE, "Kernel info page").leak_ptr(); + s_info_page_address = info_page_region->vaddr(); + memset(s_info_page_address.as_ptr(), 0, PAGE_SIZE); +} + int Process::sys$restore_signal_mask(u32 mask) { current->m_signal_mask = mask; @@ -1682,10 +1700,7 @@ int Process::sys$sleep(unsigned seconds) timeval kgettimeofday() { - timeval tv; - tv.tv_sec = RTC::boot_time() + PIT::seconds_since_boot(); - tv.tv_usec = PIT::ticks_this_second() * 1000; - return tv; + return const_cast(((KernelInfoPage*)s_info_page_address.as_ptr())->now); } void kgettimeofday(timeval& tv) @@ -1697,7 +1712,7 @@ int Process::sys$gettimeofday(timeval* tv) { if (!validate_write_typed(tv)) return -EFAULT; - kgettimeofday(*tv); + *tv = kgettimeofday(); return 0; } @@ -3733,3 +3748,8 @@ int Process::sys$profiling_disable(pid_t pid) Profiling::stop(); return 0; } + +void* Process::sys$get_kernel_info_page() +{ + return s_info_page_address.as_ptr(); +} diff --git a/Kernel/Process.h b/Kernel/Process.h index 8db6c109a6..56bac006d7 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -67,6 +67,8 @@ public: static Process* from_pid(pid_t); + static void update_info_page_timestamp(const timeval&); + const String& name() const { return m_name; } pid_t pid() const { return m_pid; } pid_t sid() const { return m_sid; } @@ -233,6 +235,7 @@ public: int sys$module_unload(const char* name, size_t name_length); int sys$profiling_enable(pid_t); int sys$profiling_disable(pid_t); + void* sys$get_kernel_info_page(); static void initialize(); diff --git a/Kernel/Scheduler.cpp b/Kernel/Scheduler.cpp index f8849af97a..ef710619fd 100644 --- a/Kernel/Scheduler.cpp +++ b/Kernel/Scheduler.cpp @@ -548,6 +548,11 @@ void Scheduler::timer_tick(RegisterDump& regs) ++g_uptime; + timeval tv; + tv.tv_sec = RTC::boot_time() + PIT::seconds_since_boot(); + tv.tv_usec = PIT::ticks_this_second() * 1000; + Process::update_info_page_timestamp(tv); + if (s_beep_timeout && g_uptime > s_beep_timeout) { PCSpeaker::tone_off(); s_beep_timeout = 0; diff --git a/Kernel/Syscall.h b/Kernel/Syscall.h index 366ce1e999..e3b238862f 100644 --- a/Kernel/Syscall.h +++ b/Kernel/Syscall.h @@ -149,7 +149,8 @@ typedef u32 socklen_t; __ENUMERATE_SYSCALL(purge) \ __ENUMERATE_SYSCALL(set_shared_buffer_volatile) \ __ENUMERATE_SYSCALL(profiling_enable) \ - __ENUMERATE_SYSCALL(profiling_disable) + __ENUMERATE_SYSCALL(profiling_disable) \ + __ENUMERATE_SYSCALL(get_kernel_info_page) namespace Syscall { diff --git a/Libraries/LibC/time.cpp b/Libraries/LibC/time.cpp index 4cd2e47fd9..d0d156d67e 100644 --- a/Libraries/LibC/time.cpp +++ b/Libraries/LibC/time.cpp @@ -1,10 +1,11 @@ +#include #include #include #include +#include #include #include #include -#include extern "C" { @@ -21,8 +22,17 @@ time_t time(time_t* tloc) int gettimeofday(struct timeval* __restrict__ tv, void* __restrict__) { - int rc = syscall(SC_gettimeofday, tv); - __RETURN_WITH_ERRNO(rc, rc, -1); + static volatile KernelInfoPage* kernel_info; + if (!kernel_info) + kernel_info = (volatile KernelInfoPage*)syscall(SC_get_kernel_info_page); + + for (;;) { + auto serial = kernel_info->serial; + *tv = const_cast(kernel_info->now); + if (serial == kernel_info->serial) + break; + } + return 0; } char* ctime(const time_t*)