PageRenderTime 29ms CodeModel.GetById 16ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 0ms

/arch/x86/kernel/reboot_32.S

https://gitlab.com/Team-OSE-old/SimpleKernel
Assembly | 135 lines | 128 code | 7 blank | 0 comment | 4 complexity | 1faced100123512104ba7ee8bc1b89a7 MD5 | raw file
  1#include <linux/linkage.h>
  2#include <linux/init.h>
  3#include <asm/segment.h>
  4#include <asm/page_types.h>
  5
  6/*
  7 * The following code and data reboots the machine by switching to real
  8 * mode and jumping to the BIOS reset entry point, as if the CPU has
  9 * really been reset.  The previous version asked the keyboard
 10 * controller to pulse the CPU reset line, which is more thorough, but
 11 * doesn't work with at least one type of 486 motherboard.  It is easy
 12 * to stop this code working; hence the copious comments.
 13 *
 14 * This code is called with the restart type (0 = BIOS, 1 = APM) in %eax.
 15 */
 16	.section ".x86_trampoline","a"
 17	.balign 16
 18	.code32
 19ENTRY(machine_real_restart_asm)
 20r_base = .
 21	/* Get our own relocated address */
 22	call	1f
 231:	popl	%ebx
 24	subl	$(1b - r_base), %ebx
 25
 26	/* Compute the equivalent real-mode segment */
 27	movl	%ebx, %ecx
 28	shrl	$4, %ecx
 29	
 30	/* Patch post-real-mode segment jump */
 31	movw	(dispatch_table - r_base)(%ebx,%eax,2),%ax
 32	movw	%ax, (101f - r_base)(%ebx)
 33	movw	%cx, (102f - r_base)(%ebx)
 34
 35	/* Set up the IDT for real mode. */
 36	lidtl	(machine_real_restart_idt - r_base)(%ebx)
 37
 38	/*
 39	 * Set up a GDT from which we can load segment descriptors for real
 40	 * mode.  The GDT is not used in real mode; it is just needed here to
 41	 * prepare the descriptors.
 42	 */
 43	lgdtl	(machine_real_restart_gdt - r_base)(%ebx)
 44
 45	/*
 46	 * Load the data segment registers with 16-bit compatible values
 47	 */
 48	movl	$16, %ecx
 49	movl	%ecx, %ds
 50	movl	%ecx, %es
 51	movl	%ecx, %fs
 52	movl	%ecx, %gs
 53	movl	%ecx, %ss
 54	ljmpl	$8, $1f - r_base
 55
 56/*
 57 * This is 16-bit protected mode code to disable paging and the cache,
 58 * switch to real mode and jump to the BIOS reset code.
 59 *
 60 * The instruction that switches to real mode by writing to CR0 must be
 61 * followed immediately by a far jump instruction, which set CS to a
 62 * valid value for real mode, and flushes the prefetch queue to avoid
 63 * running instructions that have already been decoded in protected
 64 * mode.
 65 *
 66 * Clears all the flags except ET, especially PG (paging), PE
 67 * (protected-mode enable) and TS (task switch for coprocessor state
 68 * save).  Flushes the TLB after paging has been disabled.  Sets CD and
 69 * NW, to disable the cache on a 486, and invalidates the cache.  This
 70 * is more like the state of a 486 after reset.  I don't know if
 71 * something else should be done for other chips.
 72 *
 73 * More could be done here to set up the registers as if a CPU reset had
 74 * occurred; hopefully real BIOSs don't assume much.  This is not the
 75 * actual BIOS entry point, anyway (that is at 0xfffffff0).
 76 *
 77 * Most of this work is probably excessive, but it is what is tested.
 78 */
 79	.code16
 801:
 81	xorl	%ecx, %ecx
 82	movl	%cr0, %eax
 83	andl	$0x00000011, %eax
 84	orl	$0x60000000, %eax
 85	movl	%eax, %cr0
 86	movl	%ecx, %cr3
 87	movl	%cr0, %edx
 88	andl	$0x60000000, %edx	/* If no cache bits -> no wbinvd */
 89	jz	2f
 90	wbinvd
 912:
 92	andb	$0x10, %al
 93	movl	%eax, %cr0
 94	.byte	0xea			/* ljmpw */
 95101:	.word	0			/* Offset */
 96102:	.word	0			/* Segment */
 97
 98bios:
 99	ljmpw	$0xf000, $0xfff0
100
101apm:
102	movw	$0x1000, %ax
103	movw	%ax, %ss
104	movw	$0xf000, %sp
105	movw	$0x5307, %ax
106	movw	$0x0001, %bx
107	movw	$0x0003, %cx
108	int	$0x15
109
110END(machine_real_restart_asm)
111
112	.balign 16
113	/* These must match <asm/reboot.h */
114dispatch_table:
115	.word	bios - r_base
116	.word	apm - r_base
117END(dispatch_table)
118
119	.balign 16
120machine_real_restart_idt:
121	.word	0xffff		/* Length - real mode default value */
122	.long	0		/* Base - real mode default value */
123END(machine_real_restart_idt)
124
125	.balign 16
126ENTRY(machine_real_restart_gdt)
127	.quad	0		/* Self-pointer, filled in by PM code */
128	.quad	0		/* 16-bit code segment, filled in by PM code */
129	/*
130	 * 16-bit data segment with the selector value 16 = 0x10 and
131	 * base value 0x100; since this is consistent with real mode
132	 * semantics we don't have to reload the segments once CR0.PE = 0.
133	 */
134	.quad	GDT_ENTRY(0x0093, 0x100, 0xffff)
135END(machine_real_restart_gdt)