18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/* -*- linux-c -*- ------------------------------------------------------- *
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci *   Copyright (C) 1991, 1992 Linus Torvalds
58c2ecf20Sopenharmony_ci *   Copyright 2007 rPath, Inc. - All Rights Reserved
68c2ecf20Sopenharmony_ci *   Copyright 2009 Intel Corporation; author H. Peter Anvin
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * ----------------------------------------------------------------------- */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci/*
118c2ecf20Sopenharmony_ci * Main module for the real-mode kernel code
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci#include <linux/build_bug.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include "boot.h"
168c2ecf20Sopenharmony_ci#include "string.h"
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistruct boot_params boot_params __attribute__((aligned(16)));
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cichar *HEAP = _end;
218c2ecf20Sopenharmony_cichar *heap_end = _end;		/* Default end of heap = no heap */
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/*
248c2ecf20Sopenharmony_ci * Copy the header into the boot parameter block.  Since this
258c2ecf20Sopenharmony_ci * screws up the old-style command line protocol, adjust by
268c2ecf20Sopenharmony_ci * filling in the new-style command line pointer instead.
278c2ecf20Sopenharmony_ci */
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic void copy_boot_params(void)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	struct old_cmdline {
328c2ecf20Sopenharmony_ci		u16 cl_magic;
338c2ecf20Sopenharmony_ci		u16 cl_offset;
348c2ecf20Sopenharmony_ci	};
358c2ecf20Sopenharmony_ci	const struct old_cmdline * const oldcmd =
368c2ecf20Sopenharmony_ci		absolute_pointer(OLD_CL_ADDRESS);
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(boot_params) != 4096);
398c2ecf20Sopenharmony_ci	memcpy(&boot_params.hdr, &hdr, sizeof(hdr));
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	if (!boot_params.hdr.cmd_line_ptr &&
428c2ecf20Sopenharmony_ci	    oldcmd->cl_magic == OLD_CL_MAGIC) {
438c2ecf20Sopenharmony_ci		/* Old-style command line protocol. */
448c2ecf20Sopenharmony_ci		u16 cmdline_seg;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci		/* Figure out if the command line falls in the region
478c2ecf20Sopenharmony_ci		   of memory that an old kernel would have copied up
488c2ecf20Sopenharmony_ci		   to 0x90000... */
498c2ecf20Sopenharmony_ci		if (oldcmd->cl_offset < boot_params.hdr.setup_move_size)
508c2ecf20Sopenharmony_ci			cmdline_seg = ds();
518c2ecf20Sopenharmony_ci		else
528c2ecf20Sopenharmony_ci			cmdline_seg = 0x9000;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci		boot_params.hdr.cmd_line_ptr =
558c2ecf20Sopenharmony_ci			(cmdline_seg << 4) + oldcmd->cl_offset;
568c2ecf20Sopenharmony_ci	}
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci/*
608c2ecf20Sopenharmony_ci * Query the keyboard lock status as given by the BIOS, and
618c2ecf20Sopenharmony_ci * set the keyboard repeat rate to maximum.  Unclear why the latter
628c2ecf20Sopenharmony_ci * is done here; this might be possible to kill off as stale code.
638c2ecf20Sopenharmony_ci */
648c2ecf20Sopenharmony_cistatic void keyboard_init(void)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	struct biosregs ireg, oreg;
678c2ecf20Sopenharmony_ci	initregs(&ireg);
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	ireg.ah = 0x02;		/* Get keyboard status */
708c2ecf20Sopenharmony_ci	intcall(0x16, &ireg, &oreg);
718c2ecf20Sopenharmony_ci	boot_params.kbd_status = oreg.al;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	ireg.ax = 0x0305;	/* Set keyboard repeat rate */
748c2ecf20Sopenharmony_ci	intcall(0x16, &ireg, NULL);
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci/*
788c2ecf20Sopenharmony_ci * Get Intel SpeedStep (IST) information.
798c2ecf20Sopenharmony_ci */
808c2ecf20Sopenharmony_cistatic void query_ist(void)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	struct biosregs ireg, oreg;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	/* Some older BIOSes apparently crash on this call, so filter
858c2ecf20Sopenharmony_ci	   it from machines too old to have SpeedStep at all. */
868c2ecf20Sopenharmony_ci	if (cpu.level < 6)
878c2ecf20Sopenharmony_ci		return;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	initregs(&ireg);
908c2ecf20Sopenharmony_ci	ireg.ax  = 0xe980;	 /* IST Support */
918c2ecf20Sopenharmony_ci	ireg.edx = 0x47534943;	 /* Request value */
928c2ecf20Sopenharmony_ci	intcall(0x15, &ireg, &oreg);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	boot_params.ist_info.signature  = oreg.eax;
958c2ecf20Sopenharmony_ci	boot_params.ist_info.command    = oreg.ebx;
968c2ecf20Sopenharmony_ci	boot_params.ist_info.event      = oreg.ecx;
978c2ecf20Sopenharmony_ci	boot_params.ist_info.perf_level = oreg.edx;
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci/*
1018c2ecf20Sopenharmony_ci * Tell the BIOS what CPU mode we intend to run in.
1028c2ecf20Sopenharmony_ci */
1038c2ecf20Sopenharmony_cistatic void set_bios_mode(void)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64
1068c2ecf20Sopenharmony_ci	struct biosregs ireg;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	initregs(&ireg);
1098c2ecf20Sopenharmony_ci	ireg.ax = 0xec00;
1108c2ecf20Sopenharmony_ci	ireg.bx = 2;
1118c2ecf20Sopenharmony_ci	intcall(0x15, &ireg, NULL);
1128c2ecf20Sopenharmony_ci#endif
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic void init_heap(void)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	char *stack_end;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	if (boot_params.hdr.loadflags & CAN_USE_HEAP) {
1208c2ecf20Sopenharmony_ci		asm("leal %P1(%%esp),%0"
1218c2ecf20Sopenharmony_ci		    : "=r" (stack_end) : "i" (-STACK_SIZE));
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci		heap_end = (char *)
1248c2ecf20Sopenharmony_ci			((size_t)boot_params.hdr.heap_end_ptr + 0x200);
1258c2ecf20Sopenharmony_ci		if (heap_end > stack_end)
1268c2ecf20Sopenharmony_ci			heap_end = stack_end;
1278c2ecf20Sopenharmony_ci	} else {
1288c2ecf20Sopenharmony_ci		/* Boot protocol 2.00 only, no heap available */
1298c2ecf20Sopenharmony_ci		puts("WARNING: Ancient bootloader, some functionality "
1308c2ecf20Sopenharmony_ci		     "may be limited!\n");
1318c2ecf20Sopenharmony_ci	}
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_civoid main(void)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	/* First, copy the boot header into the "zeropage" */
1378c2ecf20Sopenharmony_ci	copy_boot_params();
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	/* Initialize the early-boot console */
1408c2ecf20Sopenharmony_ci	console_init();
1418c2ecf20Sopenharmony_ci	if (cmdline_find_option_bool("debug"))
1428c2ecf20Sopenharmony_ci		puts("early console in setup code\n");
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	/* End of heap check */
1458c2ecf20Sopenharmony_ci	init_heap();
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	/* Make sure we have all the proper CPU support */
1488c2ecf20Sopenharmony_ci	if (validate_cpu()) {
1498c2ecf20Sopenharmony_ci		puts("Unable to boot - please use a kernel appropriate "
1508c2ecf20Sopenharmony_ci		     "for your CPU.\n");
1518c2ecf20Sopenharmony_ci		die();
1528c2ecf20Sopenharmony_ci	}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	/* Tell the BIOS what CPU mode we intend to run in. */
1558c2ecf20Sopenharmony_ci	set_bios_mode();
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	/* Detect memory layout */
1588c2ecf20Sopenharmony_ci	detect_memory();
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	/* Set keyboard repeat rate (why?) and query the lock flags */
1618c2ecf20Sopenharmony_ci	keyboard_init();
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	/* Query Intel SpeedStep (IST) information */
1648c2ecf20Sopenharmony_ci	query_ist();
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	/* Query APM information */
1678c2ecf20Sopenharmony_ci#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
1688c2ecf20Sopenharmony_ci	query_apm_bios();
1698c2ecf20Sopenharmony_ci#endif
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	/* Query EDD information */
1728c2ecf20Sopenharmony_ci#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
1738c2ecf20Sopenharmony_ci	query_edd();
1748c2ecf20Sopenharmony_ci#endif
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	/* Set the video mode */
1778c2ecf20Sopenharmony_ci	set_video();
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	/* Do the last things and invoke protected mode */
1808c2ecf20Sopenharmony_ci	go_to_protected_mode();
1818c2ecf20Sopenharmony_ci}
182