1/*
2** Copyright 2001, Travis Geiselbrecht. All rights reserved.
3** Copyright 2012, Alex Smith, alex@alex-smith.me.uk.
4** Distributed under the terms of the NewOS License.
5*/
6
7// Relocatable. Before calling, long_smp_trampoline_args should point
8// to a struct long_trampoline_args (see smp.cpp). This pointer should
9// be 16-byte aligned, below 1MB and identity-mapped.
10.globl long_smp_trampoline
11.globl long_smp_trampoline_end
12.globl long_smp_trampoline_args
13
14#include <asm_defs.h>
15
16#include <arch/x86/descriptors.h>
17#include "mmu.h"
18
19.code16
20long_smp_trampoline:
21	cli
22
23//  movl 0xdeadbeef, esi
24	.byte 0x66
25	.byte 0xbe
26long_smp_trampoline_args:
27	.long 0xdeadbeef
28
29	// Load the trampoline args into ss.
30	movl %esi, %eax
31	shrl $4, %eax
32	movw %ax, %ss
33	xorw %sp, %sp
34
35	// Switch to protected mode.
36	popl %ebx
37	popl %edx
38	lgdt (%edx)
39
40	movl   %cr0,%eax
41	orl    $0x01,%eax
42	movl   %eax,%cr0
43
44	pushl  $8
45	leal  (long_trampoline_32 - long_smp_trampoline)(%ebx), %eax
46	pushl  %eax
47	.byte 0x66
48.code32
49	lret
50
51long_trampoline_32:
52	mov    $0x10, %ax
53	mov    %ax, %ds
54	mov    %ax, %es
55	mov    %ax, %fs
56	mov    %ax, %gs
57	mov    %ax, %ss
58	// Put the trampoline args on the stack.
59	movl   %esi, %esp
60	addl   $8, %esp
61
62	// Enable PAE and PGE
63	movl	%cr4, %eax
64	orl		$(1 << 5) | (1 << 7), %eax
65	movl	%eax, %cr4
66
67	// Point CR3 to the kernel's PML4.
68	popl	%eax
69	movl	%eax, %cr3
70
71	// Enable long mode by setting EFER.LME.
72	movl	$0xc0000080, %ecx
73	rdmsr
74	orl		$(1 << 8), %eax
75	wrmsr
76
77	// Re-enable paging, which will put us in compatibility mode as we are
78	// currently in a 32-bit code segment.
79	movl	%cr0, %ecx
80	orl		$(1 << 31), %ecx
81	movl	%ecx, %cr0
82
83	// Load 64-bit enabled GDT
84	popl	%eax
85	lgdtl	(%eax)
86
87	// Jump into the 64-bit code segment.
88	pushl	$KERNEL_CODE_SELECTOR
89	leal	(.Llmode - long_smp_trampoline)(%ebx), %eax
90	pushl	%eax
91	lret
92.align 8
93.code64
94.Llmode:
95	// Set data segments.
96	mov		$KERNEL_DATA_SELECTOR, %ax
97	mov		%ax, %ss
98	xor		%ax, %ax
99	mov		%ax, %ds
100	mov		%ax, %es
101	mov		%ax, %fs
102	mov		%ax, %gs
103
104	// Initialisation that comes from long_smp_start_kernel.
105	movq	%cr0, %rax
106	orq		$0x10000, %rax
107	andq	$(~6), %rax
108	movq	%rax, %cr0
109	fninit
110	movq	%cr4, %rax
111	orq		$0x600, %rax
112	movq	%rax, %cr4
113
114	// Get kernel arguments.
115	popq	%rax
116	popq	%rdi
117	popq	%rsi
118
119	// Set the stack pointer, write to the sentinel and clear the stack frame/RFLAGS.
120	popq	%rbp
121	movq	$0, (%rsp)
122	movq	%rbp, %rsp
123	xorq	%rbp, %rbp
124	push	$0
125	popf
126
127	// Call the entry point.
128	call	*%rax
129long_smp_trampoline_end:
130