xref: /openbmc/linux/arch/x86/boot/compressed/head_64.S (revision 82003e04)
1/*
2 *  linux/boot/head.S
3 *
4 *  Copyright (C) 1991, 1992, 1993  Linus Torvalds
5 */
6
7/*
8 *  head.S contains the 32-bit startup code.
9 *
10 * NOTE!!! Startup happens at absolute address 0x00001000, which is also where
11 * the page directory will exist. The startup code will be overwritten by
12 * the page directory. [According to comments etc elsewhere on a compressed
13 * kernel it will end up at 0x1000 + 1Mb I hope so as I assume this. - AC]
14 *
15 * Page 0 is deliberately kept safe, since System Management Mode code in
16 * laptops may need to access the BIOS data stored there.  This is also
17 * useful for future device drivers that either access the BIOS via VM86
18 * mode.
19 */
20
21/*
22 * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
23 */
24	.code32
25	.text
26
27#include <linux/init.h>
28#include <linux/linkage.h>
29#include <asm/segment.h>
30#include <asm/boot.h>
31#include <asm/msr.h>
32#include <asm/processor-flags.h>
33#include <asm/asm-offsets.h>
34#include <asm/bootparam.h>
35
36/*
37 * Locally defined symbols should be marked hidden:
38 */
39	.hidden _bss
40	.hidden _ebss
41	.hidden _got
42	.hidden _egot
43
44	__HEAD
45	.code32
46ENTRY(startup_32)
47	/*
48	 * 32bit entry is 0 and it is ABI so immutable!
49	 * If we come here directly from a bootloader,
50	 * kernel(text+data+bss+brk) ramdisk, zero_page, command line
51	 * all need to be under the 4G limit.
52	 */
53	cld
54	/*
55	 * Test KEEP_SEGMENTS flag to see if the bootloader is asking
56	 * us to not reload segments
57	 */
58	testb $KEEP_SEGMENTS, BP_loadflags(%esi)
59	jnz 1f
60
61	cli
62	movl	$(__BOOT_DS), %eax
63	movl	%eax, %ds
64	movl	%eax, %es
65	movl	%eax, %ss
661:
67
68/*
69 * Calculate the delta between where we were compiled to run
70 * at and where we were actually loaded at.  This can only be done
71 * with a short local call on x86.  Nothing  else will tell us what
72 * address we are running at.  The reserved chunk of the real-mode
73 * data at 0x1e4 (defined as a scratch field) are used as the stack
74 * for this calculation. Only 4 bytes are needed.
75 */
76	leal	(BP_scratch+4)(%esi), %esp
77	call	1f
781:	popl	%ebp
79	subl	$1b, %ebp
80
81/* setup a stack and make sure cpu supports long mode. */
82	movl	$boot_stack_end, %eax
83	addl	%ebp, %eax
84	movl	%eax, %esp
85
86	call	verify_cpu
87	testl	%eax, %eax
88	jnz	no_longmode
89
90/*
91 * Compute the delta between where we were compiled to run at
92 * and where the code will actually run at.
93 *
94 * %ebp contains the address we are loaded at by the boot loader and %ebx
95 * contains the address where we should move the kernel image temporarily
96 * for safe in-place decompression.
97 */
98
99#ifdef CONFIG_RELOCATABLE
100	movl	%ebp, %ebx
101	movl	BP_kernel_alignment(%esi), %eax
102	decl	%eax
103	addl	%eax, %ebx
104	notl	%eax
105	andl	%eax, %ebx
106	cmpl	$LOAD_PHYSICAL_ADDR, %ebx
107	jge	1f
108#endif
109	movl	$LOAD_PHYSICAL_ADDR, %ebx
1101:
111
112	/* Target address to relocate to for decompression */
113	movl	BP_init_size(%esi), %eax
114	subl	$_end, %eax
115	addl	%eax, %ebx
116
117/*
118 * Prepare for entering 64 bit mode
119 */
120
121	/* Load new GDT with the 64bit segments using 32bit descriptor */
122	leal	gdt(%ebp), %eax
123	movl	%eax, gdt+2(%ebp)
124	lgdt	gdt(%ebp)
125
126	/* Enable PAE mode */
127	movl	%cr4, %eax
128	orl	$X86_CR4_PAE, %eax
129	movl	%eax, %cr4
130
131 /*
132  * Build early 4G boot pagetable
133  */
134	/* Initialize Page tables to 0 */
135	leal	pgtable(%ebx), %edi
136	xorl	%eax, %eax
137	movl	$(BOOT_INIT_PGT_SIZE/4), %ecx
138	rep	stosl
139
140	/* Build Level 4 */
141	leal	pgtable + 0(%ebx), %edi
142	leal	0x1007 (%edi), %eax
143	movl	%eax, 0(%edi)
144
145	/* Build Level 3 */
146	leal	pgtable + 0x1000(%ebx), %edi
147	leal	0x1007(%edi), %eax
148	movl	$4, %ecx
1491:	movl	%eax, 0x00(%edi)
150	addl	$0x00001000, %eax
151	addl	$8, %edi
152	decl	%ecx
153	jnz	1b
154
155	/* Build Level 2 */
156	leal	pgtable + 0x2000(%ebx), %edi
157	movl	$0x00000183, %eax
158	movl	$2048, %ecx
1591:	movl	%eax, 0(%edi)
160	addl	$0x00200000, %eax
161	addl	$8, %edi
162	decl	%ecx
163	jnz	1b
164
165	/* Enable the boot page tables */
166	leal	pgtable(%ebx), %eax
167	movl	%eax, %cr3
168
169	/* Enable Long mode in EFER (Extended Feature Enable Register) */
170	movl	$MSR_EFER, %ecx
171	rdmsr
172	btsl	$_EFER_LME, %eax
173	wrmsr
174
175	/* After gdt is loaded */
176	xorl	%eax, %eax
177	lldt	%ax
178	movl    $__BOOT_TSS, %eax
179	ltr	%ax
180
181	/*
182	 * Setup for the jump to 64bit mode
183	 *
184	 * When the jump is performend we will be in long mode but
185	 * in 32bit compatibility mode with EFER.LME = 1, CS.L = 0, CS.D = 1
186	 * (and in turn EFER.LMA = 1).	To jump into 64bit mode we use
187	 * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
188	 * We place all of the values on our mini stack so lret can
189	 * used to perform that far jump.
190	 */
191	pushl	$__KERNEL_CS
192	leal	startup_64(%ebp), %eax
193#ifdef CONFIG_EFI_MIXED
194	movl	efi32_config(%ebp), %ebx
195	cmp	$0, %ebx
196	jz	1f
197	leal	handover_entry(%ebp), %eax
1981:
199#endif
200	pushl	%eax
201
202	/* Enter paged protected Mode, activating Long Mode */
203	movl	$(X86_CR0_PG | X86_CR0_PE), %eax /* Enable Paging and Protected mode */
204	movl	%eax, %cr0
205
206	/* Jump from 32bit compatibility mode into 64bit mode. */
207	lret
208ENDPROC(startup_32)
209
210#ifdef CONFIG_EFI_MIXED
211	.org 0x190
212ENTRY(efi32_stub_entry)
213	add	$0x4, %esp		/* Discard return address */
214	popl	%ecx
215	popl	%edx
216	popl	%esi
217
218	leal	(BP_scratch+4)(%esi), %esp
219	call	1f
2201:	pop	%ebp
221	subl	$1b, %ebp
222
223	movl	%ecx, efi32_config(%ebp)
224	movl	%edx, efi32_config+8(%ebp)
225	sgdtl	efi32_boot_gdt(%ebp)
226
227	leal	efi32_config(%ebp), %eax
228	movl	%eax, efi_config(%ebp)
229
230	jmp	startup_32
231ENDPROC(efi32_stub_entry)
232#endif
233
234	.code64
235	.org 0x200
236ENTRY(startup_64)
237	/*
238	 * 64bit entry is 0x200 and it is ABI so immutable!
239	 * We come here either from startup_32 or directly from a
240	 * 64bit bootloader.
241	 * If we come here from a bootloader, kernel(text+data+bss+brk),
242	 * ramdisk, zero_page, command line could be above 4G.
243	 * We depend on an identity mapped page table being provided
244	 * that maps our entire kernel(text+data+bss+brk), zero page
245	 * and command line.
246	 */
247#ifdef CONFIG_EFI_STUB
248	/*
249	 * The entry point for the PE/COFF executable is efi_pe_entry, so
250	 * only legacy boot loaders will execute this jmp.
251	 */
252	jmp	preferred_addr
253
254ENTRY(efi_pe_entry)
255	movq	%rcx, efi64_config(%rip)	/* Handle */
256	movq	%rdx, efi64_config+8(%rip) /* EFI System table pointer */
257
258	leaq	efi64_config(%rip), %rax
259	movq	%rax, efi_config(%rip)
260
261	call	1f
2621:	popq	%rbp
263	subq	$1b, %rbp
264
265	/*
266	 * Relocate efi_config->call().
267	 */
268	addq	%rbp, efi64_config+32(%rip)
269
270	movq	%rax, %rdi
271	call	make_boot_params
272	cmpq	$0,%rax
273	je	fail
274	mov	%rax, %rsi
275	leaq	startup_32(%rip), %rax
276	movl	%eax, BP_code32_start(%rsi)
277	jmp	2f		/* Skip the relocation */
278
279handover_entry:
280	call	1f
2811:	popq	%rbp
282	subq	$1b, %rbp
283
284	/*
285	 * Relocate efi_config->call().
286	 */
287	movq	efi_config(%rip), %rax
288	addq	%rbp, 32(%rax)
2892:
290	movq	efi_config(%rip), %rdi
291	call	efi_main
292	movq	%rax,%rsi
293	cmpq	$0,%rax
294	jne	2f
295fail:
296	/* EFI init failed, so hang. */
297	hlt
298	jmp	fail
2992:
300	movl	BP_code32_start(%esi), %eax
301	leaq	preferred_addr(%rax), %rax
302	jmp	*%rax
303
304preferred_addr:
305#endif
306
307	/* Setup data segments. */
308	xorl	%eax, %eax
309	movl	%eax, %ds
310	movl	%eax, %es
311	movl	%eax, %ss
312	movl	%eax, %fs
313	movl	%eax, %gs
314
315	/*
316	 * Compute the decompressed kernel start address.  It is where
317	 * we were loaded at aligned to a 2M boundary. %rbp contains the
318	 * decompressed kernel start address.
319	 *
320	 * If it is a relocatable kernel then decompress and run the kernel
321	 * from load address aligned to 2MB addr, otherwise decompress and
322	 * run the kernel from LOAD_PHYSICAL_ADDR
323	 *
324	 * We cannot rely on the calculation done in 32-bit mode, since we
325	 * may have been invoked via the 64-bit entry point.
326	 */
327
328	/* Start with the delta to where the kernel will run at. */
329#ifdef CONFIG_RELOCATABLE
330	leaq	startup_32(%rip) /* - $startup_32 */, %rbp
331	movl	BP_kernel_alignment(%rsi), %eax
332	decl	%eax
333	addq	%rax, %rbp
334	notq	%rax
335	andq	%rax, %rbp
336	cmpq	$LOAD_PHYSICAL_ADDR, %rbp
337	jge	1f
338#endif
339	movq	$LOAD_PHYSICAL_ADDR, %rbp
3401:
341
342	/* Target address to relocate to for decompression */
343	movl	BP_init_size(%rsi), %ebx
344	subl	$_end, %ebx
345	addq	%rbp, %rbx
346
347	/* Set up the stack */
348	leaq	boot_stack_end(%rbx), %rsp
349
350	/* Zero EFLAGS */
351	pushq	$0
352	popfq
353
354/*
355 * Copy the compressed kernel to the end of our buffer
356 * where decompression in place becomes safe.
357 */
358	pushq	%rsi
359	leaq	(_bss-8)(%rip), %rsi
360	leaq	(_bss-8)(%rbx), %rdi
361	movq	$_bss /* - $startup_32 */, %rcx
362	shrq	$3, %rcx
363	std
364	rep	movsq
365	cld
366	popq	%rsi
367
368/*
369 * Jump to the relocated address.
370 */
371	leaq	relocated(%rbx), %rax
372	jmp	*%rax
373
374#ifdef CONFIG_EFI_STUB
375	.org 0x390
376ENTRY(efi64_stub_entry)
377	movq	%rdi, efi64_config(%rip)	/* Handle */
378	movq	%rsi, efi64_config+8(%rip) /* EFI System table pointer */
379
380	leaq	efi64_config(%rip), %rax
381	movq	%rax, efi_config(%rip)
382
383	movq	%rdx, %rsi
384	jmp	handover_entry
385ENDPROC(efi64_stub_entry)
386#endif
387
388	.text
389relocated:
390
391/*
392 * Clear BSS (stack is currently empty)
393 */
394	xorl	%eax, %eax
395	leaq    _bss(%rip), %rdi
396	leaq    _ebss(%rip), %rcx
397	subq	%rdi, %rcx
398	shrq	$3, %rcx
399	rep	stosq
400
401/*
402 * Adjust our own GOT
403 */
404	leaq	_got(%rip), %rdx
405	leaq	_egot(%rip), %rcx
4061:
407	cmpq	%rcx, %rdx
408	jae	2f
409	addq	%rbx, (%rdx)
410	addq	$8, %rdx
411	jmp	1b
4122:
413
414/*
415 * Do the extraction, and jump to the new kernel..
416 */
417	pushq	%rsi			/* Save the real mode argument */
418	movq	%rsi, %rdi		/* real mode address */
419	leaq	boot_heap(%rip), %rsi	/* malloc area for uncompression */
420	leaq	input_data(%rip), %rdx  /* input_data */
421	movl	$z_input_len, %ecx	/* input_len */
422	movq	%rbp, %r8		/* output target address */
423	movq	$z_output_len, %r9	/* decompressed length, end of relocs */
424	call	extract_kernel		/* returns kernel location in %rax */
425	popq	%rsi
426
427/*
428 * Jump to the decompressed kernel.
429 */
430	jmp	*%rax
431
432	.code32
433no_longmode:
434	/* This isn't an x86-64 CPU so hang */
4351:
436	hlt
437	jmp     1b
438
439#include "../../kernel/verify_cpu.S"
440
441	.data
442gdt:
443	.word	gdt_end - gdt
444	.long	gdt
445	.word	0
446	.quad	0x0000000000000000	/* NULL descriptor */
447	.quad	0x00af9a000000ffff	/* __KERNEL_CS */
448	.quad	0x00cf92000000ffff	/* __KERNEL_DS */
449	.quad	0x0080890000000000	/* TS descriptor */
450	.quad   0x0000000000000000	/* TS continued */
451gdt_end:
452
453#ifdef CONFIG_EFI_STUB
454efi_config:
455	.quad	0
456
457#ifdef CONFIG_EFI_MIXED
458	.global efi32_config
459efi32_config:
460	.fill	4,8,0
461	.quad	efi64_thunk
462	.byte	0
463#endif
464
465	.global efi64_config
466efi64_config:
467	.fill	4,8,0
468	.quad	efi_call
469	.byte	1
470#endif /* CONFIG_EFI_STUB */
471
472/*
473 * Stack and heap for uncompression
474 */
475	.bss
476	.balign 4
477boot_heap:
478	.fill BOOT_HEAP_SIZE, 1, 0
479boot_stack:
480	.fill BOOT_STACK_SIZE, 1, 0
481boot_stack_end:
482
483/*
484 * Space for page tables (not in .bss so not zeroed)
485 */
486	.section ".pgtable","a",@nobits
487	.balign 4096
488pgtable:
489	.fill BOOT_PGT_SIZE, 1, 0
490