halt.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. /* halt.c - command to halt the computer. */
  2. /*
  3. * GRUB -- GRand Unified Bootloader
  4. * Copyright (C) 2005,2007,2009 Free Software Foundation, Inc.
  5. *
  6. * GRUB is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * GRUB is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <grub/dl.h>
  20. #include <grub/misc.h>
  21. #include <grub/extcmd.h>
  22. #include <grub/i18n.h>
  23. #include <grub/machine/int.h>
  24. #include <grub/acpi.h>
  25. GRUB_MOD_LICENSE ("GPLv3+");
  26. static const struct grub_arg_option options[] =
  27. {
  28. {"no-apm", 'n', 0, N_("Do not use APM to halt the computer."), 0, 0},
  29. {0, 0, 0, 0, 0, 0}
  30. };
  31. static inline void __attribute__ ((noreturn))
  32. stop (void)
  33. {
  34. while (1)
  35. {
  36. asm volatile ("hlt");
  37. }
  38. }
  39. /*
  40. * Halt the system, using APM if possible. If NO_APM is true, don't use
  41. * APM even if it is available.
  42. */
  43. void __attribute__ ((noreturn))
  44. grub_halt (int no_apm)
  45. {
  46. struct grub_bios_int_registers regs;
  47. grub_acpi_halt ();
  48. if (no_apm)
  49. stop ();
  50. /* detect APM */
  51. regs.eax = 0x5300;
  52. regs.ebx = 0;
  53. regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
  54. grub_bios_interrupt (0x15, &regs);
  55. if (regs.flags & GRUB_CPU_INT_FLAGS_CARRY)
  56. stop ();
  57. /* disconnect APM first */
  58. regs.eax = 0x5304;
  59. regs.ebx = 0;
  60. regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
  61. grub_bios_interrupt (0x15, &regs);
  62. /* connect APM */
  63. regs.eax = 0x5301;
  64. regs.ebx = 0;
  65. regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
  66. grub_bios_interrupt (0x15, &regs);
  67. if (regs.flags & GRUB_CPU_INT_FLAGS_CARRY)
  68. stop ();
  69. /* set APM protocol level - 1.1 or bust. (this covers APM 1.2 also) */
  70. regs.eax = 0x530E;
  71. regs.ebx = 0;
  72. regs.ecx = 0x0101;
  73. regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
  74. grub_bios_interrupt (0x15, &regs);
  75. if (regs.flags & GRUB_CPU_INT_FLAGS_CARRY)
  76. stop ();
  77. /* set the power state to off */
  78. regs.eax = 0x5307;
  79. regs.ebx = 1;
  80. regs.ecx = 3;
  81. regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
  82. grub_bios_interrupt (0x15, &regs);
  83. /* shouldn't reach here */
  84. stop ();
  85. }
  86. static grub_err_t __attribute__ ((noreturn))
  87. grub_cmd_halt (grub_extcmd_context_t ctxt,
  88. int argc __attribute__ ((unused)),
  89. char **args __attribute__ ((unused)))
  90. {
  91. struct grub_arg_list *state = ctxt->state;
  92. int no_apm = 0;
  93. if (state[0].set)
  94. no_apm = 1;
  95. grub_halt (no_apm);
  96. }
  97. static grub_extcmd_t cmd;
  98. GRUB_MOD_INIT(halt)
  99. {
  100. cmd = grub_register_extcmd ("halt", grub_cmd_halt, 0, "[-n]",
  101. N_("Halt the system, if possible using APM."),
  102. options);
  103. }
  104. GRUB_MOD_FINI(halt)
  105. {
  106. grub_unregister_extcmd (cmd);
  107. }