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