Commit | Line | Data |
---|---|---|
62607313 PA |
1 | /* -*- linux-c -*- ------------------------------------------------------- * |
2 | * | |
3 | * Copyright (C) 1991, 1992 Linus Torvalds | |
4 | * Copyright 2007 rPath, Inc. - All Rights Reserved | |
df7699c5 | 5 | * Copyright 2009 Intel Corporation; author H. Peter Anvin |
62607313 PA |
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 | /* | |
62607313 PA |
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 | */ | |
62607313 PA |
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 | /* | |
b2d0b7a0 JC |
60 | * Query the keyboard lock status as given by the BIOS, and |
61 | * set the keyboard repeat rate to maximum. Unclear why the latter | |
62607313 PA |
62 | * is done here; this might be possible to kill off as stale code. |
63 | */ | |
b2d0b7a0 | 64 | static void keyboard_init(void) |
62607313 | 65 | { |
b2d0b7a0 | 66 | struct biosregs ireg, oreg; |
df7699c5 | 67 | initregs(&ireg); |
b2d0b7a0 JC |
68 | |
69 | ireg.ah = 0x02; /* Get keyboard status */ | |
70 | intcall(0x16, &ireg, &oreg); | |
71 | boot_params.kbd_status = oreg.al; | |
72 | ||
73 | ireg.ax = 0x0305; /* Set keyboard repeat rate */ | |
df7699c5 | 74 | intcall(0x16, &ireg, NULL); |
62607313 PA |
75 | } |
76 | ||
77 | /* | |
238b706d | 78 | * Get Intel SpeedStep (IST) information. |
62607313 | 79 | */ |
238b706d | 80 | static void query_ist(void) |
62607313 | 81 | { |
df7699c5 PA |
82 | struct biosregs ireg, oreg; |
83 | ||
c2dcfde8 PA |
84 | /* Some older BIOSes apparently crash on this call, so filter |
85 | it from machines too old to have SpeedStep at all. */ | |
7b27718b JR |
86 | if (cpu.level < 6) |
87 | return; | |
88 | ||
df7699c5 PA |
89 | initregs(&ireg); |
90 | ireg.ax = 0xe980; /* IST Support */ | |
91 | ireg.edx = 0x47534943; /* Request value */ | |
92 | intcall(0x15, &ireg, &oreg); | |
93 | ||
94 | boot_params.ist_info.signature = oreg.eax; | |
95 | boot_params.ist_info.command = oreg.ebx; | |
96 | boot_params.ist_info.event = oreg.ecx; | |
97 | boot_params.ist_info.perf_level = oreg.edx; | |
62607313 PA |
98 | } |
99 | ||
100 | /* | |
101 | * Tell the BIOS what CPU mode we intend to run in. | |
102 | */ | |
103 | static void set_bios_mode(void) | |
104 | { | |
105 | #ifdef CONFIG_X86_64 | |
df7699c5 | 106 | struct biosregs ireg; |
62607313 | 107 | |
df7699c5 PA |
108 | initregs(&ireg); |
109 | ireg.ax = 0xec00; | |
110 | ireg.bx = 2; | |
111 | intcall(0x15, &ireg, NULL); | |
62607313 PA |
112 | #endif |
113 | } | |
114 | ||
acd644bb | 115 | static void init_heap(void) |
62607313 | 116 | { |
acd644bb | 117 | char *stack_end; |
62607313 | 118 | |
62607313 | 119 | if (boot_params.hdr.loadflags & CAN_USE_HEAP) { |
acd644bb PA |
120 | asm("leal %P1(%%esp),%0" |
121 | : "=r" (stack_end) : "i" (-STACK_SIZE)); | |
122 | ||
123 | heap_end = (char *) | |
124 | ((size_t)boot_params.hdr.heap_end_ptr + 0x200); | |
125 | if (heap_end > stack_end) | |
126 | heap_end = stack_end; | |
62607313 PA |
127 | } else { |
128 | /* Boot protocol 2.00 only, no heap available */ | |
129 | puts("WARNING: Ancient bootloader, some functionality " | |
130 | "may be limited!\n"); | |
131 | } | |
acd644bb PA |
132 | } |
133 | ||
134 | void main(void) | |
135 | { | |
136 | /* First, copy the boot header into the "zeropage" */ | |
137 | copy_boot_params(); | |
138 | ||
fa97bdf9 PE |
139 | /* Initialize the early-boot console */ |
140 | console_init(); | |
8fee13a4 YL |
141 | if (cmdline_find_option_bool("debug")) |
142 | puts("early console in setup code\n"); | |
fa97bdf9 | 143 | |
acd644bb PA |
144 | /* End of heap check */ |
145 | init_heap(); | |
62607313 PA |
146 | |
147 | /* Make sure we have all the proper CPU support */ | |
148 | if (validate_cpu()) { | |
149 | puts("Unable to boot - please use a kernel appropriate " | |
150 | "for your CPU.\n"); | |
151 | die(); | |
152 | } | |
153 | ||
154 | /* Tell the BIOS what CPU mode we intend to run in. */ | |
155 | set_bios_mode(); | |
156 | ||
157 | /* Detect memory layout */ | |
158 | detect_memory(); | |
159 | ||
b2d0b7a0 JC |
160 | /* Set keyboard repeat rate (why?) and query the lock flags */ |
161 | keyboard_init(); | |
62607313 | 162 | |
62607313 PA |
163 | /* Query MCA information */ |
164 | query_mca(); | |
165 | ||
238b706d PA |
166 | /* Query Intel SpeedStep (IST) information */ |
167 | query_ist(); | |
62607313 PA |
168 | |
169 | /* Query APM information */ | |
170 | #if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) | |
171 | query_apm_bios(); | |
172 | #endif | |
173 | ||
174 | /* Query EDD information */ | |
175 | #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE) | |
176 | query_edd(); | |
177 | #endif | |
1a8514e0 PA |
178 | |
179 | /* Set the video mode */ | |
180 | set_video(); | |
181 | ||
62607313 PA |
182 | /* Do the last things and invoke protected mode */ |
183 | go_to_protected_mode(); | |
184 | } |