linux/arch/i386/kernel/reboot.c History
<<
>>
Prefs
   1/*
   2 *  linux/arch/i386/kernel/reboot.c
   3 */
   4
   5#include <linux/mm.h>
   6#include <linux/module.h>
   7#include <linux/delay.h>
   8#include <linux/init.h>
   9#include <linux/interrupt.h>
  10#include <linux/mc146818rtc.h>
  11#include <linux/efi.h>
  12#include <linux/dmi.h>
  13#include <linux/ctype.h>
  14#include <linux/pm.h>
  15#include <linux/reboot.h>
  16#include <asm/uaccess.h>
  17#include <asm/apic.h>
  18#include <asm/desc.h>
  19#include "mach_reboot.h"
  20#include <asm/reboot_fixups.h>
  21#include <asm/reboot.h>
  22
  23/*
  24 * Power off function, if any
  25 */
  26void (*pm_power_off)(void);
  27EXPORT_SYMBOL(pm_power_off);
  28
  29static int reboot_mode;
  30static int reboot_thru_bios;
  31
  32#ifdef CONFIG_SMP
  33static int reboot_cpu = -1;
  34#endif
  35static int __init reboot_setup(char *str)
  36{
  37        while(1) {
  38                switch (*str) {
  39                case 'w': /* "warm" reboot (no memory testing etc) */
  40                        reboot_mode = 0x1234;
  41                        break;
  42                case 'c': /* "cold" reboot (with memory testing etc) */
  43                        reboot_mode = 0x0;
  44                        break;
  45                case 'b': /* "bios" reboot by jumping through the BIOS */
  46                        reboot_thru_bios = 1;
  47                        break;
  48                case 'h': /* "hard" reboot by toggling RESET and/or crashing the CPU */
  49                        reboot_thru_bios = 0;
  50                        break;
  51#ifdef CONFIG_SMP
  52                case 's': /* "smp" reboot by executing reset on BSP or other CPU*/
  53                        if (isdigit(*(str+1))) {
  54                                reboot_cpu = (int) (*(str+1) - '0');
  55                                if (isdigit(*(str+2)))
  56                                        reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0');
  57                        }
  58                                /* we will leave sorting out the final value 
  59                                when we are ready to reboot, since we might not
  60                                have set up boot_cpu_id or smp_num_cpu */
  61                        break;
  62#endif
  63                }
  64                if((str = strchr(str,',')) != NULL)
  65                        str++;
  66                else
  67                        break;
  68        }
  69        return 1;
  70}
  71
  72__setup("reboot=", reboot_setup);
  73
  74/*
  75 * Reboot options and system auto-detection code provided by
  76 * Dell Inc. so their systems "just work". :-)
  77 */
  78
  79/*
  80 * Some machines require the "reboot=b"  commandline option, this quirk makes that automatic.
  81 */
  82static int __init set_bios_reboot(struct dmi_system_id *d)
  83{
  84        if (!reboot_thru_bios) {
  85                reboot_thru_bios = 1;
  86                printk(KERN_INFO "%s series board detected. Selecting BIOS-method for reboots.\n", d->ident);
  87        }
  88        return 0;
  89}
  90
  91static struct dmi_system_id __initdata reboot_dmi_table[] = {
  92        {       /* Handle problems with rebooting on Dell E520's */
  93                .callback = set_bios_reboot,
  94                .ident = "Dell E520",
  95                .matches = {
  96                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
  97                        DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM061"),
  98                },
  99        },
 100        {       /* Handle problems with rebooting on Dell 1300's */
 101                .callback = set_bios_reboot,
 102                .ident = "Dell PowerEdge 1300",
 103                .matches = {
 104                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
 105                        DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"),
 106                },
 107        },
 108        {       /* Handle problems with rebooting on Dell 300's */
 109                .callback = set_bios_reboot,
 110                .ident = "Dell PowerEdge 300",
 111                .matches = {
 112                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
 113                        DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"),
 114                },
 115        },
 116        {       /* Handle problems with rebooting on Dell 2400's */
 117                .callback = set_bios_reboot,
 118                .ident = "Dell PowerEdge 2400",
 119                .matches = {
 120                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
 121                        DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"),
 122                },
 123        },
 124        {       /* Handle problems with rebooting on HP laptops */
 125                .callback = set_bios_reboot,
 126                .ident = "HP Compaq Laptop",
 127                .matches = {
 128                        DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
 129                        DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"),
 130                },
 131        },
 132        { }
 133};
 134
 135static int __init reboot_init(void)
 136{
 137        dmi_check_system(reboot_dmi_table);
 138        return 0;
 139}
 140
 141core_initcall(reboot_init);
 142
 143/* The following code and data reboots the machine by switching to real
 144   mode and jumping to the BIOS reset entry point, as if the CPU has
 145   really been reset.  The previous version asked the keyboard
 146   controller to pulse the CPU reset line, which is more thorough, but
 147   doesn't work with at least one type of 486 motherboard.  It is easy
 148   to stop this code working; hence the copious comments. */
 149
 150static unsigned long long
 151real_mode_gdt_entries [3] =
 152{
 153        0x0000000000000000ULL,  /* Null descriptor */
 154        0x00009a000000ffffULL,  /* 16-bit real-mode 64k code at 0x00000000 */
 155        0x000092000100ffffULL   /* 16-bit real-mode 64k data at 0x00000100 */
 156};
 157
 158static struct Xgt_desc_struct
 159real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, (long)real_mode_gdt_entries },
 160real_mode_idt = { 0x3ff, 0 },
 161no_idt = { 0, 0 };
 162
 163
 164/* This is 16-bit protected mode code to disable paging and the cache,
 165   switch to real mode and jump to the BIOS reset code.
 166
 167   The instruction that switches to real mode by writing to CR0 must be
 168   followed immediately by a far jump instruction, which set CS to a
 169   valid value for real mode, and flushes the prefetch queue to avoid
 170   running instructions that have already been decoded in protected
 171   mode.
 172
 173   Clears all the flags except ET, especially PG (paging), PE
 174   (protected-mode enable) and TS (task switch for coprocessor state
 175   save).  Flushes the TLB after paging has been disabled.  Sets CD and
 176   NW, to disable the cache on a 486, and invalidates the cache.  This
 177   is more like the state of a 486 after reset.  I don't know if
 178   something else should be done for other chips.
 179
 180   More could be done here to set up the registers as if a CPU reset had
 181   occurred; hopefully real BIOSs don't assume much. */
 182
 183static unsigned char real_mode_switch [] =
 184{
 185        0x66, 0x0f, 0x20, 0xc0,                 /*    movl  %cr0,%eax        */
 186        0x66, 0x83, 0xe0, 0x11,                 /*    andl  $0x00000011,%eax */
 187        0x66, 0x0d, 0x00, 0x00, 0x00, 0x60,     /*    orl   $0x60000000,%eax */
 188        0x66, 0x0f, 0x22, 0xc0,                 /*    movl  %eax,%cr0        */
 189        0x66, 0x0f, 0x22, 0xd8,                 /*    movl  %eax,%cr3        */
 190        0x66, 0x0f, 0x20, 0xc3,                 /*    movl  %cr0,%ebx        */
 191        0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60,       /*    andl  $0x60000000,%ebx */
 192        0x74, 0x02,                             /*    jz    f                */
 193        0x0f, 0x09,                             /*    wbinvd                 */
 194        0x24, 0x10,                             /* f: andb  $0x10,al         */
 195        0x66, 0x0f, 0x22, 0xc0                  /*    movl  %eax,%cr0        */
 196};
 197static unsigned char jump_to_bios [] =
 198{
 199        0xea, 0x00, 0x00, 0xff, 0xff            /*    ljmp  $0xffff,$0x0000  */
 200};
 201
 202/*
 203 * Switch to real mode and then execute the code
 204 * specified by the code and length parameters.
 205 * We assume that length will aways be less that 100!
 206 */
 207void machine_real_restart(unsigned char *code, int length)
 208{
 209        local_irq_disable();
 210
 211        /* Write zero to CMOS register number 0x0f, which the BIOS POST
 212           routine will recognize as telling it to do a proper reboot.  (Well
 213           that's what this book in front of me says -- it may only apply to
 214           the Phoenix BIOS though, it's not clear).  At the same time,
 215           disable NMIs by setting the top bit in the CMOS address register,
 216           as we're about to do peculiar things to the CPU.  I'm not sure if
 217           `outb_p' is needed instead of just `outb'.  Use it to be on the
 218           safe side.  (Yes, CMOS_WRITE does outb_p's. -  Paul G.)
 219         */
 220
 221        spin_lock(&rtc_lock);
 222        CMOS_WRITE(0x00, 0x8f);
 223        spin_unlock(&rtc_lock);
 224
 225        /* Remap the kernel at virtual address zero, as well as offset zero
 226           from the kernel segment.  This assumes the kernel segment starts at
 227           virtual address PAGE_OFFSET. */
 228
 229        memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
 230                sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS);
 231
 232        /*
 233         * Use `swapper_pg_dir' as our page directory.
 234         */
 235        load_cr3(swapper_pg_dir);
 236
 237        /* Write 0x1234 to absolute memory location 0x472.  The BIOS reads
 238           this on booting to tell it to "Bypass memory test (also warm
 239           boot)".  This seems like a fairly standard thing that gets set by
 240           REBOOT.COM programs, and the previous reset routine did this
 241           too. */
 242
 243        *((unsigned short *)0x472) = reboot_mode;
 244
 245        /* For the switch to real mode, copy some code to low memory.  It has
 246           to be in the first 64k because it is running in 16-bit mode, and it
 247           has to have the same physical and virtual address, because it turns
 248           off paging.  Copy it near the end of the first page, out of the way
 249           of BIOS variables. */
 250
 251        memcpy ((void *) (0x1000 - sizeof (real_mode_switch) - 100),
 252                real_mode_switch, sizeof (real_mode_switch));
 253        memcpy ((void *) (0x1000 - 100), code, length);
 254
 255        /* Set up the IDT for real mode. */
 256
 257        load_idt(&real_mode_idt);
 258
 259        /* Set up a GDT from which we can load segment descriptors for real
 260           mode.  The GDT is not used in real mode; it is just needed here to
 261           prepare the descriptors. */
 262
 263        load_gdt(&real_mode_gdt);
 264
 265        /* Load the data segment registers, and thus the descriptors ready for
 266           real mode.  The base address of each segment is 0x100, 16 times the
 267           selector value being loaded here.  This is so that the segment
 268           registers don't have to be reloaded after switching to real mode:
 269           the values are consistent for real mode operation already. */
 270
 271        __asm__ __volatile__ ("movl $0x0010,%%eax\n"
 272                                "\tmovl %%eax,%%ds\n"
 273                                "\tmovl %%eax,%%es\n"
 274                                "\tmovl %%eax,%%fs\n"
 275                                "\tmovl %%eax,%%gs\n"
 276                                "\tmovl %%eax,%%ss" : : : "eax");
 277
 278        /* Jump to the 16-bit code that we copied earlier.  It disables paging
 279           and the cache, switches to real mode, and jumps to the BIOS reset
 280           entry point. */
 281
 282        __asm__ __volatile__ ("ljmp $0x0008,%0"
 283                                :
 284                                : "i" ((void *) (0x1000 - sizeof (real_mode_switch) - 100)));
 285}
 286#ifdef CONFIG_APM_MODULE
 287EXPORT_SYMBOL(machine_real_restart);
 288#endif
 289
 290static void native_machine_shutdown(void)
 291{
 292#ifdef CONFIG_SMP
 293        int reboot_cpu_id;
 294
 295        /* The boot cpu is always logical cpu 0 */
 296        reboot_cpu_id = 0;
 297
 298        /* See if there has been given a command line override */
 299        if ((reboot_cpu != -1) && (reboot_cpu < NR_CPUS) &&
 300                cpu_isset(reboot_cpu, cpu_online_map)) {
 301                reboot_cpu_id = reboot_cpu;
 302        }
 303
 304        /* Make certain the cpu I'm rebooting on is online */
 305        if (!cpu_isset(reboot_cpu_id, cpu_online_map)) {
 306                reboot_cpu_id = smp_processor_id();
 307        }
 308
 309        /* Make certain I only run on the appropriate processor */
 310        set_cpus_allowed(current, cpumask_of_cpu(reboot_cpu_id));
 311
 312        /* O.K. Now that I'm on the appropriate processor, stop
 313         * all of the others, and disable their local APICs.
 314         */
 315
 316        smp_send_stop();
 317#endif /* CONFIG_SMP */
 318
 319        lapic_shutdown();
 320
 321#ifdef CONFIG_X86_IO_APIC
 322        disable_IO_APIC();
 323#endif
 324}
 325
 326void __attribute__((weak)) mach_reboot_fixups(void)
 327{
 328}
 329
 330static void native_machine_emergency_restart(void)
 331{
 332        if (!reboot_thru_bios) {
 333                if (efi_enabled) {
 334                        efi.reset_system(EFI_RESET_COLD, EFI_SUCCESS, 0, NULL);
 335                        load_idt(&no_idt);
 336                        __asm__ __volatile__("int3");
 337                }
 338                /* rebooting needs to touch the page at absolute addr 0 */
 339                *((unsigned short *)__va(0x472)) = reboot_mode;
 340                for (;;) {
 341                        mach_reboot_fixups(); /* for board specific fixups */
 342                        mach_reboot();
 343                        /* That didn't work - force a triple fault.. */
 344                        load_idt(&no_idt);
 345                        __asm__ __volatile__("int3");
 346                }
 347        }
 348        if (efi_enabled)
 349                efi.reset_system(EFI_RESET_WARM, EFI_SUCCESS, 0, NULL);
 350
 351        machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
 352}
 353
 354static void native_machine_restart(char * __unused)
 355{
 356        machine_shutdown();
 357        machine_emergency_restart();
 358}
 359
 360static void native_machine_halt(void)
 361{
 362}
 363
 364static void native_machine_power_off(void)
 365{
 366        if (pm_power_off) {
 367                machine_shutdown();
 368                pm_power_off();
 369        }
 370}
 371
 372
 373struct machine_ops machine_ops = {
 374        .power_off = native_machine_power_off,
 375        .shutdown = native_machine_shutdown,
 376        .emergency_restart = native_machine_emergency_restart,
 377        .restart = native_machine_restart,
 378        .halt = native_machine_halt,
 379};
 380
 381void machine_power_off(void)
 382{
 383        machine_ops.power_off();
 384}
 385
 386void machine_shutdown(void)
 387{
 388        machine_ops.shutdown();
 389}
 390
 391void machine_emergency_restart(void)
 392{
 393        machine_ops.emergency_restart();
 394}
 395
 396void machine_restart(char *cmd)
 397{
 398        machine_ops.restart(cmd);
 399}
 400
 401void machine_halt(void)
 402{
 403        machine_ops.halt();
 404}
 405
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.