![]() |
|
|||
0001 /* SPDX-License-Identifier: GPL-2.0 */ 0002 #include <linux/linkage.h> 0003 #include <asm/segment.h> 0004 #include <asm/page_types.h> 0005 #include <asm/processor-flags.h> 0006 #include <asm/msr-index.h> 0007 #include "realmode.h" 0008 0009 /* 0010 * The following code and data reboots the machine by switching to real 0011 * mode and jumping to the BIOS reset entry point, as if the CPU has 0012 * really been reset. The previous version asked the keyboard 0013 * controller to pulse the CPU reset line, which is more thorough, but 0014 * doesn't work with at least one type of 486 motherboard. It is easy 0015 * to stop this code working; hence the copious comments. 0016 * 0017 * This code is called with the restart type (0 = BIOS, 1 = APM) in 0018 * the primary argument register (%eax for 32 bit, %edi for 64 bit). 0019 */ 0020 .section ".text32", "ax" 0021 .code32 0022 SYM_CODE_START(machine_real_restart_asm) 0023 0024 #ifdef CONFIG_X86_64 0025 /* Switch to trampoline GDT as it is guaranteed < 4 GiB */ 0026 movl $__KERNEL_DS, %eax 0027 movl %eax, %ds 0028 lgdtl pa_tr_gdt 0029 0030 /* Disable paging to drop us out of long mode */ 0031 movl %cr0, %eax 0032 andl $~X86_CR0_PG, %eax 0033 movl %eax, %cr0 0034 ljmpl $__KERNEL32_CS, $pa_machine_real_restart_paging_off 0035 0036 SYM_INNER_LABEL(machine_real_restart_paging_off, SYM_L_GLOBAL) 0037 xorl %eax, %eax 0038 xorl %edx, %edx 0039 movl $MSR_EFER, %ecx 0040 wrmsr 0041 0042 movl %edi, %eax 0043 0044 #endif /* CONFIG_X86_64 */ 0045 0046 /* Set up the IDT for real mode. */ 0047 lidtl pa_machine_real_restart_idt 0048 0049 /* 0050 * Set up a GDT from which we can load segment descriptors for real 0051 * mode. The GDT is not used in real mode; it is just needed here to 0052 * prepare the descriptors. 0053 */ 0054 lgdtl pa_machine_real_restart_gdt 0055 0056 /* 0057 * Load the data segment registers with 16-bit compatible values 0058 */ 0059 movl $16, %ecx 0060 movl %ecx, %ds 0061 movl %ecx, %es 0062 movl %ecx, %fs 0063 movl %ecx, %gs 0064 movl %ecx, %ss 0065 ljmpw $8, $1f 0066 SYM_CODE_END(machine_real_restart_asm) 0067 0068 /* 0069 * This is 16-bit protected mode code to disable paging and the cache, 0070 * switch to real mode and jump to the BIOS reset code. 0071 * 0072 * The instruction that switches to real mode by writing to CR0 must be 0073 * followed immediately by a far jump instruction, which set CS to a 0074 * valid value for real mode, and flushes the prefetch queue to avoid 0075 * running instructions that have already been decoded in protected 0076 * mode. 0077 * 0078 * Clears all the flags except ET, especially PG (paging), PE 0079 * (protected-mode enable) and TS (task switch for coprocessor state 0080 * save). Flushes the TLB after paging has been disabled. Sets CD and 0081 * NW, to disable the cache on a 486, and invalidates the cache. This 0082 * is more like the state of a 486 after reset. I don't know if 0083 * something else should be done for other chips. 0084 * 0085 * More could be done here to set up the registers as if a CPU reset had 0086 * occurred; hopefully real BIOSs don't assume much. This is not the 0087 * actual BIOS entry point, anyway (that is at 0xfffffff0). 0088 * 0089 * Most of this work is probably excessive, but it is what is tested. 0090 */ 0091 .text 0092 .code16 0093 0094 .balign 16 0095 machine_real_restart_asm16: 0096 1: 0097 xorl %ecx, %ecx 0098 movl %cr0, %edx 0099 andl $0x00000011, %edx 0100 orl $0x60000000, %edx 0101 movl %edx, %cr0 0102 movl %ecx, %cr3 0103 movl %cr0, %edx 0104 testl $0x60000000, %edx /* If no cache bits -> no wbinvd */ 0105 jz 2f 0106 wbinvd 0107 2: 0108 andb $0x10, %dl 0109 movl %edx, %cr0 0110 LJMPW_RM(3f) 0111 3: 0112 andw %ax, %ax 0113 jz bios 0114 0115 apm: 0116 movw $0x1000, %ax 0117 movw %ax, %ss 0118 movw $0xf000, %sp 0119 movw $0x5307, %ax 0120 movw $0x0001, %bx 0121 movw $0x0003, %cx 0122 int $0x15 0123 /* This should never return... */ 0124 0125 bios: 0126 ljmpw $0xf000, $0xfff0 0127 0128 .section ".rodata", "a" 0129 0130 .balign 16 0131 SYM_DATA_START(machine_real_restart_idt) 0132 .word 0xffff /* Length - real mode default value */ 0133 .long 0 /* Base - real mode default value */ 0134 SYM_DATA_END(machine_real_restart_idt) 0135 0136 .balign 16 0137 SYM_DATA_START(machine_real_restart_gdt) 0138 /* Self-pointer */ 0139 .word 0xffff /* Length - real mode default value */ 0140 .long pa_machine_real_restart_gdt 0141 .word 0 0142 0143 /* 0144 * 16-bit code segment pointing to real_mode_seg 0145 * Selector value 8 0146 */ 0147 .word 0xffff /* Limit */ 0148 .long 0x9b000000 + pa_real_mode_base 0149 .word 0 0150 0151 /* 0152 * 16-bit data segment with the selector value 16 = 0x10 and 0153 * base value 0x100; since this is consistent with real mode 0154 * semantics we don't have to reload the segments once CR0.PE = 0. 0155 */ 0156 .quad GDT_ENTRY(0x0093, 0x100, 0xffff) 0157 SYM_DATA_END(machine_real_restart_gdt)
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.1.0 LXR engine. The LXR team |
![]() ![]() |