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