xref: /haiku/src/system/boot/platform/bios_ia32/long_asm.S (revision 1e60bdeab63fa7a57bc9a55b032052e95a18bd2c)
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	// Currently running with 32-bit paging tables at an identity mapped
31	// address. To switch to 64-bit paging we must first disable 32-bit paging,
32	// otherwise loading the new CR3 will fault.
33	movl	%cr0, %eax
34	andl	$~(1 << 31), %eax
35	movl	%eax, %cr0
36
37	// Enable PAE and PGE
38	movl	%cr4, %eax
39	orl		$(1 << 5) | (1 << 7), %eax
40	movl	%eax, %cr4
41
42	// Point CR3 to the kernel's PML4.
43	movl	gLongPhysicalPML4, %eax
44	movl	%eax, %cr3
45
46	// Enable long mode by setting EFER.LME.
47	movl	$0xc0000080, %ecx
48	rdmsr
49	orl		$(1 << 8), %eax
50	wrmsr
51
52	// Re-enable paging, which will put us in compatibility mode as we are
53	// currently in a 32-bit code segment.
54	movl	%cr0, %ecx
55	orl		$(1 << 31), %ecx
56	movl	%ecx, %cr0
57
58	// Load 64-bit enabled GDT
59	lgdtl	long_gdtr
60
61	// Jump into the 64-bit code segment.
62	ljmp	$KERNEL_CODE_SELECTOR, $.Llmode
63.align 8
64.code64
65.Llmode:
66	// Set data segments.
67	mov		$KERNEL_DATA_SELECTOR, %ax
68	mov		%ax, %ss
69	xor		%ax, %ax
70	mov		%ax, %ds
71	mov		%ax, %es
72	mov		%ax, %fs
73	mov		%ax, %gs
74
75	// Set the stack pointer.
76	movl	%edi, %esp
77	shl		$32, %rsi
78	orq		%rsi, %rsp
79
80	// Clear the stack frame/RFLAGS.
81	xorq	%rbp, %rbp
82	push	$0
83	popf
84
85	// Get arguments and call the kernel entry point.
86	leaq	gKernelArgs(%rip), %rdi
87	movl	%ebx, %esi
88	movq	gLongKernelEntry(%rip), %rax
89	call	*%rax
90
91
92.data
93
94
95long_gdtr:
96	.word	BOOT_GDT_SEGMENT_COUNT * 8 - 1
97SYMBOL(gLongGDT):
98	.long	0
99
100SYMBOL(gLongPhysicalPML4):
101	.long	0
102
103SYMBOL(gLongKernelEntry):
104	.quad	0
105