xref: /openbmc/linux/arch/x86/boot/main.c (revision 96ae6ea0be1b902c28b3b463c27da42b41e2b63a)
1*96ae6ea0SThomas Gleixner /* -*- linux-c -*- ------------------------------------------------------- *
2*96ae6ea0SThomas Gleixner  *
3*96ae6ea0SThomas Gleixner  *   Copyright (C) 1991, 1992 Linus Torvalds
4*96ae6ea0SThomas Gleixner  *   Copyright 2007 rPath, Inc. - All Rights Reserved
5*96ae6ea0SThomas Gleixner  *
6*96ae6ea0SThomas Gleixner  *   This file is part of the Linux kernel, and is made available under
7*96ae6ea0SThomas Gleixner  *   the terms of the GNU General Public License version 2.
8*96ae6ea0SThomas Gleixner  *
9*96ae6ea0SThomas Gleixner  * ----------------------------------------------------------------------- */
10*96ae6ea0SThomas Gleixner 
11*96ae6ea0SThomas Gleixner /*
12*96ae6ea0SThomas Gleixner  * arch/i386/boot/main.c
13*96ae6ea0SThomas Gleixner  *
14*96ae6ea0SThomas Gleixner  * Main module for the real-mode kernel code
15*96ae6ea0SThomas Gleixner  */
16*96ae6ea0SThomas Gleixner 
17*96ae6ea0SThomas Gleixner #include "boot.h"
18*96ae6ea0SThomas Gleixner 
19*96ae6ea0SThomas Gleixner struct boot_params boot_params __attribute__((aligned(16)));
20*96ae6ea0SThomas Gleixner 
21*96ae6ea0SThomas Gleixner char *HEAP = _end;
22*96ae6ea0SThomas Gleixner char *heap_end = _end;		/* Default end of heap = no heap */
23*96ae6ea0SThomas Gleixner 
24*96ae6ea0SThomas Gleixner /*
25*96ae6ea0SThomas Gleixner  * Copy the header into the boot parameter block.  Since this
26*96ae6ea0SThomas Gleixner  * screws up the old-style command line protocol, adjust by
27*96ae6ea0SThomas Gleixner  * filling in the new-style command line pointer instead.
28*96ae6ea0SThomas Gleixner  */
29*96ae6ea0SThomas Gleixner #define OLD_CL_MAGIC	0xA33F
30*96ae6ea0SThomas Gleixner #define OLD_CL_ADDRESS	0x20
31*96ae6ea0SThomas Gleixner 
32*96ae6ea0SThomas Gleixner static void copy_boot_params(void)
33*96ae6ea0SThomas Gleixner {
34*96ae6ea0SThomas Gleixner 	struct old_cmdline {
35*96ae6ea0SThomas Gleixner 		u16 cl_magic;
36*96ae6ea0SThomas Gleixner 		u16 cl_offset;
37*96ae6ea0SThomas Gleixner 	};
38*96ae6ea0SThomas Gleixner 	const struct old_cmdline * const oldcmd =
39*96ae6ea0SThomas Gleixner 		(const struct old_cmdline *)OLD_CL_ADDRESS;
40*96ae6ea0SThomas Gleixner 
41*96ae6ea0SThomas Gleixner 	BUILD_BUG_ON(sizeof boot_params != 4096);
42*96ae6ea0SThomas Gleixner 	memcpy(&boot_params.hdr, &hdr, sizeof hdr);
43*96ae6ea0SThomas Gleixner 
44*96ae6ea0SThomas Gleixner 	if (!boot_params.hdr.cmd_line_ptr &&
45*96ae6ea0SThomas Gleixner 	    oldcmd->cl_magic == OLD_CL_MAGIC) {
46*96ae6ea0SThomas Gleixner 		/* Old-style command line protocol. */
47*96ae6ea0SThomas Gleixner 		u16 cmdline_seg;
48*96ae6ea0SThomas Gleixner 
49*96ae6ea0SThomas Gleixner 		/* Figure out if the command line falls in the region
50*96ae6ea0SThomas Gleixner 		   of memory that an old kernel would have copied up
51*96ae6ea0SThomas Gleixner 		   to 0x90000... */
52*96ae6ea0SThomas Gleixner 		if (oldcmd->cl_offset < boot_params.hdr.setup_move_size)
53*96ae6ea0SThomas Gleixner 			cmdline_seg = ds();
54*96ae6ea0SThomas Gleixner 		else
55*96ae6ea0SThomas Gleixner 			cmdline_seg = 0x9000;
56*96ae6ea0SThomas Gleixner 
57*96ae6ea0SThomas Gleixner 		boot_params.hdr.cmd_line_ptr =
58*96ae6ea0SThomas Gleixner 			(cmdline_seg << 4) + oldcmd->cl_offset;
59*96ae6ea0SThomas Gleixner 	}
60*96ae6ea0SThomas Gleixner }
61*96ae6ea0SThomas Gleixner 
62*96ae6ea0SThomas Gleixner /*
63*96ae6ea0SThomas Gleixner  * Set the keyboard repeat rate to maximum.  Unclear why this
64*96ae6ea0SThomas Gleixner  * is done here; this might be possible to kill off as stale code.
65*96ae6ea0SThomas Gleixner  */
66*96ae6ea0SThomas Gleixner static void keyboard_set_repeat(void)
67*96ae6ea0SThomas Gleixner {
68*96ae6ea0SThomas Gleixner 	u16 ax = 0x0305;
69*96ae6ea0SThomas Gleixner 	u16 bx = 0;
70*96ae6ea0SThomas Gleixner 	asm volatile("int $0x16"
71*96ae6ea0SThomas Gleixner 		     : "+a" (ax), "+b" (bx)
72*96ae6ea0SThomas Gleixner 		     : : "ecx", "edx", "esi", "edi");
73*96ae6ea0SThomas Gleixner }
74*96ae6ea0SThomas Gleixner 
75*96ae6ea0SThomas Gleixner /*
76*96ae6ea0SThomas Gleixner  * Get Intel SpeedStep (IST) information.
77*96ae6ea0SThomas Gleixner  */
78*96ae6ea0SThomas Gleixner static void query_ist(void)
79*96ae6ea0SThomas Gleixner {
80*96ae6ea0SThomas Gleixner 	asm("int $0x15"
81*96ae6ea0SThomas Gleixner 	    : "=a" (boot_params.ist_info.signature),
82*96ae6ea0SThomas Gleixner 	      "=b" (boot_params.ist_info.command),
83*96ae6ea0SThomas Gleixner 	      "=c" (boot_params.ist_info.event),
84*96ae6ea0SThomas Gleixner 	      "=d" (boot_params.ist_info.perf_level)
85*96ae6ea0SThomas Gleixner 	    : "a" (0x0000e980),	 /* IST Support */
86*96ae6ea0SThomas Gleixner 	      "d" (0x47534943)); /* Request value */
87*96ae6ea0SThomas Gleixner }
88*96ae6ea0SThomas Gleixner 
89*96ae6ea0SThomas Gleixner /*
90*96ae6ea0SThomas Gleixner  * Tell the BIOS what CPU mode we intend to run in.
91*96ae6ea0SThomas Gleixner  */
92*96ae6ea0SThomas Gleixner static void set_bios_mode(void)
93*96ae6ea0SThomas Gleixner {
94*96ae6ea0SThomas Gleixner #ifdef CONFIG_X86_64
95*96ae6ea0SThomas Gleixner 	u32 eax, ebx;
96*96ae6ea0SThomas Gleixner 
97*96ae6ea0SThomas Gleixner 	eax = 0xec00;
98*96ae6ea0SThomas Gleixner 	ebx = 2;
99*96ae6ea0SThomas Gleixner 	asm volatile("int $0x15"
100*96ae6ea0SThomas Gleixner 		     : "+a" (eax), "+b" (ebx)
101*96ae6ea0SThomas Gleixner 		     : : "ecx", "edx", "esi", "edi");
102*96ae6ea0SThomas Gleixner #endif
103*96ae6ea0SThomas Gleixner }
104*96ae6ea0SThomas Gleixner 
105*96ae6ea0SThomas Gleixner void main(void)
106*96ae6ea0SThomas Gleixner {
107*96ae6ea0SThomas Gleixner 	/* First, copy the boot header into the "zeropage" */
108*96ae6ea0SThomas Gleixner 	copy_boot_params();
109*96ae6ea0SThomas Gleixner 
110*96ae6ea0SThomas Gleixner 	/* End of heap check */
111*96ae6ea0SThomas Gleixner 	if (boot_params.hdr.loadflags & CAN_USE_HEAP) {
112*96ae6ea0SThomas Gleixner 		heap_end = (char *)(boot_params.hdr.heap_end_ptr
113*96ae6ea0SThomas Gleixner 				    +0x200-STACK_SIZE);
114*96ae6ea0SThomas Gleixner 	} else {
115*96ae6ea0SThomas Gleixner 		/* Boot protocol 2.00 only, no heap available */
116*96ae6ea0SThomas Gleixner 		puts("WARNING: Ancient bootloader, some functionality "
117*96ae6ea0SThomas Gleixner 		     "may be limited!\n");
118*96ae6ea0SThomas Gleixner 	}
119*96ae6ea0SThomas Gleixner 
120*96ae6ea0SThomas Gleixner 	/* Make sure we have all the proper CPU support */
121*96ae6ea0SThomas Gleixner 	if (validate_cpu()) {
122*96ae6ea0SThomas Gleixner 		puts("Unable to boot - please use a kernel appropriate "
123*96ae6ea0SThomas Gleixner 		     "for your CPU.\n");
124*96ae6ea0SThomas Gleixner 		die();
125*96ae6ea0SThomas Gleixner 	}
126*96ae6ea0SThomas Gleixner 
127*96ae6ea0SThomas Gleixner 	/* Tell the BIOS what CPU mode we intend to run in. */
128*96ae6ea0SThomas Gleixner 	set_bios_mode();
129*96ae6ea0SThomas Gleixner 
130*96ae6ea0SThomas Gleixner 	/* Detect memory layout */
131*96ae6ea0SThomas Gleixner 	detect_memory();
132*96ae6ea0SThomas Gleixner 
133*96ae6ea0SThomas Gleixner 	/* Set keyboard repeat rate (why?) */
134*96ae6ea0SThomas Gleixner 	keyboard_set_repeat();
135*96ae6ea0SThomas Gleixner 
136*96ae6ea0SThomas Gleixner 	/* Set the video mode */
137*96ae6ea0SThomas Gleixner 	set_video();
138*96ae6ea0SThomas Gleixner 
139*96ae6ea0SThomas Gleixner 	/* Query MCA information */
140*96ae6ea0SThomas Gleixner 	query_mca();
141*96ae6ea0SThomas Gleixner 
142*96ae6ea0SThomas Gleixner 	/* Voyager */
143*96ae6ea0SThomas Gleixner #ifdef CONFIG_X86_VOYAGER
144*96ae6ea0SThomas Gleixner 	query_voyager();
145*96ae6ea0SThomas Gleixner #endif
146*96ae6ea0SThomas Gleixner 
147*96ae6ea0SThomas Gleixner 	/* Query Intel SpeedStep (IST) information */
148*96ae6ea0SThomas Gleixner 	query_ist();
149*96ae6ea0SThomas Gleixner 
150*96ae6ea0SThomas Gleixner 	/* Query APM information */
151*96ae6ea0SThomas Gleixner #if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
152*96ae6ea0SThomas Gleixner 	query_apm_bios();
153*96ae6ea0SThomas Gleixner #endif
154*96ae6ea0SThomas Gleixner 
155*96ae6ea0SThomas Gleixner 	/* Query EDD information */
156*96ae6ea0SThomas Gleixner #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
157*96ae6ea0SThomas Gleixner 	query_edd();
158*96ae6ea0SThomas Gleixner #endif
159*96ae6ea0SThomas Gleixner 	/* Do the last things and invoke protected mode */
160*96ae6ea0SThomas Gleixner 	go_to_protected_mode();
161*96ae6ea0SThomas Gleixner }
162