~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/x86/realmode/rm/reboot.S

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* SPDX-License-Identifier: GPL-2.0 */
  2 #include <linux/linkage.h>
  3 #include <asm/desc_defs.h>
  4 #include <asm/segment.h>
  5 #include <asm/page_types.h>
  6 #include <asm/processor-flags.h>
  7 #include <asm/msr-index.h>
  8 #include "realmode.h"
  9 
 10 /*
 11  * The following code and data reboots the machine by switching to real
 12  * mode and jumping to the BIOS reset entry point, as if the CPU has
 13  * really been reset.  The previous version asked the keyboard
 14  * controller to pulse the CPU reset line, which is more thorough, but
 15  * doesn't work with at least one type of 486 motherboard.  It is easy
 16  * to stop this code working; hence the copious comments.
 17  *
 18  * This code is called with the restart type (0 = BIOS, 1 = APM) in
 19  * the primary argument register (%eax for 32 bit, %edi for 64 bit).
 20  */
 21         .section ".text32", "ax"
 22         .code32
 23 SYM_CODE_START(machine_real_restart_asm)
 24 
 25 #ifdef CONFIG_X86_64
 26         /* Switch to trampoline GDT as it is guaranteed < 4 GiB */
 27         movl    $__KERNEL_DS, %eax
 28         movl    %eax, %ds
 29         lgdtl   pa_tr_gdt
 30 
 31         /* Disable paging to drop us out of long mode */
 32         movl    %cr0, %eax
 33         andl    $~X86_CR0_PG, %eax
 34         movl    %eax, %cr0
 35         ljmpl   $__KERNEL32_CS, $pa_machine_real_restart_paging_off
 36 
 37 SYM_INNER_LABEL(machine_real_restart_paging_off, SYM_L_GLOBAL)
 38         xorl    %eax, %eax
 39         xorl    %edx, %edx
 40         movl    $MSR_EFER, %ecx
 41         wrmsr
 42 
 43         movl    %edi, %eax
 44         
 45 #endif /* CONFIG_X86_64 */
 46         
 47         /* Set up the IDT for real mode. */
 48         lidtl   pa_machine_real_restart_idt
 49 
 50         /*
 51          * Set up a GDT from which we can load segment descriptors for real
 52          * mode.  The GDT is not used in real mode; it is just needed here to
 53          * prepare the descriptors.
 54          */
 55         lgdtl   pa_machine_real_restart_gdt
 56 
 57         /*
 58          * Load the data segment registers with 16-bit compatible values
 59          */
 60         movl    $16, %ecx
 61         movl    %ecx, %ds
 62         movl    %ecx, %es
 63         movl    %ecx, %fs
 64         movl    %ecx, %gs
 65         movl    %ecx, %ss
 66         ljmpw   $8, $1f
 67 SYM_CODE_END(machine_real_restart_asm)
 68 
 69 /*
 70  * This is 16-bit protected mode code to disable paging and the cache,
 71  * switch to real mode and jump to the BIOS reset code.
 72  *
 73  * The instruction that switches to real mode by writing to CR0 must be
 74  * followed immediately by a far jump instruction, which set CS to a
 75  * valid value for real mode, and flushes the prefetch queue to avoid
 76  * running instructions that have already been decoded in protected
 77  * mode.
 78  *
 79  * Clears all the flags except ET, especially PG (paging), PE
 80  * (protected-mode enable) and TS (task switch for coprocessor state
 81  * save).  Flushes the TLB after paging has been disabled.  Sets CD and
 82  * NW, to disable the cache on a 486, and invalidates the cache.  This
 83  * is more like the state of a 486 after reset.  I don't know if
 84  * something else should be done for other chips.
 85  *
 86  * More could be done here to set up the registers as if a CPU reset had
 87  * occurred; hopefully real BIOSs don't assume much.  This is not the
 88  * actual BIOS entry point, anyway (that is at 0xfffffff0).
 89  *
 90  * Most of this work is probably excessive, but it is what is tested.
 91  */
 92         .text
 93         .code16
 94 
 95         .balign 16
 96 machine_real_restart_asm16:
 97 1:
 98         xorl    %ecx, %ecx
 99         movl    %cr0, %edx
100         andl    $0x00000011, %edx
101         orl     $0x60000000, %edx
102         movl    %edx, %cr0
103         movl    %ecx, %cr3
104         movl    %cr0, %edx
105         testl   $0x60000000, %edx       /* If no cache bits -> no wbinvd */
106         jz      2f
107         wbinvd
108 2:
109         andb    $0x10, %dl
110         movl    %edx, %cr0
111         LJMPW_RM(3f)
112 3:
113         andw    %ax, %ax
114         jz      bios
115 
116 apm:
117         movw    $0x1000, %ax
118         movw    %ax, %ss
119         movw    $0xf000, %sp
120         movw    $0x5307, %ax
121         movw    $0x0001, %bx
122         movw    $0x0003, %cx
123         int     $0x15
124         /* This should never return... */
125 
126 bios:
127         ljmpw   $0xf000, $0xfff0
128 
129         .section ".rodata", "a"
130 
131         .balign 16
132 SYM_DATA_START(machine_real_restart_idt)
133         .word   0xffff          /* Length - real mode default value */
134         .long   0               /* Base - real mode default value */
135 SYM_DATA_END(machine_real_restart_idt)
136 
137         .balign 16
138 SYM_DATA_START(machine_real_restart_gdt)
139         /* Self-pointer */
140         .word   0xffff          /* Length - real mode default value */
141         .long   pa_machine_real_restart_gdt
142         .word   0
143 
144         /*
145          * 16-bit code segment pointing to real_mode_seg
146          * Selector value 8
147          */
148         .word   0xffff          /* Limit */
149         .long   0x9b000000 + pa_real_mode_base
150         .word   0
151 
152         /*
153          * 16-bit data segment with the selector value 16 = 0x10 and
154          * base value 0x100; since this is consistent with real mode
155          * semantics we don't have to reload the segments once CR0.PE = 0.
156          */
157         .quad   GDT_ENTRY(DESC_DATA16, 0x100, 0xffff)
158 SYM_DATA_END(machine_real_restart_gdt)

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php