/* * GRUB -- GRand Unified Bootloader * Copyright (C) 2008 Free Software Foundation, Inc. * * GRUB 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 3 of the License, or * (at your option) any later version. * * GRUB 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 GRUB. If not, see . */ #include #include #include #include #include #include const char bochs_shutdown[] = "Shutdown"; /* * This call is special... it never returns... in fact it should simply * hang at this point! */ static inline void __attribute__ ((noreturn)) stop (void) { asm volatile ("cli"); while (1) { asm volatile ("hlt"); } } static int grub_shutdown_pci_iter (grub_pci_device_t dev, grub_pci_id_t pciid, void *data __attribute__ ((unused))) { /* QEMU. */ if (pciid == 0x71138086) { grub_pci_address_t addr; addr = grub_pci_make_address (dev, 0x40); grub_pci_write (addr, 0x7001); addr = grub_pci_make_address (dev, 0x80); grub_pci_write (addr, grub_pci_read (addr) | 1); grub_outw (0x2000, 0x7004); } return 0; } void grub_halt (void) { unsigned int i; #if defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_MULTIBOOT) grub_acpi_halt (); #endif /* Disable interrupts. */ __asm__ __volatile__ ("cli"); /* Bochs, QEMU, etc. Removed in newer QEMU releases. */ for (i = 0; i < sizeof (bochs_shutdown) - 1; i++) grub_outb (bochs_shutdown[i], 0x8900); grub_pci_iterate (grub_shutdown_pci_iter, NULL); grub_puts_ (N_("GRUB doesn't know how to halt this machine yet!")); /* In order to return we'd have to check what the previous status of IF flag was. But user most likely doesn't want to return anyway ... */ stop (); }