OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [arch/] [x86/] [kernel/] [reboot_32.c] - Blame information for rev 3

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.