| 
									
										
										
										
											2007-07-11 12:18:54 -07:00
										 |  |  | /* -*- linux-c -*- ------------------------------------------------------- *
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *   Copyright (C) 1991, 1992 Linus Torvalds | 
					
						
							|  |  |  |  *   Copyright 2007 rPath, Inc. - All Rights Reserved | 
					
						
							| 
									
										
										
										
											2009-04-01 18:13:46 -07:00
										 |  |  |  *   Copyright 2009 Intel Corporation; author H. Peter Anvin | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:54 -07:00
										 |  |  |  * | 
					
						
							|  |  |  |  *   This file is part of the Linux kernel, and is made available under | 
					
						
							|  |  |  |  *   the terms of the GNU General Public License version 2. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * ----------------------------------------------------------------------- */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Main module for the real-mode kernel code | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "boot.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct boot_params boot_params __attribute__((aligned(16))); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | char *HEAP = _end; | 
					
						
							|  |  |  | char *heap_end = _end;		/* Default end of heap = no heap */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Copy the header into the boot parameter block.  Since this | 
					
						
							|  |  |  |  * screws up the old-style command line protocol, adjust by | 
					
						
							|  |  |  |  * filling in the new-style command line pointer instead. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void copy_boot_params(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct old_cmdline { | 
					
						
							|  |  |  | 		u16 cl_magic; | 
					
						
							|  |  |  | 		u16 cl_offset; | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 	const struct old_cmdline * const oldcmd = | 
					
						
							|  |  |  | 		(const struct old_cmdline *)OLD_CL_ADDRESS; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	BUILD_BUG_ON(sizeof boot_params != 4096); | 
					
						
							|  |  |  | 	memcpy(&boot_params.hdr, &hdr, sizeof hdr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!boot_params.hdr.cmd_line_ptr && | 
					
						
							|  |  |  | 	    oldcmd->cl_magic == OLD_CL_MAGIC) { | 
					
						
							|  |  |  | 		/* Old-style command line protocol. */ | 
					
						
							|  |  |  | 		u16 cmdline_seg; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* Figure out if the command line falls in the region
 | 
					
						
							|  |  |  | 		   of memory that an old kernel would have copied up | 
					
						
							|  |  |  | 		   to 0x90000... */ | 
					
						
							|  |  |  | 		if (oldcmd->cl_offset < boot_params.hdr.setup_move_size) | 
					
						
							|  |  |  | 			cmdline_seg = ds(); | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			cmdline_seg = 0x9000; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		boot_params.hdr.cmd_line_ptr = | 
					
						
							|  |  |  | 			(cmdline_seg << 4) + oldcmd->cl_offset; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2012-04-13 21:08:26 +02:00
										 |  |  |  * Query the keyboard lock status as given by the BIOS, and | 
					
						
							|  |  |  |  * set the keyboard repeat rate to maximum.  Unclear why the latter | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:54 -07:00
										 |  |  |  * is done here; this might be possible to kill off as stale code. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2012-04-13 21:08:26 +02:00
										 |  |  | static void keyboard_init(void) | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:54 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-04-13 21:08:26 +02:00
										 |  |  | 	struct biosregs ireg, oreg; | 
					
						
							| 
									
										
										
										
											2009-04-01 18:13:46 -07:00
										 |  |  | 	initregs(&ireg); | 
					
						
							| 
									
										
										
										
											2012-04-13 21:08:26 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	ireg.ah = 0x02;		/* Get keyboard status */ | 
					
						
							|  |  |  | 	intcall(0x16, &ireg, &oreg); | 
					
						
							|  |  |  | 	boot_params.kbd_status = oreg.al; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ireg.ax = 0x0305;	/* Set keyboard repeat rate */ | 
					
						
							| 
									
										
										
										
											2009-04-01 18:13:46 -07:00
										 |  |  | 	intcall(0x16, &ireg, NULL); | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:54 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2007-07-18 17:19:30 -07:00
										 |  |  |  * Get Intel SpeedStep (IST) information. | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:54 -07:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2007-07-18 17:19:30 -07:00
										 |  |  | static void query_ist(void) | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:54 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-04-01 18:13:46 -07:00
										 |  |  | 	struct biosregs ireg, oreg; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-13 13:14:22 -07:00
										 |  |  | 	/* Some older BIOSes apparently crash on this call, so filter
 | 
					
						
							|  |  |  | 	   it from machines too old to have SpeedStep at all. */ | 
					
						
							| 
									
										
										
										
											2008-08-13 10:07:05 +02:00
										 |  |  | 	if (cpu.level < 6) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-01 18:13:46 -07:00
										 |  |  | 	initregs(&ireg); | 
					
						
							|  |  |  | 	ireg.ax  = 0xe980;	 /* IST Support */ | 
					
						
							|  |  |  | 	ireg.edx = 0x47534943;	 /* Request value */ | 
					
						
							|  |  |  | 	intcall(0x15, &ireg, &oreg); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	boot_params.ist_info.signature  = oreg.eax; | 
					
						
							|  |  |  | 	boot_params.ist_info.command    = oreg.ebx; | 
					
						
							|  |  |  | 	boot_params.ist_info.event      = oreg.ecx; | 
					
						
							|  |  |  | 	boot_params.ist_info.perf_level = oreg.edx; | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:54 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Tell the BIOS what CPU mode we intend to run in. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void set_bios_mode(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #ifdef CONFIG_X86_64
 | 
					
						
							| 
									
										
										
										
											2009-04-01 18:13:46 -07:00
										 |  |  | 	struct biosregs ireg; | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:54 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-01 18:13:46 -07:00
										 |  |  | 	initregs(&ireg); | 
					
						
							|  |  |  | 	ireg.ax = 0xec00; | 
					
						
							|  |  |  | 	ireg.bx = 2; | 
					
						
							|  |  |  | 	intcall(0x15, &ireg, NULL); | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:54 -07:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-01-30 13:33:04 +01:00
										 |  |  | static void init_heap(void) | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:54 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-01-30 13:33:04 +01:00
										 |  |  | 	char *stack_end; | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:54 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (boot_params.hdr.loadflags & CAN_USE_HEAP) { | 
					
						
							| 
									
										
										
										
											2008-01-30 13:33:04 +01:00
										 |  |  | 		asm("leal %P1(%%esp),%0" | 
					
						
							|  |  |  | 		    : "=r" (stack_end) : "i" (-STACK_SIZE)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		heap_end = (char *) | 
					
						
							|  |  |  | 			((size_t)boot_params.hdr.heap_end_ptr + 0x200); | 
					
						
							|  |  |  | 		if (heap_end > stack_end) | 
					
						
							|  |  |  | 			heap_end = stack_end; | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:54 -07:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		/* Boot protocol 2.00 only, no heap available */ | 
					
						
							|  |  |  | 		puts("WARNING: Ancient bootloader, some functionality " | 
					
						
							|  |  |  | 		     "may be limited!\n"); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-01-30 13:33:04 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void main(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* First, copy the boot header into the "zeropage" */ | 
					
						
							|  |  |  | 	copy_boot_params(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-11 11:06:57 +03:00
										 |  |  | 	/* Initialize the early-boot console */ | 
					
						
							|  |  |  | 	console_init(); | 
					
						
							| 
									
										
										
										
											2010-08-02 16:21:22 -07:00
										 |  |  | 	if (cmdline_find_option_bool("debug")) | 
					
						
							|  |  |  | 		puts("early console in setup code\n"); | 
					
						
							| 
									
										
										
										
											2010-07-11 11:06:57 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-01-30 13:33:04 +01:00
										 |  |  | 	/* End of heap check */ | 
					
						
							|  |  |  | 	init_heap(); | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:54 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Make sure we have all the proper CPU support */ | 
					
						
							|  |  |  | 	if (validate_cpu()) { | 
					
						
							|  |  |  | 		puts("Unable to boot - please use a kernel appropriate " | 
					
						
							|  |  |  | 		     "for your CPU.\n"); | 
					
						
							|  |  |  | 		die(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Tell the BIOS what CPU mode we intend to run in. */ | 
					
						
							|  |  |  | 	set_bios_mode(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Detect memory layout */ | 
					
						
							|  |  |  | 	detect_memory(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-13 21:08:26 +02:00
										 |  |  | 	/* Set keyboard repeat rate (why?) and query the lock flags */ | 
					
						
							|  |  |  | 	keyboard_init(); | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:54 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Query MCA information */ | 
					
						
							|  |  |  | 	query_mca(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-18 17:19:30 -07:00
										 |  |  | 	/* Query Intel SpeedStep (IST) information */ | 
					
						
							|  |  |  | 	query_ist(); | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:54 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Query APM information */ | 
					
						
							|  |  |  | #if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
 | 
					
						
							|  |  |  | 	query_apm_bios(); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Query EDD information */ | 
					
						
							|  |  |  | #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
 | 
					
						
							|  |  |  | 	query_edd(); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2008-01-30 13:33:03 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Set the video mode */ | 
					
						
							|  |  |  | 	set_video(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:54 -07:00
										 |  |  | 	/* Do the last things and invoke protected mode */ | 
					
						
							|  |  |  | 	go_to_protected_mode(); | 
					
						
							|  |  |  | } |