| 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 |  | 
| Pekka Enberg | fa97bdf | 2010-07-11 11:06:57 +0300 | [diff] [blame] | 133 | 	/* Initialize the early-boot console */ | 
 | 134 | 	console_init(); | 
| Yinghai Lu | 8fee13a | 2010-08-02 16:21:22 -0700 | [diff] [blame] | 135 | 	if (cmdline_find_option_bool("debug")) | 
 | 136 | 		puts("early console in setup code\n"); | 
| Pekka Enberg | fa97bdf | 2010-07-11 11:06:57 +0300 | [diff] [blame] | 137 |  | 
| H. Peter Anvin | 6260731 | 2007-07-11 12:18:54 -0700 | [diff] [blame] | 138 | 	/* End of heap check */ | 
| H. Peter Anvin | acd644b | 2008-01-30 13:33:04 +0100 | [diff] [blame] | 139 | 	init_heap(); | 
| H. Peter Anvin | 6260731 | 2007-07-11 12:18:54 -0700 | [diff] [blame] | 140 |  | 
 | 141 | 	/* Make sure we have all the proper CPU support */ | 
 | 142 | 	if (validate_cpu()) { | 
 | 143 | 		puts("Unable to boot - please use a kernel appropriate " | 
 | 144 | 		     "for your CPU.\n"); | 
 | 145 | 		die(); | 
 | 146 | 	} | 
 | 147 |  | 
 | 148 | 	/* Tell the BIOS what CPU mode we intend to run in. */ | 
 | 149 | 	set_bios_mode(); | 
 | 150 |  | 
 | 151 | 	/* Detect memory layout */ | 
 | 152 | 	detect_memory(); | 
 | 153 |  | 
 | 154 | 	/* Set keyboard repeat rate (why?) */ | 
 | 155 | 	keyboard_set_repeat(); | 
 | 156 |  | 
| H. Peter Anvin | 6260731 | 2007-07-11 12:18:54 -0700 | [diff] [blame] | 157 | 	/* Query MCA information */ | 
 | 158 | 	query_mca(); | 
 | 159 |  | 
| H. Peter Anvin | 238b706 | 2007-07-18 17:19:30 -0700 | [diff] [blame] | 160 | 	/* Query Intel SpeedStep (IST) information */ | 
 | 161 | 	query_ist(); | 
| H. Peter Anvin | 6260731 | 2007-07-11 12:18:54 -0700 | [diff] [blame] | 162 |  | 
 | 163 | 	/* Query APM information */ | 
 | 164 | #if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) | 
 | 165 | 	query_apm_bios(); | 
 | 166 | #endif | 
 | 167 |  | 
 | 168 | 	/* Query EDD information */ | 
 | 169 | #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE) | 
 | 170 | 	query_edd(); | 
 | 171 | #endif | 
| H. Peter Anvin | 1a8514e | 2008-01-30 13:33:03 +0100 | [diff] [blame] | 172 |  | 
 | 173 | 	/* Set the video mode */ | 
 | 174 | 	set_video(); | 
 | 175 |  | 
| H. Peter Anvin | 6260731 | 2007-07-11 12:18:54 -0700 | [diff] [blame] | 176 | 	/* Do the last things and invoke protected mode */ | 
 | 177 | 	go_to_protected_mode(); | 
 | 178 | } |