PowerStateSwitch.cpp 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  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/FileSystem/FileSystem.h>
  8. #include <Kernel/Firmware/ACPI/Parser.h>
  9. #include <Kernel/Firmware/PowerStateSwitch.h>
  10. #include <Kernel/IO.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("power_state")
  25. {
  26. }
  27. KResultOr<size_t> PowerStateSwitchNode::write_bytes(off_t offset, size_t count, UserOrKernelBuffer const& data, OpenFileDescription*)
  28. {
  29. if (Checked<off_t>::addition_would_overflow(offset, count))
  30. return EOVERFLOW;
  31. if (offset > 0)
  32. return EINVAL;
  33. if (count > 1)
  34. return EINVAL;
  35. char buf[1];
  36. TRY(data.read(buf, 1));
  37. switch (buf[0]) {
  38. case '0':
  39. return EINVAL;
  40. case '1':
  41. reboot();
  42. VERIFY_NOT_REACHED();
  43. case '2':
  44. poweroff();
  45. VERIFY_NOT_REACHED();
  46. default:
  47. return EINVAL;
  48. }
  49. VERIFY_NOT_REACHED();
  50. }
  51. void PowerStateSwitchNode::reboot()
  52. {
  53. MutexLocker locker(Process::current().big_lock());
  54. dbgln("acquiring FS locks...");
  55. FileSystem::lock_all();
  56. dbgln("syncing mounted filesystems...");
  57. FileSystem::sync();
  58. dbgln("attempting reboot via ACPI");
  59. if (ACPI::is_enabled())
  60. ACPI::Parser::the()->try_acpi_reboot();
  61. dbgln("attempting reboot via KB Controller...");
  62. IO::out8(0x64, 0xFE);
  63. dbgln("reboot attempts failed, applications will stop responding.");
  64. dmesgln("Reboot can't be completed. It's safe to turn off the computer!");
  65. Processor::halt();
  66. }
  67. void PowerStateSwitchNode::poweroff()
  68. {
  69. MutexLocker locker(Process::current().big_lock());
  70. ConsoleManagement::the().switch_to_debug();
  71. dbgln("acquiring FS locks...");
  72. FileSystem::lock_all();
  73. dbgln("syncing mounted filesystems...");
  74. FileSystem::sync();
  75. dbgln("attempting system shutdown...");
  76. // QEMU Shutdown
  77. IO::out16(0x604, 0x2000);
  78. // If we're here, the shutdown failed. Try VirtualBox shutdown.
  79. IO::out16(0x4004, 0x3400);
  80. // VirtualBox shutdown failed. Try Bochs/Old QEMU shutdown.
  81. IO::out16(0xb004, 0x2000);
  82. dbgln("shutdown attempts failed, applications will stop responding.");
  83. dmesgln("Shutdown can't be completed. It's safe to turn off the computer!");
  84. Processor::halt();
  85. }
  86. }