1/*
2 * Copyright 2012, Alex Smith, alex@alex-smith.me.uk.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include <asm_defs.h>
8
9#define __x86_64__
10#include <arch/x86/descriptors.h>
11
12#include "mmu.h"
13#undef __x86_64__
14
15
16#define GDT_LIMIT 0x800
17
18
19.code32
20
21
22/*!	void long_enter_kernel(int currentCPU, uint64 stackTop); */
23FUNCTION(long_enter_kernel):
24	// Preserve the arguments. We may no longer be able to use the stack once
25	// paging is disabled.
26	movl	4(%esp), %ebx
27	movl	8(%esp), %edi
28	movl	12(%esp), %esi
29
30	movl	gLongLA57, %ecx
31	shl		$12, %ecx
32
33	// Currently running with 32-bit paging tables at an identity mapped
34	// address. To switch to 64-bit paging we must first disable 32-bit paging,
35	// otherwise loading the new CR3 will fault.
36	movl	%cr0, %eax
37	andl	$~(1 << 31), %eax
38	movl	%eax, %cr0
39
40	// Enable PAE and PGE, and optionally LA57
41	movl	%cr4, %eax
42	orl		$(1 << 5) | (1 << 7), %eax
43	orl		%ecx, %eax
44	movl	%eax, %cr4
45
46	// Point CR3 to the kernel's PMLTop.
47	movl	gLongPhysicalPMLTop, %eax
48	movl	%eax, %cr3
49
50	// Enable long mode by setting EFER.LME.
51	movl	$0xc0000080, %ecx
52	rdmsr
53	orl		$(1 << 8), %eax
54	wrmsr
55
56	// Re-enable paging, which will put us in compatibility mode as we are
57	// currently in a 32-bit code segment.
58	movl	%cr0, %ecx
59	orl		$(1 << 31), %ecx
60	movl	%ecx, %cr0
61
62	// Load 64-bit enabled GDT
63	lgdtl	long_gdtr
64
65	// Jump into the 64-bit code segment.
66	ljmp	$KERNEL_CODE_SELECTOR, $.Llmode
67.align 8
68.code64
69.Llmode:
70	// Set data segments.
71	mov		$KERNEL_DATA_SELECTOR, %ax
72	mov		%ax, %ss
73	xor		%ax, %ax
74	mov		%ax, %ds
75	mov		%ax, %es
76	mov		%ax, %fs
77	mov		%ax, %gs
78
79	// Set the stack pointer.
80	movl	%edi, %esp
81	shl		$32, %rsi
82	orq		%rsi, %rsp
83
84	// Clear the stack frame/RFLAGS.
85	xorq	%rbp, %rbp
86	push	$0
87	popf
88
89	// Get arguments and call the kernel entry point.
90	leaq	gKernelArgs(%rip), %rdi
91	movl	%ebx, %esi
92	movq	gLongKernelEntry(%rip), %rax
93	call	*%rax
94
95
96.data
97
98
99long_gdtr:
100	.word	BOOT_GDT_SEGMENT_COUNT * 8 - 1
101SYMBOL(gLongGDT):
102	.long	0
103
104SYMBOL(gLongPhysicalPMLTop):
105	.long	0
106
107SYMBOL(gLongLA57):
108	.long	0
109
110SYMBOL(gLongKernelEntry):
111	.quad	0
112