]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[cmdline] Add "poweroff" command
authorMarin Hannache <git@mareo.fr>
Sat, 13 Jul 2013 12:31:15 +0000 (14:31 +0200)
committerMichael Brown <mcb30@ipxe.org>
Mon, 15 Jul 2013 11:49:48 +0000 (13:49 +0200)
Modified-by: Michael Brown <mcb30@ipxe.org>
Signed-off-by: Marin Hannache <git@mareo.fr>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/arch/i386/interface/pcbios/apm.c [new file with mode: 0644]
src/arch/x86/include/bits/errfile.h
src/config/config.c
src/config/general.h
src/core/null_reboot.c
src/hci/commands/poweroff_cmd.c [new file with mode: 0644]
src/include/ipxe/errfile.h
src/include/ipxe/reboot.h
src/interface/efi/efi_reboot.c

diff --git a/src/arch/i386/interface/pcbios/apm.c b/src/arch/i386/interface/pcbios/apm.c
new file mode 100644 (file)
index 0000000..3b13e1c
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2013 Marin Hannache <ipxe@mareo.fr>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * Advanced Power Management
+ *
+ */
+
+#include <errno.h>
+#include <realmode.h>
+#include <ipxe/reboot.h>
+
+/**
+ * Power off the computer using APM
+ *
+ * @ret rc             Return status code
+ */
+static int apm_poweroff ( void ) {
+       uint16_t apm_version;
+       uint16_t apm_signature;
+       uint16_t apm_flags;
+       uint16_t carry;
+
+       /* APM check */
+       __asm__ __volatile__ ( REAL_CODE ( "int $0x15\n\t"
+                                          "adc %%edx,0\n\t" )
+                              : "=a" ( apm_version ), "=b" ( apm_signature ),
+                                 "=c" ( apm_flags ), "=d" ( carry )
+                              : "a" ( 0x5300 ), "b" ( 0x0000 ),
+                                "d" ( 0x0000 ) );
+       if ( carry ) {
+               DBG ( "APM not present\n" );
+               return -ENOTSUP;
+       }
+       if ( apm_signature != 0x504d ) { /* signature 'PM' */
+               DBG ( "APM not present\n" );
+               return -ENOTSUP;
+       }
+       if ( apm_version < 0x0101 ) { /* Need version 1.1+ */
+               DBG ( "APM 1.1+ not supported\n" );
+               return -ENOTSUP;
+       }
+       if ( ( apm_flags & 0x8 ) == 0x8 ) {
+               DBG ( "APM power management disabled\n" );
+               return -EPERM;
+       }
+       DBG2 ( "APM check completed\n" );
+
+       /* APM initialisation */
+       __asm__ __volatile__ ( REAL_CODE ( "int $0x15\n\t"
+                                          "adc %%edx,0\n\t" )
+                              : "=d" ( carry )
+                              : "a" ( 0x5301 ), "b" ( 0x0000 ),
+                                "d" ( 0x0000 ) );
+       if ( carry ) {
+               DBG ( "APM initialisation failed\n" );
+               return -EIO;
+       }
+       DBG2 ( "APM initialisation completed\n" );
+
+       /* Set APM driver version */
+       __asm__ __volatile__ ( REAL_CODE ( "int $0x15\n\t"
+                                          "adc %%edx,0\n\t" )
+                              : "=d" ( carry )
+                              : "a" ( 0x530e ), "b" ( 0x0000 ),
+                                "c" ( 0x0101 ), "d" ( 0x0000 ) );
+       if ( carry ) {
+               DBG ( "APM setting driver version failed\n" );
+               return -EIO;
+       }
+       DBG2 ( "APM driver version set\n" );
+
+       /* Setting power state to off */
+       __asm__ __volatile__ ( REAL_CODE ( "int $0x15\n\t"
+                                          "adc %%edx,0\n\t" )
+                              : "=d" ( carry )
+                              : "a" ( 0x5307 ), "b" ( 0x0001 ),
+                                "c" ( 0x0003 ), "d" ( 0x0000) );
+       if ( carry ) {
+               DBG ( "APM setting power state failed\n" );
+               return -ENOTTY;
+       }
+
+       /* Should never happen */
+       return -ECANCELED;
+}
+
+PROVIDE_REBOOT ( pcbios, poweroff, apm_poweroff );
index 5f676c8710d5e92a3623db34d40e18e8e3322393..bfd223853b41b2a34800fb55f487a31456023691 100644 (file)
@@ -19,6 +19,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define ERRFILE_vmware         ( ERRFILE_ARCH | ERRFILE_CORE | 0x00080000 )
 #define ERRFILE_guestrpc       ( ERRFILE_ARCH | ERRFILE_CORE | 0x00090000 )
 #define ERRFILE_guestinfo      ( ERRFILE_ARCH | ERRFILE_CORE | 0x000a0000 )
+#define ERRFILE_apm            ( ERRFILE_ARCH | ERRFILE_CORE | 0x000b0000 )
 
 #define ERRFILE_bootsector     ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 )
 #define ERRFILE_bzimage               ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 )
index 1de3db43f66f1e410a610af5f02d74dd8d7dfcf3..45dc29bcfcb70219369d25373e18f1ad3444fb98 100644 (file)
@@ -242,6 +242,9 @@ REQUIRE_OBJECT ( lotest_cmd );
 #ifdef VLAN_CMD
 REQUIRE_OBJECT ( vlan_cmd );
 #endif
+#ifdef POWEROFF_CMD
+REQUIRE_OBJECT ( poweroff_cmd );
+#endif
 #ifdef REBOOT_CMD
 REQUIRE_OBJECT ( reboot_cmd );
 #endif
index 9f0bb521b580cf34d58eeb00c5a708c82f19d5ba..62edd3fe85b892973bf9aa706c23b2a690695402 100644 (file)
@@ -126,6 +126,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 //#define VLAN_CMD             /* VLAN commands */
 //#define PXE_CMD              /* PXE commands */
 //#define REBOOT_CMD           /* Reboot command */
+//#define POWEROFF_CMD         /* Power off command */
 //#define IMAGE_TRUST_CMD      /* Image trust management commands */
 
 /*
index 8e3ed0bb6132aeefd057b472aa47afc4c3374dbd..a3d5b2ef85a2e6c2fd23b67df74f55d1a081a884 100644 (file)
@@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
  */
 
 #include <stdio.h>
+#include <errno.h>
 #include <ipxe/reboot.h>
 
 /**
@@ -40,4 +41,15 @@ static void null_reboot ( int warm __unused ) {
        while ( 1 ) {}
 }
 
+/**
+ * Power off system
+ *
+ * @ret rc             Return status code
+ */
+static int null_poweroff ( void ) {
+
+       return -ENOTSUP;
+}
+
 PROVIDE_REBOOT ( null, reboot, null_reboot );
+PROVIDE_REBOOT ( null, poweroff, null_poweroff );
diff --git a/src/hci/commands/poweroff_cmd.c b/src/hci/commands/poweroff_cmd.c
new file mode 100644 (file)
index 0000000..159fe61
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2013 Marin Hannache <ipxe@mareo.fr>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <getopt.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+#include <ipxe/reboot.h>
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Power off command
+ *
+ */
+
+/** "poweroff" options */
+struct poweroff_options {};
+
+/** "poweroff" option list */
+static struct option_descriptor poweroff_opts[] = {};
+
+/** "poweroff" command descriptor */
+static struct command_descriptor poweroff_cmd =
+       COMMAND_DESC ( struct poweroff_options, poweroff_opts, 0, 0, "" );
+
+/**
+ * The "poweroff" command
+ *
+ * @v argc             Argument count
+ * @v argv             Argument list
+ * @ret rc             Return status code
+ */
+static int poweroff_exec ( int argc, char **argv ) {
+       struct poweroff_options opts;
+       int rc;
+
+       /* Parse options */
+       if ( ( rc = parse_options ( argc, argv, &poweroff_cmd, &opts ) ) != 0 )
+               return rc;
+
+       /* Power off system */
+       rc = poweroff();
+       if ( rc != 0 )
+               printf ( "Could not power off: %s\n", strerror ( rc ) );
+
+       return rc;
+}
+
+/** "poweroff" command */
+struct command poweroff_command __command = {
+       .name = "poweroff",
+       .exec = poweroff_exec,
+};
index c6b0e794a9d78a783d71196c051b675047eab6bf..aad3f358b60e001d3b7ee9b98dc562565a392ecb 100644 (file)
@@ -63,6 +63,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define ERRFILE_test                  ( ERRFILE_CORE | 0x00170000 )
 #define ERRFILE_xferbuf                       ( ERRFILE_CORE | 0x00180000 )
 #define ERRFILE_pending                       ( ERRFILE_CORE | 0x00190000 )
+#define ERRFILE_null_reboot           ( ERRFILE_CORE | 0x001a0000 )
 
 #define ERRFILE_eisa                ( ERRFILE_DRIVER | 0x00000000 )
 #define ERRFILE_isa                 ( ERRFILE_DRIVER | 0x00010000 )
@@ -277,6 +278,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define ERRFILE_efi_umalloc          ( ERRFILE_OTHER | 0x003b0000 )
 #define ERRFILE_linux_pci            ( ERRFILE_OTHER | 0x003c0000 )
 #define ERRFILE_pci_settings         ( ERRFILE_OTHER | 0x003d0000 )
+#define ERRFILE_efi_reboot           ( ERRFILE_OTHER | 0x003e0000 )
 
 /** @} */
 
index 5d882d3dd927e58c8bc1335c83dcd7bf52cafa7b..97e0d5fb6daa955cad98559dbd1f05ba4ff966ff 100644 (file)
@@ -55,4 +55,14 @@ FILE_LICENCE ( GPL2_OR_LATER );
  */
 void reboot ( int warm );
 
+/**
+ * Power off system
+ *
+ * @ret rc             Return status code
+ *
+ * This function may fail, since not all systems support being powered
+ * off by software.
+ */
+int poweroff ( void );
+
 #endif /* _IPXE_REBOOT_H */
index bfee36aa3b1c23e822409c096bed6ab017e7500c..96638c48e7b3036c324a965f48972ba09d6c3b7b 100644 (file)
@@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
  *
  */
 
+#include <errno.h>
 #include <ipxe/efi/efi.h>
 #include <ipxe/reboot.h>
 
@@ -41,4 +42,20 @@ static void efi_reboot ( int warm ) {
        rs->ResetSystem ( ( warm ? EfiResetWarm : EfiResetCold ), 0, 0, NULL );
 }
 
+/**
+ * Power off system
+ *
+ * @ret rc             Return status code
+ */
+static int efi_poweroff ( void ) {
+       EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
+
+       /* Use runtime services to power off system */
+       rs->ResetSystem ( EfiResetShutdown, 0, 0, NULL );
+
+       /* Should never happen */
+       return -ECANCELED;
+}
+
 PROVIDE_REBOOT ( efi, reboot, efi_reboot );
+PROVIDE_REBOOT ( efi, poweroff, efi_poweroff );