162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* -*- linux-c -*- ------------------------------------------------------- * 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 1991, 1992 Linus Torvalds 562306a36Sopenharmony_ci * Copyright 2007 rPath, Inc. - All Rights Reserved 662306a36Sopenharmony_ci * Copyright 2009 Intel Corporation; author H. Peter Anvin 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * ----------------------------------------------------------------------- */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/* 1162306a36Sopenharmony_ci * Main module for the real-mode kernel code 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci#include <linux/build_bug.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "boot.h" 1662306a36Sopenharmony_ci#include "string.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistruct boot_params boot_params __attribute__((aligned(16))); 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistruct port_io_ops pio_ops; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cichar *HEAP = _end; 2362306a36Sopenharmony_cichar *heap_end = _end; /* Default end of heap = no heap */ 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* 2662306a36Sopenharmony_ci * Copy the header into the boot parameter block. Since this 2762306a36Sopenharmony_ci * screws up the old-style command line protocol, adjust by 2862306a36Sopenharmony_ci * filling in the new-style command line pointer instead. 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic void copy_boot_params(void) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci struct old_cmdline { 3462306a36Sopenharmony_ci u16 cl_magic; 3562306a36Sopenharmony_ci u16 cl_offset; 3662306a36Sopenharmony_ci }; 3762306a36Sopenharmony_ci const struct old_cmdline * const oldcmd = 3862306a36Sopenharmony_ci absolute_pointer(OLD_CL_ADDRESS); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(boot_params) != 4096); 4162306a36Sopenharmony_ci memcpy(&boot_params.hdr, &hdr, sizeof(hdr)); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci if (!boot_params.hdr.cmd_line_ptr && 4462306a36Sopenharmony_ci oldcmd->cl_magic == OLD_CL_MAGIC) { 4562306a36Sopenharmony_ci /* Old-style command line protocol. */ 4662306a36Sopenharmony_ci u16 cmdline_seg; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci /* Figure out if the command line falls in the region 4962306a36Sopenharmony_ci of memory that an old kernel would have copied up 5062306a36Sopenharmony_ci to 0x90000... */ 5162306a36Sopenharmony_ci if (oldcmd->cl_offset < boot_params.hdr.setup_move_size) 5262306a36Sopenharmony_ci cmdline_seg = ds(); 5362306a36Sopenharmony_ci else 5462306a36Sopenharmony_ci cmdline_seg = 0x9000; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci boot_params.hdr.cmd_line_ptr = 5762306a36Sopenharmony_ci (cmdline_seg << 4) + oldcmd->cl_offset; 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* 6262306a36Sopenharmony_ci * Query the keyboard lock status as given by the BIOS, and 6362306a36Sopenharmony_ci * set the keyboard repeat rate to maximum. Unclear why the latter 6462306a36Sopenharmony_ci * is done here; this might be possible to kill off as stale code. 6562306a36Sopenharmony_ci */ 6662306a36Sopenharmony_cistatic void keyboard_init(void) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci struct biosregs ireg, oreg; 6962306a36Sopenharmony_ci initregs(&ireg); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci ireg.ah = 0x02; /* Get keyboard status */ 7262306a36Sopenharmony_ci intcall(0x16, &ireg, &oreg); 7362306a36Sopenharmony_ci boot_params.kbd_status = oreg.al; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci ireg.ax = 0x0305; /* Set keyboard repeat rate */ 7662306a36Sopenharmony_ci intcall(0x16, &ireg, NULL); 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci/* 8062306a36Sopenharmony_ci * Get Intel SpeedStep (IST) information. 8162306a36Sopenharmony_ci */ 8262306a36Sopenharmony_cistatic void query_ist(void) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci struct biosregs ireg, oreg; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci /* Some older BIOSes apparently crash on this call, so filter 8762306a36Sopenharmony_ci it from machines too old to have SpeedStep at all. */ 8862306a36Sopenharmony_ci if (cpu.level < 6) 8962306a36Sopenharmony_ci return; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci initregs(&ireg); 9262306a36Sopenharmony_ci ireg.ax = 0xe980; /* IST Support */ 9362306a36Sopenharmony_ci ireg.edx = 0x47534943; /* Request value */ 9462306a36Sopenharmony_ci intcall(0x15, &ireg, &oreg); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci boot_params.ist_info.signature = oreg.eax; 9762306a36Sopenharmony_ci boot_params.ist_info.command = oreg.ebx; 9862306a36Sopenharmony_ci boot_params.ist_info.event = oreg.ecx; 9962306a36Sopenharmony_ci boot_params.ist_info.perf_level = oreg.edx; 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci/* 10362306a36Sopenharmony_ci * Tell the BIOS what CPU mode we intend to run in. 10462306a36Sopenharmony_ci */ 10562306a36Sopenharmony_cistatic void set_bios_mode(void) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci#ifdef CONFIG_X86_64 10862306a36Sopenharmony_ci struct biosregs ireg; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci initregs(&ireg); 11162306a36Sopenharmony_ci ireg.ax = 0xec00; 11262306a36Sopenharmony_ci ireg.bx = 2; 11362306a36Sopenharmony_ci intcall(0x15, &ireg, NULL); 11462306a36Sopenharmony_ci#endif 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic void init_heap(void) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci char *stack_end; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci if (boot_params.hdr.loadflags & CAN_USE_HEAP) { 12262306a36Sopenharmony_ci asm("leal %P1(%%esp),%0" 12362306a36Sopenharmony_ci : "=r" (stack_end) : "i" (-STACK_SIZE)); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci heap_end = (char *) 12662306a36Sopenharmony_ci ((size_t)boot_params.hdr.heap_end_ptr + 0x200); 12762306a36Sopenharmony_ci if (heap_end > stack_end) 12862306a36Sopenharmony_ci heap_end = stack_end; 12962306a36Sopenharmony_ci } else { 13062306a36Sopenharmony_ci /* Boot protocol 2.00 only, no heap available */ 13162306a36Sopenharmony_ci puts("WARNING: Ancient bootloader, some functionality " 13262306a36Sopenharmony_ci "may be limited!\n"); 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_civoid main(void) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci init_default_io_ops(); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci /* First, copy the boot header into the "zeropage" */ 14162306a36Sopenharmony_ci copy_boot_params(); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci /* Initialize the early-boot console */ 14462306a36Sopenharmony_ci console_init(); 14562306a36Sopenharmony_ci if (cmdline_find_option_bool("debug")) 14662306a36Sopenharmony_ci puts("early console in setup code\n"); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci /* End of heap check */ 14962306a36Sopenharmony_ci init_heap(); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* Make sure we have all the proper CPU support */ 15262306a36Sopenharmony_ci if (validate_cpu()) { 15362306a36Sopenharmony_ci puts("Unable to boot - please use a kernel appropriate " 15462306a36Sopenharmony_ci "for your CPU.\n"); 15562306a36Sopenharmony_ci die(); 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci /* Tell the BIOS what CPU mode we intend to run in. */ 15962306a36Sopenharmony_ci set_bios_mode(); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci /* Detect memory layout */ 16262306a36Sopenharmony_ci detect_memory(); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* Set keyboard repeat rate (why?) and query the lock flags */ 16562306a36Sopenharmony_ci keyboard_init(); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci /* Query Intel SpeedStep (IST) information */ 16862306a36Sopenharmony_ci query_ist(); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci /* Query APM information */ 17162306a36Sopenharmony_ci#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) 17262306a36Sopenharmony_ci query_apm_bios(); 17362306a36Sopenharmony_ci#endif 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci /* Query EDD information */ 17662306a36Sopenharmony_ci#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE) 17762306a36Sopenharmony_ci query_edd(); 17862306a36Sopenharmony_ci#endif 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci /* Set the video mode */ 18162306a36Sopenharmony_ci set_video(); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci /* Do the last things and invoke protected mode */ 18462306a36Sopenharmony_ci go_to_protected_mode(); 18562306a36Sopenharmony_ci} 186