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", 95 [ERR_BAD_GZIP_CRC] = "Incorrect gunzip CRC checksum", 96 [ERR_FILESYSTEM_NOT_FOUND] = "File System not found", 97 /* this zfs file system is not found in the pool of the device */ 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.", 99 [ERR_NEWER_VERSION] = "Newer on-disk pool version", 100 [ERR_NOTXPM] = "Image not in XPM graphics format", 101 [ERR_TOOMANYCOLORS] = "Image cannot use more than 14 colors", 102 [ERR_CORRUPTXPM] = "File contains corrupt XPM image data", 103 [ERR_NOVAR] = "Unknown variable reference", 104 }; 105 106 107 /* static for BIOS memory map fakery */ 108 static struct AddrRangeDesc fakemap[3] = 109 { 110 {20, 0, 0, MB_ARD_MEMORY}, 111 {20, 0x100000, 0, MB_ARD_MEMORY}, 112 {20, 0x1000000, 0, MB_ARD_MEMORY} 113 }; 114 115 /* A big problem is that the memory areas aren't guaranteed to be: 116 (1) contiguous, (2) sorted in ascending order, or (3) non-overlapping. 117 Thus this kludge. */ 118 static unsigned long 119 mmap_avail_at (unsigned long bottom) 120 { 121 unsigned long long top; 122 unsigned long addr; 123 int cont; 124 125 top = bottom; 126 do 127 { 128 for (cont = 0, addr = mbi.mmap_addr; 129 addr < mbi.mmap_addr + mbi.mmap_length; 130 addr += *((unsigned long *) addr) + 4) 131 { 132 struct AddrRangeDesc *desc = (struct AddrRangeDesc *) addr; 133 134 if (desc->Type == MB_ARD_MEMORY 135 && desc->BaseAddr <= top 136 && desc->BaseAddr + desc->Length > top) 137 { 138 top = desc->BaseAddr + desc->Length; 139 cont++; 140 } 141 } 142 } 143 while (cont); 144 145 /* For now, GRUB assumes 32bits addresses, so... */ 146 if (top > 0xFFFFFFFF) 147 top = 0xFFFFFFFF; 148 149 return (unsigned long) top - bottom; 150 } 151 #endif /* ! STAGE1_5 */ 152 153 /* This queries for BIOS information. */ 154 void 155 init_bios_info (void) 156 { 157 #ifndef STAGE1_5 158 unsigned long cont, memtmp, addr; 159 int drive; 160 #endif 161 162 /* 163 * Get information from BIOS on installed RAM. 164 */ 165 166 mbi.mem_lower = get_memsize (0); 167 mbi.mem_upper = get_memsize (1); 168 169 #ifndef STAGE1_5 170 /* 171 * We need to call this somewhere before trying to put data 172 * above 1 MB, since without calling it, address line 20 will be wired 173 * to 0. Not too desirable. 174 */ 175 176 gateA20 (1); 177 178 /* Store the size of extended memory in EXTENDED_MEMORY, in order to 179 tell it to non-Multiboot OSes. */ 180 extended_memory = mbi.mem_upper; 181 182 /* 183 * The "mbi.mem_upper" variable only recognizes upper memory in the 184 * first memory region. If there are multiple memory regions, 185 * the rest are reported to a Multiboot-compliant OS, but otherwise 186 * unused by GRUB. 187 */ 188 189 addr = get_code_end (); 190 mbi.mmap_addr = addr; 191 mbi.mmap_length = 0; 192 cont = 0; 193 194 do 195 { 196 cont = get_mmap_entry ((void *) addr, cont); 197 198 /* If the returned buffer's length is zero, quit. */ 199 if (! *((unsigned long *) addr)) 200 break; 201 202 mbi.mmap_length += *((unsigned long *) addr) + 4; 203 addr += *((unsigned long *) addr) + 4; 204 } 205 while (cont); 206 207 if (mbi.mmap_length) 208 { 209 unsigned long long max_addr; 210 211 /* 212 * This is to get the lower memory, and upper memory (up to the 213 * first memory hole), into the "mbi.mem_{lower,upper}" 214 * elements. This is for OS's that don't care about the memory 215 * map, but might care about total RAM available. 216 */ 217 mbi.mem_lower = mmap_avail_at (0) >> 10; 218 mbi.mem_upper = mmap_avail_at (0x100000) >> 10; 219 220 /* Find the maximum available address. Ignore any memory holes. */ 221 for (max_addr = 0, addr = mbi.mmap_addr; 222 addr < mbi.mmap_addr + mbi.mmap_length; 223 addr += *((unsigned long *) addr) + 4) 224 { 225 struct AddrRangeDesc *desc = (struct AddrRangeDesc *) addr; 226 227 if (desc->Type == MB_ARD_MEMORY && desc->Length > 0 228 && desc->BaseAddr + desc->Length > max_addr) 229 max_addr = desc->BaseAddr + desc->Length; 230 } 231 232 extended_memory = (max_addr - 0x100000) >> 10; 233 } 234 else if ((memtmp = get_eisamemsize ()) != -1) 235 { 236 cont = memtmp & ~0xFFFF; 237 memtmp = memtmp & 0xFFFF; 238 239 if (cont != 0) 240 extended_memory = (cont >> 10) + 0x3c00; 241 else 242 extended_memory = memtmp; 243 244 if (!cont || (memtmp == 0x3c00)) 245 memtmp += (cont >> 10); 246 else 247 { 248 /* XXX should I do this at all ??? */ 249 250 mbi.mmap_addr = (unsigned long) fakemap; 251 mbi.mmap_length = sizeof (fakemap); 252 fakemap[0].Length = (mbi.mem_lower << 10); 253 fakemap[1].Length = (memtmp << 10); 254 fakemap[2].Length = cont; 255 } 256 257 mbi.mem_upper = memtmp; 258 } 259 260 saved_mem_upper = mbi.mem_upper; 261 262 #ifdef SUPPORT_NETBOOT 263 #ifdef SOLARIS_NETBOOT 264 /* leave room for dhcpack_buf */ 265 dhcpack_buf = addr; 266 addr += sizeof (struct dhcp_t); 267 #endif 268 #endif 269 270 /* Get the drive info. */ 271 /* FIXME: This should be postponed until a Multiboot kernel actually 272 requires it, because this could slow down the start-up 273 unreasonably. */ 274 mbi.drives_length = 0; 275 mbi.drives_addr = addr; 276 277 /* For now, GRUB doesn't probe floppies, since it is trivial to map 278 floppy drives to BIOS drives. */ 279 for (drive = 0x80; drive < 0x88; drive++) 280 { 281 struct geometry geom; 282 struct drive_info *info = (struct drive_info *) addr; 283 unsigned short *port; 284 285 /* Get the geometry. This ensures that the drive is present. */ 286 if (get_diskinfo (drive, &geom)) 287 break; 288 289 /* Clean out the I/O map. */ 290 grub_memset ((char *) io_map, 0, 291 IO_MAP_SIZE * sizeof (unsigned short)); 292 293 /* Disable to probe I/O ports temporarily, because this doesn't 294 work with some BIOSes (maybe they are too buggy). */ 295 #if 0 296 /* Track the int13 handler. */ 297 track_int13 (drive); 298 #endif 299 300 /* Set the information. */ 301 info->drive_number = drive; 302 info->drive_mode = ((geom.flags & BIOSDISK_FLAG_LBA_EXTENSION) 303 ? MB_DI_LBA_MODE : MB_DI_CHS_MODE); 304 info->drive_cylinders = geom.cylinders; 305 info->drive_heads = geom.heads; 306 info->drive_sectors = geom.sectors; 307 308 addr += sizeof (struct drive_info); 309 for (port = io_map; *port; port++, addr += sizeof (unsigned short)) 310 *((unsigned short *) addr) = *port; 311 312 info->size = addr - (unsigned long) info; 313 mbi.drives_length += info->size; 314 } 315 316 /* Get the ROM configuration table by INT 15, AH=C0h. */ 317 mbi.config_table = get_rom_config_table (); 318 319 /* Set the boot loader name. */ 320 mbi.boot_loader_name = (unsigned long) "GNU GRUB " VERSION; 321 322 /* Get the APM BIOS table. */ 323 get_apm_info (); 324 if (apm_bios_info.version) 325 mbi.apm_table = (unsigned long) &apm_bios_info; 326 327 /* 328 * Initialize other Multiboot Info flags. 329 */ 330 331 mbi.flags = (MB_INFO_MEMORY | MB_INFO_CMDLINE | MB_INFO_BOOTDEV 332 | MB_INFO_DRIVE_INFO | MB_INFO_CONFIG_TABLE 333 | MB_INFO_BOOT_LOADER_NAME); 334 335 if (apm_bios_info.version) 336 mbi.flags |= MB_INFO_APM_TABLE; 337 338 #endif /* STAGE1_5 */ 339 340 /* Set boot drive and partition. */ 341 saved_drive = boot_drive; 342 saved_partition = install_partition; 343 344 /* Set cdrom drive. */ 345 { 346 struct geometry geom; 347 348 /* Get the geometry. */ 349 if (get_diskinfo (boot_drive, &geom) 350 || ! (geom.flags & BIOSDISK_FLAG_CDROM)) 351 cdrom_drive = GRUB_INVALID_DRIVE; 352 else 353 cdrom_drive = boot_drive; 354 } 355 356 /* Start main routine here. */ 357 cmain (); 358 } 359