author | William Kucharski <William.Kucharski@Sun.COM> |
Fri, 07 Nov 2008 21:36:41 -0700 | |
changeset 8044 | b3af80bbf173 |
parent 7300 | usr/src/grub/grub-0.95/stage2/common.c@3f0c3af330d3 |
child 8352 | af83fb61a268 |
permissions | -rw-r--r-- |
0 | 1 |
/* common.c - miscellaneous shared variables and routines */ |
2 |
/* |
|
3 |
* GRUB -- GRand Unified Bootloader |
|
4 |
* Copyright (C) 1999,2000,2001,2002,2004 Free Software Foundation, Inc. |
|
5 |
* |
|
6 |
* This program is free software; you can redistribute it and/or modify |
|
7 |
* it under the terms of the GNU General Public License as published by |
|
8 |
* the Free Software Foundation; either version 2 of the License, or |
|
9 |
* (at your option) any later version. |
|
10 |
* |
|
11 |
* This program is distributed in the hope that it will be useful, |
|
12 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
14 |
* GNU General Public License for more details. |
|
15 |
* |
|
16 |
* You should have received a copy of the GNU General Public License |
|
17 |
* along with this program; if not, write to the Free Software |
|
18 |
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
|
19 |
*/ |
|
20 |
||
21 |
#include <shared.h> |
|
22 |
||
23 |
#ifdef SUPPORT_NETBOOT |
|
24 |
#include <grub.h> |
|
25 |
#include <bootp.h> |
|
26 |
#endif |
|
27 |
||
28 |
/* |
|
29 |
* Shared BIOS/boot data. |
|
30 |
*/ |
|
31 |
||
32 |
struct multiboot_info mbi; |
|
33 |
unsigned long saved_drive; |
|
34 |
unsigned long saved_partition; |
|
35 |
unsigned long cdrom_drive; |
|
36 |
#ifndef STAGE1_5 |
|
37 |
#ifdef SOLARIS_NETBOOT |
|
38 |
unsigned long dhcpack_length; |
|
39 |
unsigned long dhcpack_buf; |
|
40 |
#endif /* SOLARIS_NETBOOT */ |
|
41 |
unsigned long saved_mem_upper; |
|
42 |
||
43 |
/* This saves the maximum size of extended memory (in KB). */ |
|
44 |
unsigned long extended_memory; |
|
45 |
#endif |
|
46 |
||
47 |
/* |
|
48 |
* Error code stuff. |
|
49 |
*/ |
|
50 |
||
51 |
grub_error_t errnum = ERR_NONE; |
|
52 |
||
53 |
#ifndef STAGE1_5 |
|
54 |
||
55 |
char *err_list[] = |
|
56 |
{ |
|
57 |
[ERR_NONE] = 0, |
|
58 |
[ERR_BAD_ARGUMENT] = "Invalid argument", |
|
59 |
[ERR_BAD_FILENAME] = |
|
60 |
"Filename must be either an absolute pathname or blocklist", |
|
61 |
[ERR_BAD_FILETYPE] = "Bad file or directory type", |
|
62 |
[ERR_BAD_GZIP_DATA] = "Bad or corrupt data while decompressing file", |
|
63 |
[ERR_BAD_GZIP_HEADER] = "Bad or incompatible header in compressed file", |
|
64 |
[ERR_BAD_PART_TABLE] = "Partition table invalid or corrupt", |
|
65 |
[ERR_BAD_VERSION] = "Mismatched or corrupt version of stage1/stage2", |
|
66 |
[ERR_BELOW_1MB] = "Loading below 1MB is not supported", |
|
67 |
[ERR_BOOT_COMMAND] = "Kernel must be loaded before booting", |
|
68 |
[ERR_BOOT_FAILURE] = "Unknown boot failure", |
|
69 |
[ERR_BOOT_FEATURES] = "Unsupported Multiboot features requested", |
|
70 |
[ERR_DEV_FORMAT] = "Unrecognized device string", |
|
71 |
[ERR_DEV_NEED_INIT] = "Device not initialized yet", |
|
72 |
[ERR_DEV_VALUES] = "Invalid device requested", |
|
73 |
[ERR_EXEC_FORMAT] = "Invalid or unsupported executable format", |
|
74 |
[ERR_FILELENGTH] = |
|
75 |
"Filesystem compatibility error, cannot read whole file", |
|
76 |
[ERR_FILE_NOT_FOUND] = "File not found", |
|
77 |
[ERR_FSYS_CORRUPT] = "Inconsistent filesystem structure", |
|
78 |
[ERR_FSYS_MOUNT] = "Cannot mount selected partition", |
|
79 |
[ERR_GEOM] = "Selected cylinder exceeds maximum supported by BIOS", |
|
80 |
[ERR_NEED_LX_KERNEL] = "Linux kernel must be loaded before initrd", |
|
81 |
[ERR_NEED_MB_KERNEL] = "Multiboot kernel must be loaded before modules", |
|
82 |
[ERR_NO_DISK] = "Selected disk does not exist", |
|
83 |
[ERR_NO_DISK_SPACE] = "No spare sectors on the disk", |
|
84 |
[ERR_NO_PART] = "No such partition", |
|
85 |
[ERR_NUMBER_OVERFLOW] = "Overflow while parsing number", |
|
86 |
[ERR_NUMBER_PARSING] = "Error while parsing number", |
|
87 |
[ERR_OUTSIDE_PART] = "Attempt to access block outside partition", |
|
88 |
[ERR_PRIVILEGED] = "Must be authenticated", |
|
89 |
[ERR_READ] = "Disk read error", |
|
90 |
[ERR_SYMLINK_LOOP] = "Too many symbolic links", |
|
91 |
[ERR_UNALIGNED] = "File is not sector aligned", |
|
92 |
[ERR_UNRECOGNIZED] = "Unrecognized command", |
|
93 |
[ERR_WONT_FIT] = "Selected item cannot fit into memory", |
|
94 |
[ERR_WRITE] = "Disk write error", |
|
3912 | 95 |
[ERR_BAD_GZIP_CRC] = "Incorrect gunzip CRC checksum", |
6423 | 96 |
[ERR_FILESYSTEM_NOT_FOUND] = "File System not found", |
3912 | 97 |
/* this zfs file system is not found in the pool of the device */ |
7300
3f0c3af330d3
6667976 support booting up a snapshot root dataset
Eric Taylor <Eric.Taylor@Sun.COM>
parents:
6423
diff
changeset
|
98 |
[ERR_NO_BOOTPATH] = "No valid boot path found in the zfs label. This may be caused by attempting to boot from an off-lined device.", |
3f0c3af330d3
6667976 support booting up a snapshot root dataset
Eric Taylor <Eric.Taylor@Sun.COM>
parents:
6423
diff
changeset
|
99 |
[ERR_NEWER_VERSION] = "Newer on-disk pool version" |
0 | 100 |
}; |
101 |
||
102 |
||
103 |
/* static for BIOS memory map fakery */ |
|
104 |
static struct AddrRangeDesc fakemap[3] = |
|
105 |
{ |
|
106 |
{20, 0, 0, MB_ARD_MEMORY}, |
|
107 |
{20, 0x100000, 0, MB_ARD_MEMORY}, |
|
108 |
{20, 0x1000000, 0, MB_ARD_MEMORY} |
|
109 |
}; |
|
110 |
||
111 |
/* A big problem is that the memory areas aren't guaranteed to be: |
|
112 |
(1) contiguous, (2) sorted in ascending order, or (3) non-overlapping. |
|
113 |
Thus this kludge. */ |
|
114 |
static unsigned long |
|
115 |
mmap_avail_at (unsigned long bottom) |
|
116 |
{ |
|
117 |
unsigned long long top; |
|
118 |
unsigned long addr; |
|
119 |
int cont; |
|
120 |
||
121 |
top = bottom; |
|
122 |
do |
|
123 |
{ |
|
124 |
for (cont = 0, addr = mbi.mmap_addr; |
|
125 |
addr < mbi.mmap_addr + mbi.mmap_length; |
|
126 |
addr += *((unsigned long *) addr) + 4) |
|
127 |
{ |
|
128 |
struct AddrRangeDesc *desc = (struct AddrRangeDesc *) addr; |
|
129 |
||
130 |
if (desc->Type == MB_ARD_MEMORY |
|
131 |
&& desc->BaseAddr <= top |
|
132 |
&& desc->BaseAddr + desc->Length > top) |
|
133 |
{ |
|
134 |
top = desc->BaseAddr + desc->Length; |
|
135 |
cont++; |
|
136 |
} |
|
137 |
} |
|
138 |
} |
|
139 |
while (cont); |
|
140 |
||
141 |
/* For now, GRUB assumes 32bits addresses, so... */ |
|
142 |
if (top > 0xFFFFFFFF) |
|
143 |
top = 0xFFFFFFFF; |
|
144 |
||
145 |
return (unsigned long) top - bottom; |
|
146 |
} |
|
147 |
#endif /* ! STAGE1_5 */ |
|
148 |
||
149 |
/* This queries for BIOS information. */ |
|
150 |
void |
|
151 |
init_bios_info (void) |
|
152 |
{ |
|
153 |
#ifndef STAGE1_5 |
|
154 |
unsigned long cont, memtmp, addr; |
|
155 |
int drive; |
|
156 |
#endif |
|
157 |
||
158 |
/* |
|
159 |
* Get information from BIOS on installed RAM. |
|
160 |
*/ |
|
161 |
||
162 |
mbi.mem_lower = get_memsize (0); |
|
163 |
mbi.mem_upper = get_memsize (1); |
|
164 |
||
165 |
#ifndef STAGE1_5 |
|
166 |
/* |
|
167 |
* We need to call this somewhere before trying to put data |
|
168 |
* above 1 MB, since without calling it, address line 20 will be wired |
|
169 |
* to 0. Not too desirable. |
|
170 |
*/ |
|
171 |
||
172 |
gateA20 (1); |
|
173 |
||
174 |
/* Store the size of extended memory in EXTENDED_MEMORY, in order to |
|
175 |
tell it to non-Multiboot OSes. */ |
|
176 |
extended_memory = mbi.mem_upper; |
|
177 |
||
178 |
/* |
|
179 |
* The "mbi.mem_upper" variable only recognizes upper memory in the |
|
180 |
* first memory region. If there are multiple memory regions, |
|
181 |
* the rest are reported to a Multiboot-compliant OS, but otherwise |
|
182 |
* unused by GRUB. |
|
183 |
*/ |
|
184 |
||
185 |
addr = get_code_end (); |
|
186 |
mbi.mmap_addr = addr; |
|
187 |
mbi.mmap_length = 0; |
|
188 |
cont = 0; |
|
189 |
||
190 |
do |
|
191 |
{ |
|
192 |
cont = get_mmap_entry ((void *) addr, cont); |
|
193 |
||
194 |
/* If the returned buffer's length is zero, quit. */ |
|
195 |
if (! *((unsigned long *) addr)) |
|
196 |
break; |
|
197 |
||
198 |
mbi.mmap_length += *((unsigned long *) addr) + 4; |
|
199 |
addr += *((unsigned long *) addr) + 4; |
|
200 |
} |
|
201 |
while (cont); |
|
202 |
||
203 |
if (mbi.mmap_length) |
|
204 |
{ |
|
205 |
unsigned long long max_addr; |
|
206 |
||
207 |
/* |
|
208 |
* This is to get the lower memory, and upper memory (up to the |
|
209 |
* first memory hole), into the "mbi.mem_{lower,upper}" |
|
210 |
* elements. This is for OS's that don't care about the memory |
|
211 |
* map, but might care about total RAM available. |
|
212 |
*/ |
|
213 |
mbi.mem_lower = mmap_avail_at (0) >> 10; |
|
214 |
mbi.mem_upper = mmap_avail_at (0x100000) >> 10; |
|
215 |
||
216 |
/* Find the maximum available address. Ignore any memory holes. */ |
|
217 |
for (max_addr = 0, addr = mbi.mmap_addr; |
|
218 |
addr < mbi.mmap_addr + mbi.mmap_length; |
|
219 |
addr += *((unsigned long *) addr) + 4) |
|
220 |
{ |
|
221 |
struct AddrRangeDesc *desc = (struct AddrRangeDesc *) addr; |
|
222 |
||
223 |
if (desc->Type == MB_ARD_MEMORY && desc->Length > 0 |
|
224 |
&& desc->BaseAddr + desc->Length > max_addr) |
|
225 |
max_addr = desc->BaseAddr + desc->Length; |
|
226 |
} |
|
227 |
||
228 |
extended_memory = (max_addr - 0x100000) >> 10; |
|
229 |
} |
|
230 |
else if ((memtmp = get_eisamemsize ()) != -1) |
|
231 |
{ |
|
232 |
cont = memtmp & ~0xFFFF; |
|
233 |
memtmp = memtmp & 0xFFFF; |
|
234 |
||
235 |
if (cont != 0) |
|
236 |
extended_memory = (cont >> 10) + 0x3c00; |
|
237 |
else |
|
238 |
extended_memory = memtmp; |
|
239 |
||
240 |
if (!cont || (memtmp == 0x3c00)) |
|
241 |
memtmp += (cont >> 10); |
|
242 |
else |
|
243 |
{ |
|
244 |
/* XXX should I do this at all ??? */ |
|
245 |
||
246 |
mbi.mmap_addr = (unsigned long) fakemap; |
|
247 |
mbi.mmap_length = sizeof (fakemap); |
|
248 |
fakemap[0].Length = (mbi.mem_lower << 10); |
|
249 |
fakemap[1].Length = (memtmp << 10); |
|
250 |
fakemap[2].Length = cont; |
|
251 |
} |
|
252 |
||
253 |
mbi.mem_upper = memtmp; |
|
254 |
} |
|
255 |
||
256 |
saved_mem_upper = mbi.mem_upper; |
|
257 |
||
258 |
#ifdef SUPPORT_NETBOOT |
|
259 |
#ifdef SOLARIS_NETBOOT |
|
260 |
/* leave room for dhcpack_buf */ |
|
261 |
dhcpack_buf = addr; |
|
262 |
addr += sizeof (struct dhcp_t); |
|
263 |
#endif |
|
264 |
#endif |
|
265 |
||
266 |
/* Get the drive info. */ |
|
267 |
/* FIXME: This should be postponed until a Multiboot kernel actually |
|
268 |
requires it, because this could slow down the start-up |
|
269 |
unreasonably. */ |
|
270 |
mbi.drives_length = 0; |
|
271 |
mbi.drives_addr = addr; |
|
272 |
||
273 |
/* For now, GRUB doesn't probe floppies, since it is trivial to map |
|
274 |
floppy drives to BIOS drives. */ |
|
275 |
for (drive = 0x80; drive < 0x88; drive++) |
|
276 |
{ |
|
277 |
struct geometry geom; |
|
278 |
struct drive_info *info = (struct drive_info *) addr; |
|
279 |
unsigned short *port; |
|
280 |
||
281 |
/* Get the geometry. This ensures that the drive is present. */ |
|
282 |
if (get_diskinfo (drive, &geom)) |
|
283 |
break; |
|
284 |
||
285 |
/* Clean out the I/O map. */ |
|
286 |
grub_memset ((char *) io_map, 0, |
|
287 |
IO_MAP_SIZE * sizeof (unsigned short)); |
|
288 |
||
289 |
/* Disable to probe I/O ports temporarily, because this doesn't |
|
290 |
work with some BIOSes (maybe they are too buggy). */ |
|
291 |
#if 0 |
|
292 |
/* Track the int13 handler. */ |
|
293 |
track_int13 (drive); |
|
294 |
#endif |
|
295 |
||
296 |
/* Set the information. */ |
|
297 |
info->drive_number = drive; |
|
298 |
info->drive_mode = ((geom.flags & BIOSDISK_FLAG_LBA_EXTENSION) |
|
299 |
? MB_DI_LBA_MODE : MB_DI_CHS_MODE); |
|
300 |
info->drive_cylinders = geom.cylinders; |
|
301 |
info->drive_heads = geom.heads; |
|
302 |
info->drive_sectors = geom.sectors; |
|
303 |
||
304 |
addr += sizeof (struct drive_info); |
|
305 |
for (port = io_map; *port; port++, addr += sizeof (unsigned short)) |
|
306 |
*((unsigned short *) addr) = *port; |
|
307 |
||
308 |
info->size = addr - (unsigned long) info; |
|
309 |
mbi.drives_length += info->size; |
|
310 |
} |
|
311 |
||
312 |
/* Get the ROM configuration table by INT 15, AH=C0h. */ |
|
313 |
mbi.config_table = get_rom_config_table (); |
|
314 |
||
315 |
/* Set the boot loader name. */ |
|
316 |
mbi.boot_loader_name = (unsigned long) "GNU GRUB " VERSION; |
|
317 |
||
318 |
/* Get the APM BIOS table. */ |
|
319 |
get_apm_info (); |
|
320 |
if (apm_bios_info.version) |
|
321 |
mbi.apm_table = (unsigned long) &apm_bios_info; |
|
322 |
||
323 |
/* |
|
324 |
* Initialize other Multiboot Info flags. |
|
325 |
*/ |
|
326 |
||
327 |
mbi.flags = (MB_INFO_MEMORY | MB_INFO_CMDLINE | MB_INFO_BOOTDEV |
|
328 |
| MB_INFO_DRIVE_INFO | MB_INFO_CONFIG_TABLE |
|
329 |
| MB_INFO_BOOT_LOADER_NAME); |
|
330 |
||
331 |
if (apm_bios_info.version) |
|
332 |
mbi.flags |= MB_INFO_APM_TABLE; |
|
333 |
||
334 |
#endif /* STAGE1_5 */ |
|
335 |
||
336 |
/* Set boot drive and partition. */ |
|
337 |
saved_drive = boot_drive; |
|
338 |
saved_partition = install_partition; |
|
339 |
||
340 |
/* Set cdrom drive. */ |
|
341 |
{ |
|
342 |
struct geometry geom; |
|
343 |
||
344 |
/* Get the geometry. */ |
|
345 |
if (get_diskinfo (boot_drive, &geom) |
|
346 |
|| ! (geom.flags & BIOSDISK_FLAG_CDROM)) |
|
347 |
cdrom_drive = GRUB_INVALID_DRIVE; |
|
348 |
else |
|
349 |
cdrom_drive = boot_drive; |
|
350 |
} |
|
351 |
||
352 |
/* Start main routine here. */ |
|
353 |
cmain (); |
|
354 |
} |