xref: /openbmc/linux/arch/x86/boot/compressed/head_32.S (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1b2441318SGreg Kroah-Hartman/* SPDX-License-Identifier: GPL-2.0 */
20530bf37SThomas Gleixner/*
30530bf37SThomas Gleixner *  linux/boot/head.S
40530bf37SThomas Gleixner *
50530bf37SThomas Gleixner *  Copyright (C) 1991, 1992, 1993  Linus Torvalds
60530bf37SThomas Gleixner */
70530bf37SThomas Gleixner
80530bf37SThomas Gleixner/*
90530bf37SThomas Gleixner *  head.S contains the 32-bit startup code.
100530bf37SThomas Gleixner *
110530bf37SThomas Gleixner * NOTE!!! Startup happens at absolute address 0x00001000, which is also where
120530bf37SThomas Gleixner * the page directory will exist. The startup code will be overwritten by
130530bf37SThomas Gleixner * the page directory. [According to comments etc elsewhere on a compressed
140530bf37SThomas Gleixner * kernel it will end up at 0x1000 + 1Mb I hope so as I assume this. - AC]
150530bf37SThomas Gleixner *
160530bf37SThomas Gleixner * Page 0 is deliberately kept safe, since System Management Mode code in
170530bf37SThomas Gleixner * laptops may need to access the BIOS data stored there.  This is also
180530bf37SThomas Gleixner * useful for future device drivers that either access the BIOS via VM86
190530bf37SThomas Gleixner * mode.
200530bf37SThomas Gleixner */
210530bf37SThomas Gleixner
220530bf37SThomas Gleixner/*
230530bf37SThomas Gleixner * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
240530bf37SThomas Gleixner */
250530bf37SThomas Gleixner	.text
260530bf37SThomas Gleixner
271dc818c1STim Abbott#include <linux/init.h>
280530bf37SThomas Gleixner#include <linux/linkage.h>
290530bf37SThomas Gleixner#include <asm/segment.h>
300341c14dSJeremy Fitzhardinge#include <asm/page_types.h>
310530bf37SThomas Gleixner#include <asm/boot.h>
32a24e7851SRusty Russell#include <asm/asm-offsets.h>
33fb148d83SAlexander Kuleshov#include <asm/bootparam.h>
340530bf37SThomas Gleixner
356d92bc9dSH.J. Lu/*
36a2c4fc4dSArvind Sankar * These symbols needed to be marked as .hidden to prevent the BFD linker from
37a2c4fc4dSArvind Sankar * generating R_386_32 (rather than R_386_RELATIVE) relocations for them when
38a2c4fc4dSArvind Sankar * the 32-bit compressed kernel is linked as PIE. This is no longer necessary,
39a2c4fc4dSArvind Sankar * but it doesn't hurt to keep them .hidden.
406d92bc9dSH.J. Lu */
416d92bc9dSH.J. Lu	.hidden _bss
426d92bc9dSH.J. Lu	.hidden _ebss
435214028dSArvind Sankar	.hidden _end
446d92bc9dSH.J. Lu
451dc818c1STim Abbott	__HEAD
466d685e53SJiri SlabySYM_FUNC_START(startup_32)
47bd53147dSEric W. Biederman	cld
48bd53147dSEric W. Biederman	cli
49a24e7851SRusty Russell
505f64ec64SH. Peter Anvin/*
515f64ec64SH. Peter Anvin * Calculate the delta between where we were compiled to run
520530bf37SThomas Gleixner * at and where we were actually loaded at.  This can only be done
530530bf37SThomas Gleixner * with a short local call on x86.  Nothing  else will tell us what
540530bf37SThomas Gleixner * address we are running at.  The reserved chunk of the real-mode
550530bf37SThomas Gleixner * data at 0x1e4 (defined as a scratch field) are used as the stack
560530bf37SThomas Gleixner * for this calculation. Only 4 bytes are needed.
570530bf37SThomas Gleixner */
58bd2a3698SH. Peter Anvin	leal	(BP_scratch+4)(%esi), %esp
590530bf37SThomas Gleixner	call	1f
608ef44be3SArvind Sankar1:	popl	%edx
61a2c4fc4dSArvind Sankar	addl	$_GLOBAL_OFFSET_TABLE_+(.-1b), %edx
620530bf37SThomas Gleixner
63ef5a7b5eSArvind Sankar	/* Load new GDT */
64a2c4fc4dSArvind Sankar	leal	gdt@GOTOFF(%edx), %eax
65ef5a7b5eSArvind Sankar	movl	%eax, 2(%eax)
66ef5a7b5eSArvind Sankar	lgdt	(%eax)
67ef5a7b5eSArvind Sankar
68ef5a7b5eSArvind Sankar	/* Load segment registers with our descriptors */
69ef5a7b5eSArvind Sankar	movl	$__BOOT_DS, %eax
70ef5a7b5eSArvind Sankar	movl	%eax, %ds
71ef5a7b5eSArvind Sankar	movl	%eax, %es
72ef5a7b5eSArvind Sankar	movl	%eax, %fs
73ef5a7b5eSArvind Sankar	movl	%eax, %gs
74ef5a7b5eSArvind Sankar	movl	%eax, %ss
75ef5a7b5eSArvind Sankar
765f64ec64SH. Peter Anvin/*
77a2c4fc4dSArvind Sankar * %edx contains the address we are loaded at by the boot loader (plus the
78a2c4fc4dSArvind Sankar * offset to the GOT).  The below code calculates %ebx to be the address where
79a2c4fc4dSArvind Sankar * we should move the kernel image temporarily for safe in-place decompression
80a2c4fc4dSArvind Sankar * (again, plus the offset to the GOT).
81a2c4fc4dSArvind Sankar *
82a2c4fc4dSArvind Sankar * %ebp is calculated to be the address that the kernel will be decompressed to.
830530bf37SThomas Gleixner */
840530bf37SThomas Gleixner
850530bf37SThomas Gleixner#ifdef CONFIG_RELOCATABLE
86a2c4fc4dSArvind Sankar	leal	startup_32@GOTOFF(%edx), %ebx
8737ba7ab5SH. Peter Anvin	movl	BP_kernel_alignment(%esi), %eax
8837ba7ab5SH. Peter Anvin	decl	%eax
8937ba7ab5SH. Peter Anvin	addl    %eax, %ebx
9037ba7ab5SH. Peter Anvin	notl	%eax
9137ba7ab5SH. Peter Anvin	andl    %eax, %ebx
928ab3820fSKees Cook	cmpl	$LOAD_PHYSICAL_ADDR, %ebx
9381a34892SArvind Sankar	jae	1f
940530bf37SThomas Gleixner#endif
958ab3820fSKees Cook	movl	$LOAD_PHYSICAL_ADDR, %ebx
968ab3820fSKees Cook1:
970530bf37SThomas Gleixner
988ef44be3SArvind Sankar	movl	%ebx, %ebp	// Save the output address for later
9902a884c0SH. Peter Anvin	/* Target address to relocate to for decompression */
1008ef44be3SArvind Sankar	addl    BP_init_size(%esi), %ebx
101a2c4fc4dSArvind Sankar	subl    $_end@GOTOFF, %ebx
1020530bf37SThomas Gleixner
1030a137736SH. Peter Anvin	/* Set up the stack */
104a2c4fc4dSArvind Sankar	leal	boot_stack_end@GOTOFF(%ebx), %esp
1050a137736SH. Peter Anvin
10697541912SH. Peter Anvin	/* Zero EFLAGS */
10797541912SH. Peter Anvin	pushl	$0
10897541912SH. Peter Anvin	popfl
10997541912SH. Peter Anvin
1105f64ec64SH. Peter Anvin/*
1115f64ec64SH. Peter Anvin * Copy the compressed kernel to the end of our buffer
1120530bf37SThomas Gleixner * where decompression in place becomes safe.
1130530bf37SThomas Gleixner */
1140530bf37SThomas Gleixner	pushl	%esi
115a2c4fc4dSArvind Sankar	leal	(_bss@GOTOFF-4)(%edx), %esi
116a2c4fc4dSArvind Sankar	leal	(_bss@GOTOFF-4)(%ebx), %edi
1175b11f1ceSH. Peter Anvin	movl	$(_bss - startup_32), %ecx
11836d3793cSH. Peter Anvin	shrl	$2, %ecx
1190530bf37SThomas Gleixner	std
12036d3793cSH. Peter Anvin	rep	movsl
1210530bf37SThomas Gleixner	cld
1220530bf37SThomas Gleixner	popl	%esi
1230530bf37SThomas Gleixner
1245f64ec64SH. Peter Anvin	/*
125ef5a7b5eSArvind Sankar	 * The GDT may get overwritten either during the copy we just did or
126ef5a7b5eSArvind Sankar	 * during extract_kernel below. To avoid any issues, repoint the GDTR
127c98a76eaSArvind Sankar	 * to the new copy of the GDT.
128ef5a7b5eSArvind Sankar	 */
129a2c4fc4dSArvind Sankar	leal	gdt@GOTOFF(%ebx), %eax
130c98a76eaSArvind Sankar	movl	%eax, 2(%eax)
131c98a76eaSArvind Sankar	lgdt	(%eax)
132ef5a7b5eSArvind Sankar
133ef5a7b5eSArvind Sankar/*
1340530bf37SThomas Gleixner * Jump to the relocated address.
1350530bf37SThomas Gleixner */
136a2c4fc4dSArvind Sankar	leal	.Lrelocated@GOTOFF(%ebx), %eax
1370530bf37SThomas Gleixner	jmp	*%eax
1386d685e53SJiri SlabySYM_FUNC_END(startup_32)
139cb425afdSCyrill Gorcunov
1405f64ec64SH. Peter Anvin	.text
141deff8a24SJiri SlabySYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
1420530bf37SThomas Gleixner
1430530bf37SThomas Gleixner/*
1440a137736SH. Peter Anvin * Clear BSS (stack is currently empty)
1450530bf37SThomas Gleixner */
1460530bf37SThomas Gleixner	xorl	%eax, %eax
147a2c4fc4dSArvind Sankar	leal	_bss@GOTOFF(%ebx), %edi
148a2c4fc4dSArvind Sankar	leal	_ebss@GOTOFF(%ebx), %ecx
1490530bf37SThomas Gleixner	subl	%edi, %ecx
15036d3793cSH. Peter Anvin	shrl	$2, %ecx
15136d3793cSH. Peter Anvin	rep	stosl
1520530bf37SThomas Gleixner
153f3670394SLinus Torvalds/*
154c0402881SKees Cook * Do the extraction, and jump to the new kernel..
1550530bf37SThomas Gleixner */
156c0402881SKees Cook	/* push arguments for extract_kernel: */
157974f221cSYinghai Lu
1588ef44be3SArvind Sankar	pushl	%ebp			/* output address */
1595f64ec64SH. Peter Anvin	pushl	%esi			/* real mode pointer */
160*7734a0f3SAlexander Lobakin	call	extract_kernel		/* returns kernel entry point in %eax */
1614d2d5424SYinghai Lu	addl	$24, %esp
1620530bf37SThomas Gleixner
1630530bf37SThomas Gleixner/*
164c0402881SKees Cook * Jump to the extracted kernel.
1650530bf37SThomas Gleixner */
1660530bf37SThomas Gleixner	xorl	%ebx, %ebx
1678ab3820fSKees Cook	jmp	*%eax
168deff8a24SJiri SlabySYM_FUNC_END(.Lrelocated)
1690530bf37SThomas Gleixner
170ef5a7b5eSArvind Sankar	.data
171ef5a7b5eSArvind Sankar	.balign	8
172ef5a7b5eSArvind SankarSYM_DATA_START_LOCAL(gdt)
173ef5a7b5eSArvind Sankar	.word	gdt_end - gdt - 1
174ef5a7b5eSArvind Sankar	.long	0
175ef5a7b5eSArvind Sankar	.word	0
176ef5a7b5eSArvind Sankar	.quad	0x0000000000000000	/* Reserved */
177ef5a7b5eSArvind Sankar	.quad	0x00cf9a000000ffff	/* __KERNEL_CS */
178ef5a7b5eSArvind Sankar	.quad	0x00cf92000000ffff	/* __KERNEL_DS */
179ef5a7b5eSArvind SankarSYM_DATA_END_LABEL(gdt, SYM_L_LOCAL, gdt_end)
180ef5a7b5eSArvind Sankar
1815f64ec64SH. Peter Anvin/*
1825f64ec64SH. Peter Anvin * Stack and heap for uncompression
1835f64ec64SH. Peter Anvin */
1840530bf37SThomas Gleixner	.bss
1850530bf37SThomas Gleixner	.balign 4
1867c539764SAlexander van Heukelumboot_stack:
1877c539764SAlexander van Heukelum	.fill BOOT_STACK_SIZE, 1, 0
1887c539764SAlexander van Heukelumboot_stack_end:
189