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