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