clock.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  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 = address_space().page_directory().range_allocator().allocate_randomized(PAGE_SIZE, PAGE_SIZE);
  16. if (!range.has_value())
  17. return ENOMEM;
  18. auto region_or_error = address_space().allocate_region_with_vmobject(range.value(), vmobject, 0, "Kernel time page"sv, PROT_READ, true);
  19. if (region_or_error.is_error())
  20. return region_or_error.error();
  21. return region_or_error.value()->vaddr().get();
  22. }
  23. KResultOr<FlatPtr> Process::sys$clock_gettime(clockid_t clock_id, Userspace<timespec*> user_ts)
  24. {
  25. VERIFY_NO_PROCESS_BIG_LOCK(this);
  26. REQUIRE_PROMISE(stdio);
  27. if (!TimeManagement::is_valid_clock_id(clock_id))
  28. return EINVAL;
  29. auto ts = TimeManagement::the().current_time(clock_id).to_timespec();
  30. if (!copy_to_user(user_ts, &ts))
  31. return EFAULT;
  32. return 0;
  33. }
  34. KResultOr<FlatPtr> Process::sys$clock_settime(clockid_t clock_id, Userspace<const timespec*> user_ts)
  35. {
  36. VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
  37. REQUIRE_PROMISE(settime);
  38. if (!is_superuser())
  39. return EPERM;
  40. auto ts = copy_time_from_user(user_ts);
  41. if (!ts.has_value())
  42. return EFAULT;
  43. switch (clock_id) {
  44. case CLOCK_REALTIME:
  45. TimeManagement::the().set_epoch_time(ts.value());
  46. break;
  47. default:
  48. return EINVAL;
  49. }
  50. return 0;
  51. }
  52. KResultOr<FlatPtr> Process::sys$clock_nanosleep(Userspace<const Syscall::SC_clock_nanosleep_params*> user_params)
  53. {
  54. VERIFY_NO_PROCESS_BIG_LOCK(this);
  55. REQUIRE_PROMISE(stdio);
  56. Syscall::SC_clock_nanosleep_params params;
  57. if (!copy_from_user(&params, user_params))
  58. return EFAULT;
  59. Optional<Time> requested_sleep = copy_time_from_user(params.requested_sleep);
  60. if (!requested_sleep.has_value())
  61. return EFAULT;
  62. bool is_absolute;
  63. switch (params.flags) {
  64. case 0:
  65. is_absolute = false;
  66. break;
  67. case TIMER_ABSTIME:
  68. is_absolute = true;
  69. break;
  70. default:
  71. return EINVAL;
  72. }
  73. if (!TimeManagement::is_valid_clock_id(params.clock_id))
  74. return EINVAL;
  75. bool was_interrupted;
  76. if (is_absolute) {
  77. was_interrupted = Thread::current()->sleep_until(params.clock_id, requested_sleep.value()).was_interrupted();
  78. } else {
  79. Time remaining_sleep;
  80. was_interrupted = Thread::current()->sleep(params.clock_id, requested_sleep.value(), &remaining_sleep).was_interrupted();
  81. timespec remaining_sleep_ts = remaining_sleep.to_timespec();
  82. if (was_interrupted && params.remaining_sleep && !copy_to_user(params.remaining_sleep, &remaining_sleep_ts))
  83. return EFAULT;
  84. }
  85. if (was_interrupted)
  86. return EINTR;
  87. return 0;
  88. }
  89. KResultOr<FlatPtr> Process::sys$adjtime(Userspace<const timeval*> user_delta, Userspace<timeval*> user_old_delta)
  90. {
  91. VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
  92. if (user_old_delta) {
  93. timespec old_delta_ts = TimeManagement::the().remaining_epoch_time_adjustment();
  94. timeval old_delta;
  95. timespec_to_timeval(old_delta_ts, old_delta);
  96. if (!copy_to_user(user_old_delta, &old_delta))
  97. return EFAULT;
  98. }
  99. if (user_delta) {
  100. REQUIRE_PROMISE(settime);
  101. if (!is_superuser())
  102. return EPERM;
  103. auto delta = copy_time_from_user(user_delta);
  104. if (!delta.has_value())
  105. return EFAULT;
  106. // FIXME: Should use AK::Time internally
  107. TimeManagement::the().set_remaining_epoch_time_adjustment(delta->to_timespec());
  108. }
  109. return 0;
  110. }
  111. }