mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-01-04 01:05:58 +03:00
cf16b2c8e6
This forces anyone who wants to look into and/or manipulate an address space to lock it. And this replaces the previous, more flimsy, manual spinlock use. Note that pointers *into* the address space are not safe to use after you unlock the space. We've got many issues like this, and we'll have to track those down as wlel.
139 lines
4.0 KiB
C++
139 lines
4.0 KiB
C++
/*
|
|
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <AK/Time.h>
|
|
#include <Kernel/Process.h>
|
|
#include <Kernel/Time/TimeManagement.h>
|
|
|
|
namespace Kernel {
|
|
|
|
ErrorOr<FlatPtr> Process::sys$map_time_page()
|
|
{
|
|
VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
|
|
TRY(require_promise(Pledge::stdio));
|
|
|
|
auto& vmobject = TimeManagement::the().time_page_vmobject();
|
|
|
|
return address_space().with([&](auto& space) -> ErrorOr<FlatPtr> {
|
|
auto* region = TRY(space->allocate_region_with_vmobject(Memory::RandomizeVirtualAddress::Yes, {}, PAGE_SIZE, PAGE_SIZE, vmobject, 0, "Kernel time page"sv, PROT_READ, true));
|
|
return region->vaddr().get();
|
|
});
|
|
}
|
|
|
|
ErrorOr<FlatPtr> Process::sys$clock_gettime(clockid_t clock_id, Userspace<timespec*> user_ts)
|
|
{
|
|
VERIFY_NO_PROCESS_BIG_LOCK(this);
|
|
TRY(require_promise(Pledge::stdio));
|
|
|
|
TRY(TimeManagement::validate_clock_id(clock_id));
|
|
|
|
auto ts = TimeManagement::the().current_time(clock_id).to_timespec();
|
|
TRY(copy_to_user(user_ts, &ts));
|
|
return 0;
|
|
}
|
|
|
|
ErrorOr<FlatPtr> Process::sys$clock_settime(clockid_t clock_id, Userspace<timespec const*> user_ts)
|
|
{
|
|
VERIFY_NO_PROCESS_BIG_LOCK(this);
|
|
TRY(require_promise(Pledge::settime));
|
|
|
|
auto credentials = this->credentials();
|
|
if (!credentials->is_superuser())
|
|
return EPERM;
|
|
|
|
auto time = TRY(copy_time_from_user(user_ts));
|
|
|
|
switch (clock_id) {
|
|
case CLOCK_REALTIME:
|
|
TimeManagement::the().set_epoch_time(time);
|
|
break;
|
|
default:
|
|
return EINVAL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ErrorOr<FlatPtr> Process::sys$clock_nanosleep(Userspace<Syscall::SC_clock_nanosleep_params const*> user_params)
|
|
{
|
|
VERIFY_NO_PROCESS_BIG_LOCK(this);
|
|
TRY(require_promise(Pledge::stdio));
|
|
auto params = TRY(copy_typed_from_user(user_params));
|
|
|
|
auto requested_sleep = TRY(copy_time_from_user(params.requested_sleep));
|
|
|
|
bool is_absolute;
|
|
switch (params.flags) {
|
|
case 0:
|
|
is_absolute = false;
|
|
break;
|
|
case TIMER_ABSTIME:
|
|
is_absolute = true;
|
|
break;
|
|
default:
|
|
return EINVAL;
|
|
}
|
|
|
|
TRY(TimeManagement::validate_clock_id(params.clock_id));
|
|
|
|
bool was_interrupted;
|
|
if (is_absolute) {
|
|
was_interrupted = Thread::current()->sleep_until(params.clock_id, requested_sleep).was_interrupted();
|
|
} else {
|
|
Time remaining_sleep;
|
|
was_interrupted = Thread::current()->sleep(params.clock_id, requested_sleep, &remaining_sleep).was_interrupted();
|
|
timespec remaining_sleep_ts = remaining_sleep.to_timespec();
|
|
if (was_interrupted && params.remaining_sleep) {
|
|
TRY(copy_to_user(params.remaining_sleep, &remaining_sleep_ts));
|
|
}
|
|
}
|
|
if (was_interrupted)
|
|
return EINTR;
|
|
return 0;
|
|
}
|
|
|
|
ErrorOr<FlatPtr> Process::sys$clock_getres(Userspace<Syscall::SC_clock_getres_params const*> user_params)
|
|
{
|
|
VERIFY_NO_PROCESS_BIG_LOCK(this);
|
|
auto params = TRY(copy_typed_from_user(user_params));
|
|
timespec ts {};
|
|
switch (params.clock_id) {
|
|
case CLOCK_REALTIME:
|
|
ts.tv_sec = 0;
|
|
ts.tv_nsec = 1000000000 / _SC_CLK_TCK;
|
|
TRY(copy_to_user(params.result, &ts));
|
|
break;
|
|
default:
|
|
return EINVAL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ErrorOr<FlatPtr> Process::sys$adjtime(Userspace<timeval const*> user_delta, Userspace<timeval*> user_old_delta)
|
|
{
|
|
VERIFY_NO_PROCESS_BIG_LOCK(this);
|
|
if (user_old_delta) {
|
|
timespec old_delta_ts = TimeManagement::the().remaining_epoch_time_adjustment();
|
|
timeval old_delta;
|
|
timespec_to_timeval(old_delta_ts, old_delta);
|
|
TRY(copy_to_user(user_old_delta, &old_delta));
|
|
}
|
|
|
|
if (user_delta) {
|
|
TRY(require_promise(Pledge::settime));
|
|
auto credentials = this->credentials();
|
|
if (!credentials->is_superuser())
|
|
return EPERM;
|
|
auto delta = TRY(copy_time_from_user(user_delta));
|
|
|
|
// FIXME: Should use AK::Time internally
|
|
TimeManagement::the().set_remaining_epoch_time_adjustment(delta.to_timespec());
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
}
|