18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * misc.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * This is a collection of several routines used to extract the kernel
68c2ecf20Sopenharmony_ci * which includes KASLR relocation, decompression, ELF parsing, and
78c2ecf20Sopenharmony_ci * relocation processing. Additionally included are the screen and serial
88c2ecf20Sopenharmony_ci * output functions and related debugging support functions.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
118c2ecf20Sopenharmony_ci * puts by Nick Holloway 1993, better puts by Martin Mares 1995
128c2ecf20Sopenharmony_ci * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
138c2ecf20Sopenharmony_ci */
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include "misc.h"
168c2ecf20Sopenharmony_ci#include "error.h"
178c2ecf20Sopenharmony_ci#include "pgtable.h"
188c2ecf20Sopenharmony_ci#include "../string.h"
198c2ecf20Sopenharmony_ci#include "../voffset.h"
208c2ecf20Sopenharmony_ci#include <asm/bootparam_utils.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci/*
238c2ecf20Sopenharmony_ci * WARNING!!
248c2ecf20Sopenharmony_ci * This code is compiled with -fPIC and it is relocated dynamically at
258c2ecf20Sopenharmony_ci * run time, but no relocation processing is performed. This means that
268c2ecf20Sopenharmony_ci * it is not safe to place pointers in static structures.
278c2ecf20Sopenharmony_ci */
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci/* Macros used by the included decompressor code below. */
308c2ecf20Sopenharmony_ci#define STATIC		static
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci/*
338c2ecf20Sopenharmony_ci * Provide definitions of memzero and memmove as some of the decompressors will
348c2ecf20Sopenharmony_ci * try to define their own functions if these are not defined as macros.
358c2ecf20Sopenharmony_ci */
368c2ecf20Sopenharmony_ci#define memzero(s, n)	memset((s), 0, (n))
378c2ecf20Sopenharmony_ci#define memmove		memmove
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci/* Functions used by the included decompressor code below. */
408c2ecf20Sopenharmony_civoid *memmove(void *dest, const void *src, size_t n);
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci/*
438c2ecf20Sopenharmony_ci * This is set up by the setup-routine at boot-time
448c2ecf20Sopenharmony_ci */
458c2ecf20Sopenharmony_cistruct boot_params *boot_params;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cimemptr free_mem_ptr;
488c2ecf20Sopenharmony_cimemptr free_mem_end_ptr;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic char *vidmem;
518c2ecf20Sopenharmony_cistatic int vidport;
528c2ecf20Sopenharmony_cistatic int lines, cols;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci#ifdef CONFIG_KERNEL_GZIP
558c2ecf20Sopenharmony_ci#include "../../../../lib/decompress_inflate.c"
568c2ecf20Sopenharmony_ci#endif
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci#ifdef CONFIG_KERNEL_BZIP2
598c2ecf20Sopenharmony_ci#include "../../../../lib/decompress_bunzip2.c"
608c2ecf20Sopenharmony_ci#endif
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci#ifdef CONFIG_KERNEL_LZMA
638c2ecf20Sopenharmony_ci#include "../../../../lib/decompress_unlzma.c"
648c2ecf20Sopenharmony_ci#endif
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci#ifdef CONFIG_KERNEL_XZ
678c2ecf20Sopenharmony_ci#include "../../../../lib/decompress_unxz.c"
688c2ecf20Sopenharmony_ci#endif
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci#ifdef CONFIG_KERNEL_LZO
718c2ecf20Sopenharmony_ci#include "../../../../lib/decompress_unlzo.c"
728c2ecf20Sopenharmony_ci#endif
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci#ifdef CONFIG_KERNEL_LZ4
758c2ecf20Sopenharmony_ci#include "../../../../lib/decompress_unlz4.c"
768c2ecf20Sopenharmony_ci#endif
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci#ifdef CONFIG_KERNEL_ZSTD
798c2ecf20Sopenharmony_ci#include "../../../../lib/decompress_unzstd.c"
808c2ecf20Sopenharmony_ci#endif
818c2ecf20Sopenharmony_ci/*
828c2ecf20Sopenharmony_ci * NOTE: When adding a new decompressor, please update the analysis in
838c2ecf20Sopenharmony_ci * ../header.S.
848c2ecf20Sopenharmony_ci */
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic void scroll(void)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	int i;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	memmove(vidmem, vidmem + cols * 2, (lines - 1) * cols * 2);
918c2ecf20Sopenharmony_ci	for (i = (lines - 1) * cols * 2; i < lines * cols * 2; i += 2)
928c2ecf20Sopenharmony_ci		vidmem[i] = ' ';
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci#define XMTRDY          0x20
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci#define TXR             0       /*  Transmit register (WRITE) */
988c2ecf20Sopenharmony_ci#define LSR             5       /*  Line Status               */
998c2ecf20Sopenharmony_cistatic void serial_putchar(int ch)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	unsigned timeout = 0xffff;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout)
1048c2ecf20Sopenharmony_ci		cpu_relax();
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	outb(ch, early_serial_base + TXR);
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_civoid __putstr(const char *s)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	int x, y, pos;
1128c2ecf20Sopenharmony_ci	char c;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	if (early_serial_base) {
1158c2ecf20Sopenharmony_ci		const char *str = s;
1168c2ecf20Sopenharmony_ci		while (*str) {
1178c2ecf20Sopenharmony_ci			if (*str == '\n')
1188c2ecf20Sopenharmony_ci				serial_putchar('\r');
1198c2ecf20Sopenharmony_ci			serial_putchar(*str++);
1208c2ecf20Sopenharmony_ci		}
1218c2ecf20Sopenharmony_ci	}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	if (lines == 0 || cols == 0)
1248c2ecf20Sopenharmony_ci		return;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	x = boot_params->screen_info.orig_x;
1278c2ecf20Sopenharmony_ci	y = boot_params->screen_info.orig_y;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	while ((c = *s++) != '\0') {
1308c2ecf20Sopenharmony_ci		if (c == '\n') {
1318c2ecf20Sopenharmony_ci			x = 0;
1328c2ecf20Sopenharmony_ci			if (++y >= lines) {
1338c2ecf20Sopenharmony_ci				scroll();
1348c2ecf20Sopenharmony_ci				y--;
1358c2ecf20Sopenharmony_ci			}
1368c2ecf20Sopenharmony_ci		} else {
1378c2ecf20Sopenharmony_ci			vidmem[(x + cols * y) * 2] = c;
1388c2ecf20Sopenharmony_ci			if (++x >= cols) {
1398c2ecf20Sopenharmony_ci				x = 0;
1408c2ecf20Sopenharmony_ci				if (++y >= lines) {
1418c2ecf20Sopenharmony_ci					scroll();
1428c2ecf20Sopenharmony_ci					y--;
1438c2ecf20Sopenharmony_ci				}
1448c2ecf20Sopenharmony_ci			}
1458c2ecf20Sopenharmony_ci		}
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	boot_params->screen_info.orig_x = x;
1498c2ecf20Sopenharmony_ci	boot_params->screen_info.orig_y = y;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	pos = (x + cols * y) * 2;	/* Update cursor position */
1528c2ecf20Sopenharmony_ci	outb(14, vidport);
1538c2ecf20Sopenharmony_ci	outb(0xff & (pos >> 9), vidport+1);
1548c2ecf20Sopenharmony_ci	outb(15, vidport);
1558c2ecf20Sopenharmony_ci	outb(0xff & (pos >> 1), vidport+1);
1568c2ecf20Sopenharmony_ci}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_civoid __puthex(unsigned long value)
1598c2ecf20Sopenharmony_ci{
1608c2ecf20Sopenharmony_ci	char alpha[2] = "0";
1618c2ecf20Sopenharmony_ci	int bits;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	for (bits = sizeof(value) * 8 - 4; bits >= 0; bits -= 4) {
1648c2ecf20Sopenharmony_ci		unsigned long digit = (value >> bits) & 0xf;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci		if (digit < 0xA)
1678c2ecf20Sopenharmony_ci			alpha[0] = '0' + digit;
1688c2ecf20Sopenharmony_ci		else
1698c2ecf20Sopenharmony_ci			alpha[0] = 'a' + (digit - 0xA);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci		__putstr(alpha);
1728c2ecf20Sopenharmony_ci	}
1738c2ecf20Sopenharmony_ci}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci#if CONFIG_X86_NEED_RELOCS
1768c2ecf20Sopenharmony_cistatic void handle_relocations(void *output, unsigned long output_len,
1778c2ecf20Sopenharmony_ci			       unsigned long virt_addr)
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	int *reloc;
1808c2ecf20Sopenharmony_ci	unsigned long delta, map, ptr;
1818c2ecf20Sopenharmony_ci	unsigned long min_addr = (unsigned long)output;
1828c2ecf20Sopenharmony_ci	unsigned long max_addr = min_addr + (VO___bss_start - VO__text);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	/*
1858c2ecf20Sopenharmony_ci	 * Calculate the delta between where vmlinux was linked to load
1868c2ecf20Sopenharmony_ci	 * and where it was actually loaded.
1878c2ecf20Sopenharmony_ci	 */
1888c2ecf20Sopenharmony_ci	delta = min_addr - LOAD_PHYSICAL_ADDR;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	/*
1918c2ecf20Sopenharmony_ci	 * The kernel contains a table of relocation addresses. Those
1928c2ecf20Sopenharmony_ci	 * addresses have the final load address of the kernel in virtual
1938c2ecf20Sopenharmony_ci	 * memory. We are currently working in the self map. So we need to
1948c2ecf20Sopenharmony_ci	 * create an adjustment for kernel memory addresses to the self map.
1958c2ecf20Sopenharmony_ci	 * This will involve subtracting out the base address of the kernel.
1968c2ecf20Sopenharmony_ci	 */
1978c2ecf20Sopenharmony_ci	map = delta - __START_KERNEL_map;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	/*
2008c2ecf20Sopenharmony_ci	 * 32-bit always performs relocations. 64-bit relocations are only
2018c2ecf20Sopenharmony_ci	 * needed if KASLR has chosen a different starting address offset
2028c2ecf20Sopenharmony_ci	 * from __START_KERNEL_map.
2038c2ecf20Sopenharmony_ci	 */
2048c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_X86_64))
2058c2ecf20Sopenharmony_ci		delta = virt_addr - LOAD_PHYSICAL_ADDR;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	if (!delta) {
2088c2ecf20Sopenharmony_ci		debug_putstr("No relocation needed... ");
2098c2ecf20Sopenharmony_ci		return;
2108c2ecf20Sopenharmony_ci	}
2118c2ecf20Sopenharmony_ci	debug_putstr("Performing relocations... ");
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	/*
2148c2ecf20Sopenharmony_ci	 * Process relocations: 32 bit relocations first then 64 bit after.
2158c2ecf20Sopenharmony_ci	 * Three sets of binary relocations are added to the end of the kernel
2168c2ecf20Sopenharmony_ci	 * before compression. Each relocation table entry is the kernel
2178c2ecf20Sopenharmony_ci	 * address of the location which needs to be updated stored as a
2188c2ecf20Sopenharmony_ci	 * 32-bit value which is sign extended to 64 bits.
2198c2ecf20Sopenharmony_ci	 *
2208c2ecf20Sopenharmony_ci	 * Format is:
2218c2ecf20Sopenharmony_ci	 *
2228c2ecf20Sopenharmony_ci	 * kernel bits...
2238c2ecf20Sopenharmony_ci	 * 0 - zero terminator for 64 bit relocations
2248c2ecf20Sopenharmony_ci	 * 64 bit relocation repeated
2258c2ecf20Sopenharmony_ci	 * 0 - zero terminator for inverse 32 bit relocations
2268c2ecf20Sopenharmony_ci	 * 32 bit inverse relocation repeated
2278c2ecf20Sopenharmony_ci	 * 0 - zero terminator for 32 bit relocations
2288c2ecf20Sopenharmony_ci	 * 32 bit relocation repeated
2298c2ecf20Sopenharmony_ci	 *
2308c2ecf20Sopenharmony_ci	 * So we work backwards from the end of the decompressed image.
2318c2ecf20Sopenharmony_ci	 */
2328c2ecf20Sopenharmony_ci	for (reloc = output + output_len - sizeof(*reloc); *reloc; reloc--) {
2338c2ecf20Sopenharmony_ci		long extended = *reloc;
2348c2ecf20Sopenharmony_ci		extended += map;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci		ptr = (unsigned long)extended;
2378c2ecf20Sopenharmony_ci		if (ptr < min_addr || ptr > max_addr)
2388c2ecf20Sopenharmony_ci			error("32-bit relocation outside of kernel!\n");
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci		*(uint32_t *)ptr += delta;
2418c2ecf20Sopenharmony_ci	}
2428c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64
2438c2ecf20Sopenharmony_ci	while (*--reloc) {
2448c2ecf20Sopenharmony_ci		long extended = *reloc;
2458c2ecf20Sopenharmony_ci		extended += map;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci		ptr = (unsigned long)extended;
2488c2ecf20Sopenharmony_ci		if (ptr < min_addr || ptr > max_addr)
2498c2ecf20Sopenharmony_ci			error("inverse 32-bit relocation outside of kernel!\n");
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci		*(int32_t *)ptr -= delta;
2528c2ecf20Sopenharmony_ci	}
2538c2ecf20Sopenharmony_ci	for (reloc--; *reloc; reloc--) {
2548c2ecf20Sopenharmony_ci		long extended = *reloc;
2558c2ecf20Sopenharmony_ci		extended += map;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci		ptr = (unsigned long)extended;
2588c2ecf20Sopenharmony_ci		if (ptr < min_addr || ptr > max_addr)
2598c2ecf20Sopenharmony_ci			error("64-bit relocation outside of kernel!\n");
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci		*(uint64_t *)ptr += delta;
2628c2ecf20Sopenharmony_ci	}
2638c2ecf20Sopenharmony_ci#endif
2648c2ecf20Sopenharmony_ci}
2658c2ecf20Sopenharmony_ci#else
2668c2ecf20Sopenharmony_cistatic inline void handle_relocations(void *output, unsigned long output_len,
2678c2ecf20Sopenharmony_ci				      unsigned long virt_addr)
2688c2ecf20Sopenharmony_ci{ }
2698c2ecf20Sopenharmony_ci#endif
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_cistatic void parse_elf(void *output)
2728c2ecf20Sopenharmony_ci{
2738c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64
2748c2ecf20Sopenharmony_ci	Elf64_Ehdr ehdr;
2758c2ecf20Sopenharmony_ci	Elf64_Phdr *phdrs, *phdr;
2768c2ecf20Sopenharmony_ci#else
2778c2ecf20Sopenharmony_ci	Elf32_Ehdr ehdr;
2788c2ecf20Sopenharmony_ci	Elf32_Phdr *phdrs, *phdr;
2798c2ecf20Sopenharmony_ci#endif
2808c2ecf20Sopenharmony_ci	void *dest;
2818c2ecf20Sopenharmony_ci	int i;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	memcpy(&ehdr, output, sizeof(ehdr));
2848c2ecf20Sopenharmony_ci	if (ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
2858c2ecf20Sopenharmony_ci	   ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
2868c2ecf20Sopenharmony_ci	   ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
2878c2ecf20Sopenharmony_ci	   ehdr.e_ident[EI_MAG3] != ELFMAG3) {
2888c2ecf20Sopenharmony_ci		error("Kernel is not a valid ELF file");
2898c2ecf20Sopenharmony_ci		return;
2908c2ecf20Sopenharmony_ci	}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	debug_putstr("Parsing ELF... ");
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	phdrs = malloc(sizeof(*phdrs) * ehdr.e_phnum);
2958c2ecf20Sopenharmony_ci	if (!phdrs)
2968c2ecf20Sopenharmony_ci		error("Failed to allocate space for phdrs");
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	memcpy(phdrs, output + ehdr.e_phoff, sizeof(*phdrs) * ehdr.e_phnum);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	for (i = 0; i < ehdr.e_phnum; i++) {
3018c2ecf20Sopenharmony_ci		phdr = &phdrs[i];
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci		switch (phdr->p_type) {
3048c2ecf20Sopenharmony_ci		case PT_LOAD:
3058c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64
3068c2ecf20Sopenharmony_ci			if ((phdr->p_align % 0x200000) != 0)
3078c2ecf20Sopenharmony_ci				error("Alignment of LOAD segment isn't multiple of 2MB");
3088c2ecf20Sopenharmony_ci#endif
3098c2ecf20Sopenharmony_ci#ifdef CONFIG_RELOCATABLE
3108c2ecf20Sopenharmony_ci			dest = output;
3118c2ecf20Sopenharmony_ci			dest += (phdr->p_paddr - LOAD_PHYSICAL_ADDR);
3128c2ecf20Sopenharmony_ci#else
3138c2ecf20Sopenharmony_ci			dest = (void *)(phdr->p_paddr);
3148c2ecf20Sopenharmony_ci#endif
3158c2ecf20Sopenharmony_ci			memmove(dest, output + phdr->p_offset, phdr->p_filesz);
3168c2ecf20Sopenharmony_ci			break;
3178c2ecf20Sopenharmony_ci		default: /* Ignore other PT_* */ break;
3188c2ecf20Sopenharmony_ci		}
3198c2ecf20Sopenharmony_ci	}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	free(phdrs);
3228c2ecf20Sopenharmony_ci}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci/*
3258c2ecf20Sopenharmony_ci * The compressed kernel image (ZO), has been moved so that its position
3268c2ecf20Sopenharmony_ci * is against the end of the buffer used to hold the uncompressed kernel
3278c2ecf20Sopenharmony_ci * image (VO) and the execution environment (.bss, .brk), which makes sure
3288c2ecf20Sopenharmony_ci * there is room to do the in-place decompression. (See header.S for the
3298c2ecf20Sopenharmony_ci * calculations.)
3308c2ecf20Sopenharmony_ci *
3318c2ecf20Sopenharmony_ci *                             |-----compressed kernel image------|
3328c2ecf20Sopenharmony_ci *                             V                                  V
3338c2ecf20Sopenharmony_ci * 0                       extract_offset                      +INIT_SIZE
3348c2ecf20Sopenharmony_ci * |-----------|---------------|-------------------------|--------|
3358c2ecf20Sopenharmony_ci *             |               |                         |        |
3368c2ecf20Sopenharmony_ci *           VO__text      startup_32 of ZO          VO__end    ZO__end
3378c2ecf20Sopenharmony_ci *             ^                                         ^
3388c2ecf20Sopenharmony_ci *             |-------uncompressed kernel image---------|
3398c2ecf20Sopenharmony_ci *
3408c2ecf20Sopenharmony_ci */
3418c2ecf20Sopenharmony_ciasmlinkage __visible void *extract_kernel(void *rmode, memptr heap,
3428c2ecf20Sopenharmony_ci				  unsigned char *input_data,
3438c2ecf20Sopenharmony_ci				  unsigned long input_len,
3448c2ecf20Sopenharmony_ci				  unsigned char *output,
3458c2ecf20Sopenharmony_ci				  unsigned long output_len)
3468c2ecf20Sopenharmony_ci{
3478c2ecf20Sopenharmony_ci	const unsigned long kernel_total_size = VO__end - VO__text;
3488c2ecf20Sopenharmony_ci	unsigned long virt_addr = LOAD_PHYSICAL_ADDR;
3498c2ecf20Sopenharmony_ci	unsigned long needed_size;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	/* Retain x86 boot parameters pointer passed from startup_32/64. */
3528c2ecf20Sopenharmony_ci	boot_params = rmode;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	/* Clear flags intended for solely in-kernel use. */
3558c2ecf20Sopenharmony_ci	boot_params->hdr.loadflags &= ~KASLR_FLAG;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	sanitize_boot_params(boot_params);
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	if (boot_params->screen_info.orig_video_mode == 7) {
3608c2ecf20Sopenharmony_ci		vidmem = (char *) 0xb0000;
3618c2ecf20Sopenharmony_ci		vidport = 0x3b4;
3628c2ecf20Sopenharmony_ci	} else {
3638c2ecf20Sopenharmony_ci		vidmem = (char *) 0xb8000;
3648c2ecf20Sopenharmony_ci		vidport = 0x3d4;
3658c2ecf20Sopenharmony_ci	}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	lines = boot_params->screen_info.orig_video_lines;
3688c2ecf20Sopenharmony_ci	cols = boot_params->screen_info.orig_video_cols;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	console_init();
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	/*
3738c2ecf20Sopenharmony_ci	 * Save RSDP address for later use. Have this after console_init()
3748c2ecf20Sopenharmony_ci	 * so that early debugging output from the RSDP parsing code can be
3758c2ecf20Sopenharmony_ci	 * collected.
3768c2ecf20Sopenharmony_ci	 */
3778c2ecf20Sopenharmony_ci	boot_params->acpi_rsdp_addr = get_rsdp_addr();
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	debug_putstr("early console in extract_kernel\n");
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	free_mem_ptr     = heap;	/* Heap */
3828c2ecf20Sopenharmony_ci	free_mem_end_ptr = heap + BOOT_HEAP_SIZE;
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	/*
3858c2ecf20Sopenharmony_ci	 * The memory hole needed for the kernel is the larger of either
3868c2ecf20Sopenharmony_ci	 * the entire decompressed kernel plus relocation table, or the
3878c2ecf20Sopenharmony_ci	 * entire decompressed kernel plus .bss and .brk sections.
3888c2ecf20Sopenharmony_ci	 *
3898c2ecf20Sopenharmony_ci	 * On X86_64, the memory is mapped with PMD pages. Round the
3908c2ecf20Sopenharmony_ci	 * size up so that the full extent of PMD pages mapped is
3918c2ecf20Sopenharmony_ci	 * included in the check against the valid memory table
3928c2ecf20Sopenharmony_ci	 * entries. This ensures the full mapped area is usable RAM
3938c2ecf20Sopenharmony_ci	 * and doesn't include any reserved areas.
3948c2ecf20Sopenharmony_ci	 */
3958c2ecf20Sopenharmony_ci	needed_size = max(output_len, kernel_total_size);
3968c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64
3978c2ecf20Sopenharmony_ci	needed_size = ALIGN(needed_size, MIN_KERNEL_ALIGN);
3988c2ecf20Sopenharmony_ci#endif
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	/* Report initial kernel position details. */
4018c2ecf20Sopenharmony_ci	debug_putaddr(input_data);
4028c2ecf20Sopenharmony_ci	debug_putaddr(input_len);
4038c2ecf20Sopenharmony_ci	debug_putaddr(output);
4048c2ecf20Sopenharmony_ci	debug_putaddr(output_len);
4058c2ecf20Sopenharmony_ci	debug_putaddr(kernel_total_size);
4068c2ecf20Sopenharmony_ci	debug_putaddr(needed_size);
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64
4098c2ecf20Sopenharmony_ci	/* Report address of 32-bit trampoline */
4108c2ecf20Sopenharmony_ci	debug_putaddr(trampoline_32bit);
4118c2ecf20Sopenharmony_ci#endif
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	choose_random_location((unsigned long)input_data, input_len,
4148c2ecf20Sopenharmony_ci				(unsigned long *)&output,
4158c2ecf20Sopenharmony_ci				needed_size,
4168c2ecf20Sopenharmony_ci				&virt_addr);
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	/* Validate memory location choices. */
4198c2ecf20Sopenharmony_ci	if ((unsigned long)output & (MIN_KERNEL_ALIGN - 1))
4208c2ecf20Sopenharmony_ci		error("Destination physical address inappropriately aligned");
4218c2ecf20Sopenharmony_ci	if (virt_addr & (MIN_KERNEL_ALIGN - 1))
4228c2ecf20Sopenharmony_ci		error("Destination virtual address inappropriately aligned");
4238c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64
4248c2ecf20Sopenharmony_ci	if (heap > 0x3fffffffffffUL)
4258c2ecf20Sopenharmony_ci		error("Destination address too large");
4268c2ecf20Sopenharmony_ci	if (virt_addr + max(output_len, kernel_total_size) > KERNEL_IMAGE_SIZE)
4278c2ecf20Sopenharmony_ci		error("Destination virtual address is beyond the kernel mapping area");
4288c2ecf20Sopenharmony_ci#else
4298c2ecf20Sopenharmony_ci	if (heap > ((-__PAGE_OFFSET-(128<<20)-1) & 0x7fffffff))
4308c2ecf20Sopenharmony_ci		error("Destination address too large");
4318c2ecf20Sopenharmony_ci#endif
4328c2ecf20Sopenharmony_ci#ifndef CONFIG_RELOCATABLE
4338c2ecf20Sopenharmony_ci	if ((unsigned long)output != LOAD_PHYSICAL_ADDR)
4348c2ecf20Sopenharmony_ci		error("Destination address does not match LOAD_PHYSICAL_ADDR");
4358c2ecf20Sopenharmony_ci	if (virt_addr != LOAD_PHYSICAL_ADDR)
4368c2ecf20Sopenharmony_ci		error("Destination virtual address changed when not relocatable");
4378c2ecf20Sopenharmony_ci#endif
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	debug_putstr("\nDecompressing Linux... ");
4408c2ecf20Sopenharmony_ci	__decompress(input_data, input_len, NULL, NULL, output, output_len,
4418c2ecf20Sopenharmony_ci			NULL, error);
4428c2ecf20Sopenharmony_ci	parse_elf(output);
4438c2ecf20Sopenharmony_ci	handle_relocations(output, output_len, virt_addr);
4448c2ecf20Sopenharmony_ci	debug_putstr("done.\nBooting the kernel.\n");
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	/*
4478c2ecf20Sopenharmony_ci	 * Flush GHCB from cache and map it encrypted again when running as
4488c2ecf20Sopenharmony_ci	 * SEV-ES guest.
4498c2ecf20Sopenharmony_ci	 */
4508c2ecf20Sopenharmony_ci	sev_es_shutdown_ghcb();
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	return output;
4538c2ecf20Sopenharmony_ci}
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_civoid fortify_panic(const char *name)
4568c2ecf20Sopenharmony_ci{
4578c2ecf20Sopenharmony_ci	error("detected buffer overflow");
4588c2ecf20Sopenharmony_ci}
459