summaryrefslogtreecommitdiff
path: root/x86_64/boothdr.S
blob: 0ab9bd55b0fa1324a24685c73b842f7784c962e9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
/*
 *  Copyright (C) 2022 Free Software Foundation
 *
 * This program is free software ; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation ; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY ; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with the program ; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <mach/machine/asm.h>

#include <i386/i386asm.h>
#include <i386/i386/proc_reg.h>
#include <i386/i386/seg.h>
	/*
	 * This section will be put first into .boot.  See also	x86_64/ldscript.
	 */
	.section .boot.text,"ax"
	/* We should never be entered this way.	 */
	.globl	boot_start
boot_start:

	.code32
	jmp	boot_entry

	/* MultiBoot header - see multiboot.h.	*/
#define	MULTIBOOT_MAGIC		0x1BADB002
#define MULTIBOOT_FLAGS		0x00000003
	P2ALIGN(2)
boot_hdr:
	.long	MULTIBOOT_MAGIC
	.long	MULTIBOOT_FLAGS
	/*
	* The next item here is the checksum.
	* XX this works OK until we need at least the 30th bit.
	*/
	.long	- (MULTIBOOT_MAGIC+MULTIBOOT_FLAGS)

	.global _start
_start:
boot_entry:
	/*
	 * Prepare minimal page mapping to jump to 64 bit and to C code.
	 * The first 4GB is identity mapped, and the first 2GB are re-mapped
	 * to high addresses at KERNEL_MAP_BASE
	 */

	movl	$p3table,%eax
	or	$(PTE_V|PTE_W),%eax
	movl	%eax,(p4table)
	/*
	 * Fill 4 entries in L3 table to cover the whole 32-bit 4GB address
	 * space. Part of it might be remapped later if the kernel is mapped
	 * below 4G.
	 */
	movl	$p2table,%eax
	or	$(PTE_V|PTE_W),%eax
	movl	%eax,(p3table)
	movl	$p2table1,%eax
	or	$(PTE_V|PTE_W),%eax
	movl	%eax,(p3table + 8)
	movl	$p2table2,%eax
	or	$(PTE_V|PTE_W),%eax
	movl	%eax,(p3table + 16)
	movl	$p2table3,%eax
	or	$(PTE_V|PTE_W),%eax
	movl	%eax,(p3table + 24)
	/* point each page table level two entry to a page */
	mov	$0,%ecx
.map_p2_table:
	mov	$0x200000,%eax	 // 2MiB page, should be always available
	mul	%ecx
	or	$(PTE_V|PTE_W|PTE_S),%eax  // enable 2MiB page instead of 4k
	mov	%eax,p2table(,%ecx,8)
	inc	%ecx
	cmp	$2048,%ecx  // 512 entries per table, map 4 L2 tables
	jne	.map_p2_table

	/*
	 * KERNEL_MAP_BASE must me aligned to 2GB.
	 * Depending on kernel starting address, we might need to add another
	 * entry in the L4 table (controlling 512 GB chunks). In any case, we
	 * add two entries in L3 table to make sure we map 2GB for the kernel.
	 * Note that this may override part of the mapping create above.
	 */
.kernel_map:
#if KERNEL_MAP_BASE >= (1U << 39)
	movl	$p3ktable,%eax
	or	$(PTE_V|PTE_W),%eax
	movl	%eax,(p4table + (8 * ((KERNEL_MAP_BASE >> 39) & 0x1FF)))  // select 512G block
	movl	$p2ktable1,%eax
	or	$(PTE_V|PTE_W),%eax
	movl	%eax,(p3ktable + (8 * ((KERNEL_MAP_BASE >> 30) & 0x1FF) ))  // select first 1G block
	movl	$p2ktable2,%eax
	or	$(PTE_V|PTE_W),%eax
	movl	%eax,(p3ktable + (8 * (((KERNEL_MAP_BASE >> 30) & 0x1FF) + 1) ))  // select second 1G block
#else
	movl	$p2ktable1,%eax
	or	$(PTE_V|PTE_W),%eax
	movl	%eax,(p3table + (8 * ((KERNEL_MAP_BASE >> 30) & 0x1FF) ))  // select first 1G block
	movl	$p2ktable2,%eax
	or	$(PTE_V|PTE_W),%eax
	movl	%eax,(p3table + (8 * (((KERNEL_MAP_BASE >> 30) & 0x1FF) + 1) ))  // select second 1G block
#endif

	mov	$0,%ecx
.map_p2k_table:
	mov	$0x200000,%eax	 // 2MiB page, should be always available
	mul	%ecx
	or	$(PTE_V|PTE_W|PTE_S),%eax  // enable 2MiB page instead of 4K
	mov	%eax,p2ktable1(,%ecx,8)
	inc	%ecx
	cmp	$1024,%ecx  // 512 entries per table, map 2 L2 tables
	jne	.map_p2k_table

switch64:
	/*
	 * Jump to 64 bit mode, we have to
	 * - enable PAE
	 * - enable long mode
	 * - enable paging and load the tables filled above in CR3
	 * - jump to a 64-bit code segment
	 */
	mov	%cr4,%eax
	or	$CR4_PAE,%eax
	mov	%eax,%cr4
	mov	$0xC0000080,%ecx  // select EFER register
	rdmsr
	or	$(1 << 8),%eax	// long mode enable bit
	wrmsr
	mov	$p4table,%eax
	mov	%eax,%cr3
	mov	%cr0,%eax
	or	$CR0_PG,%eax
	or	$CR0_WP,%eax
	mov	%eax,%cr0

	lgdt	gdt64pointer
	movw	$0,%ax
	movw	%ax,%fs
	movw	%ax,%gs
	movw	$16,%ax
	movw	%ax,%ds
	movw	%ax,%es
	movw	%ax,%ss
	ljmp	$8,$boot_entry64

	.code64

boot_entry64:
	/* Switch to our own interrupt stack.  */
	movq	$solid_intstack+INTSTACK_SIZE-16, %rax
	andq	$(~15),%rax
	movq	%rax,%rsp

	/* Reset EFLAGS to a known state.  */
	pushq	$0
	popf
	/* save multiboot info for later */
	movq	%rbx,%r8

	/* Fix ifunc entries */
	movq	$__rela_iplt_start,%rsi
	movq	$__rela_iplt_end,%rdi
iplt_cont:
	cmpq	%rdi,%rsi
	jae	iplt_done
	movq	(%rsi),%rbx	/* r_offset */
	movb	4(%rsi),%al	/* info */
	cmpb	$42,%al		/* IRELATIVE */
	jnz	iplt_next
	call	*(%ebx)		/* call ifunc */
	movq	%rax,(%rbx)	/* fixed address */
iplt_next:
	addq	$8,%rsi
	jmp	iplt_cont
iplt_done:

	/* restore multiboot info */
	movq	%r8,%rdi
	/* Jump into C code.  */
	call	EXT(c_boot_entry)
	/* not reached */
	nop

	.code32
	.section .boot.data
	.align 4096
#define  SEG_ACCESS_OFS 40
#define  SEG_GRANULARITY_OFS 52
gdt64:
	.quad	0
gdt64code:
        .quad	(ACC_P << SEG_ACCESS_OFS) | (ACC_CODE_R << SEG_ACCESS_OFS) | (SZ_64 << SEG_GRANULARITY_OFS)
gdt64data:
        .quad	(ACC_P << SEG_ACCESS_OFS) | (ACC_DATA_W << SEG_ACCESS_OFS)
gdt64end:
	.skip	(4096 - (gdt64end - gdt64))
gdt64pointer:
	.word	gdt64end - gdt64 - 1
	.quad	gdt64

	.section .boot.data
	.align 4096
p4table:	.space 4096
p3table:	.space 4096
p2table:	.space 4096
p2table1:	.space 4096
p2table2:	.space 4096
p2table3:	.space 4096
p3ktable:	.space 4096
p2ktable1:	 .space 4096
p2ktable2:	 .space 4096