^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /* -*- linux-c -*- ------------------------------------------------------- *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 1991, 1992 Linus Torvalds
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright 2007 rPath, Inc. - All Rights Reserved
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright 2009 Intel Corporation; author H. Peter Anvin
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * ----------------------------------------------------------------------- */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Main module for the real-mode kernel code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/build_bug.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include "boot.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include "string.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) struct boot_params boot_params __attribute__((aligned(16)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) char *HEAP = _end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) char *heap_end = _end; /* Default end of heap = no heap */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * Copy the header into the boot parameter block. Since this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * screws up the old-style command line protocol, adjust by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * filling in the new-style command line pointer instead.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) static void copy_boot_params(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) struct old_cmdline {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) u16 cl_magic;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) u16 cl_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) const struct old_cmdline * const oldcmd =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) (const struct old_cmdline *)OLD_CL_ADDRESS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) BUILD_BUG_ON(sizeof(boot_params) != 4096);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) memcpy(&boot_params.hdr, &hdr, sizeof(hdr));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) if (!boot_params.hdr.cmd_line_ptr &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) oldcmd->cl_magic == OLD_CL_MAGIC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) /* Old-style command line protocol. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) u16 cmdline_seg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) /* Figure out if the command line falls in the region
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) of memory that an old kernel would have copied up
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) to 0x90000... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) if (oldcmd->cl_offset < boot_params.hdr.setup_move_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) cmdline_seg = ds();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) cmdline_seg = 0x9000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) boot_params.hdr.cmd_line_ptr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) (cmdline_seg << 4) + oldcmd->cl_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * Query the keyboard lock status as given by the BIOS, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * set the keyboard repeat rate to maximum. Unclear why the latter
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * is done here; this might be possible to kill off as stale code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static void keyboard_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) struct biosregs ireg, oreg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) initregs(&ireg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) ireg.ah = 0x02; /* Get keyboard status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) intcall(0x16, &ireg, &oreg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) boot_params.kbd_status = oreg.al;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) ireg.ax = 0x0305; /* Set keyboard repeat rate */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) intcall(0x16, &ireg, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * Get Intel SpeedStep (IST) information.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) static void query_ist(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) struct biosregs ireg, oreg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) /* Some older BIOSes apparently crash on this call, so filter
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) it from machines too old to have SpeedStep at all. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (cpu.level < 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) initregs(&ireg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) ireg.ax = 0xe980; /* IST Support */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) ireg.edx = 0x47534943; /* Request value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) intcall(0x15, &ireg, &oreg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) boot_params.ist_info.signature = oreg.eax;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) boot_params.ist_info.command = oreg.ebx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) boot_params.ist_info.event = oreg.ecx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) boot_params.ist_info.perf_level = oreg.edx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) * Tell the BIOS what CPU mode we intend to run in.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) static void set_bios_mode(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) #ifdef CONFIG_X86_64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) struct biosregs ireg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) initregs(&ireg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) ireg.ax = 0xec00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) ireg.bx = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) intcall(0x15, &ireg, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) static void init_heap(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) char *stack_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) if (boot_params.hdr.loadflags & CAN_USE_HEAP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) asm("leal %P1(%%esp),%0"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) : "=r" (stack_end) : "i" (-STACK_SIZE));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) heap_end = (char *)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) ((size_t)boot_params.hdr.heap_end_ptr + 0x200);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) if (heap_end > stack_end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) heap_end = stack_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) /* Boot protocol 2.00 only, no heap available */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) puts("WARNING: Ancient bootloader, some functionality "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) "may be limited!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) void main(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) /* First, copy the boot header into the "zeropage" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) copy_boot_params();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) /* Initialize the early-boot console */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) console_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) if (cmdline_find_option_bool("debug"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) puts("early console in setup code\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) /* End of heap check */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) init_heap();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) /* Make sure we have all the proper CPU support */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) if (validate_cpu()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) puts("Unable to boot - please use a kernel appropriate "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) "for your CPU.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) die();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) /* Tell the BIOS what CPU mode we intend to run in. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) set_bios_mode();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) /* Detect memory layout */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) detect_memory();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) /* Set keyboard repeat rate (why?) and query the lock flags */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) keyboard_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) /* Query Intel SpeedStep (IST) information */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) query_ist();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) /* Query APM information */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) #if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) query_apm_bios();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) /* Query EDD information */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) query_edd();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) /* Set the video mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) set_video();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) /* Do the last things and invoke protected mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) go_to_protected_mode();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) }