PowerStateSwitch.cpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <Kernel/Arch/x86/IO.h>
  8. #include <Kernel/FileSystem/FileSystem.h>
  9. #include <Kernel/FileSystem/SysFS/Subsystems/Firmware/PowerStateSwitch.h>
  10. #include <Kernel/Firmware/ACPI/Parser.h>
  11. #include <Kernel/Process.h>
  12. #include <Kernel/Sections.h>
  13. #include <Kernel/TTY/ConsoleManagement.h>
  14. namespace Kernel {
  15. mode_t PowerStateSwitchNode::permissions() const
  16. {
  17. return S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP;
  18. }
  19. UNMAP_AFTER_INIT NonnullRefPtr<PowerStateSwitchNode> PowerStateSwitchNode::must_create(FirmwareSysFSDirectory& firmware_directory)
  20. {
  21. return adopt_ref_if_nonnull(new (nothrow) PowerStateSwitchNode(firmware_directory)).release_nonnull();
  22. }
  23. UNMAP_AFTER_INIT PowerStateSwitchNode::PowerStateSwitchNode(FirmwareSysFSDirectory&)
  24. : SysFSComponent()
  25. {
  26. }
  27. ErrorOr<void> PowerStateSwitchNode::truncate(u64 size)
  28. {
  29. // Note: This node doesn't store any useful data anyway, so we can safely
  30. // truncate this to zero (essentially ignoring the request without failing).
  31. if (size != 0)
  32. return EPERM;
  33. return {};
  34. }
  35. ErrorOr<size_t> PowerStateSwitchNode::write_bytes(off_t offset, size_t count, UserOrKernelBuffer const& data, OpenFileDescription*)
  36. {
  37. if (Checked<off_t>::addition_would_overflow(offset, count))
  38. return EOVERFLOW;
  39. if (offset > 0)
  40. return EINVAL;
  41. if (count > 1)
  42. return EINVAL;
  43. char buf[1];
  44. TRY(data.read(buf, 1));
  45. switch (buf[0]) {
  46. case '0':
  47. return EINVAL;
  48. case '1':
  49. reboot();
  50. VERIFY_NOT_REACHED();
  51. case '2':
  52. poweroff();
  53. VERIFY_NOT_REACHED();
  54. default:
  55. return EINVAL;
  56. }
  57. VERIFY_NOT_REACHED();
  58. }
  59. void PowerStateSwitchNode::reboot()
  60. {
  61. MutexLocker locker(Process::current().big_lock());
  62. dbgln("acquiring FS locks...");
  63. FileSystem::lock_all();
  64. dbgln("syncing mounted filesystems...");
  65. FileSystem::sync();
  66. dbgln("attempting reboot via ACPI");
  67. if (ACPI::is_enabled())
  68. ACPI::Parser::the()->try_acpi_reboot();
  69. dbgln("attempting reboot via KB Controller...");
  70. IO::out8(0x64, 0xFE);
  71. dbgln("reboot attempts failed, applications will stop responding.");
  72. dmesgln("Reboot can't be completed. It's safe to turn off the computer!");
  73. Processor::halt();
  74. }
  75. void PowerStateSwitchNode::poweroff()
  76. {
  77. MutexLocker locker(Process::current().big_lock());
  78. ConsoleManagement::the().switch_to_debug();
  79. dbgln("acquiring FS locks...");
  80. FileSystem::lock_all();
  81. dbgln("syncing mounted filesystems...");
  82. FileSystem::sync();
  83. dbgln("attempting system shutdown...");
  84. // QEMU Shutdown
  85. IO::out16(0x604, 0x2000);
  86. // If we're here, the shutdown failed. Try VirtualBox shutdown.
  87. IO::out16(0x4004, 0x3400);
  88. // VirtualBox shutdown failed. Try Bochs/Old QEMU shutdown.
  89. IO::out16(0xb004, 0x2000);
  90. dbgln("shutdown attempts failed, applications will stop responding.");
  91. dmesgln("Shutdown can't be completed. It's safe to turn off the computer!");
  92. Processor::halt();
  93. }
  94. }