clock.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Time.h>
  7. #include <Kernel/Process.h>
  8. #include <Kernel/Time/TimeManagement.h>
  9. namespace Kernel {
  10. KResultOr<FlatPtr> Process::sys$map_time_page()
  11. {
  12. VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
  13. REQUIRE_PROMISE(stdio);
  14. auto& vmobject = TimeManagement::the().time_page_vmobject();
  15. auto range = TRY(address_space().page_directory().range_allocator().try_allocate_randomized(PAGE_SIZE, PAGE_SIZE));
  16. auto* region = TRY(address_space().allocate_region_with_vmobject(range, vmobject, 0, "Kernel time page"sv, PROT_READ, true));
  17. return region->vaddr().get();
  18. }
  19. KResultOr<FlatPtr> Process::sys$clock_gettime(clockid_t clock_id, Userspace<timespec*> user_ts)
  20. {
  21. VERIFY_NO_PROCESS_BIG_LOCK(this);
  22. REQUIRE_PROMISE(stdio);
  23. if (!TimeManagement::is_valid_clock_id(clock_id))
  24. return EINVAL;
  25. auto ts = TimeManagement::the().current_time(clock_id).to_timespec();
  26. return copy_to_user(user_ts, &ts);
  27. }
  28. KResultOr<FlatPtr> Process::sys$clock_settime(clockid_t clock_id, Userspace<const timespec*> user_ts)
  29. {
  30. VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
  31. REQUIRE_PROMISE(settime);
  32. if (!is_superuser())
  33. return EPERM;
  34. auto time = TRY(copy_time_from_user(user_ts));
  35. switch (clock_id) {
  36. case CLOCK_REALTIME:
  37. TimeManagement::the().set_epoch_time(time);
  38. break;
  39. default:
  40. return EINVAL;
  41. }
  42. return 0;
  43. }
  44. KResultOr<FlatPtr> Process::sys$clock_nanosleep(Userspace<const Syscall::SC_clock_nanosleep_params*> user_params)
  45. {
  46. VERIFY_NO_PROCESS_BIG_LOCK(this);
  47. REQUIRE_PROMISE(stdio);
  48. auto params = TRY(copy_typed_from_user(user_params));
  49. auto requested_sleep = TRY(copy_time_from_user(params.requested_sleep));
  50. bool is_absolute;
  51. switch (params.flags) {
  52. case 0:
  53. is_absolute = false;
  54. break;
  55. case TIMER_ABSTIME:
  56. is_absolute = true;
  57. break;
  58. default:
  59. return EINVAL;
  60. }
  61. if (!TimeManagement::is_valid_clock_id(params.clock_id))
  62. return EINVAL;
  63. bool was_interrupted;
  64. if (is_absolute) {
  65. was_interrupted = Thread::current()->sleep_until(params.clock_id, requested_sleep).was_interrupted();
  66. } else {
  67. Time remaining_sleep;
  68. was_interrupted = Thread::current()->sleep(params.clock_id, requested_sleep, &remaining_sleep).was_interrupted();
  69. timespec remaining_sleep_ts = remaining_sleep.to_timespec();
  70. if (was_interrupted && params.remaining_sleep) {
  71. TRY(copy_to_user(params.remaining_sleep, &remaining_sleep_ts));
  72. }
  73. }
  74. if (was_interrupted)
  75. return EINTR;
  76. return 0;
  77. }
  78. KResultOr<FlatPtr> Process::sys$adjtime(Userspace<const timeval*> user_delta, Userspace<timeval*> user_old_delta)
  79. {
  80. VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
  81. if (user_old_delta) {
  82. timespec old_delta_ts = TimeManagement::the().remaining_epoch_time_adjustment();
  83. timeval old_delta;
  84. timespec_to_timeval(old_delta_ts, old_delta);
  85. TRY(copy_to_user(user_old_delta, &old_delta));
  86. }
  87. if (user_delta) {
  88. REQUIRE_PROMISE(settime);
  89. if (!is_superuser())
  90. return EPERM;
  91. auto delta = TRY(copy_time_from_user(user_delta));
  92. // FIXME: Should use AK::Time internally
  93. TimeManagement::the().set_remaining_epoch_time_adjustment(delta.to_timespec());
  94. }
  95. return 0;
  96. }
  97. }