17c478bd9Sstevel@tonic-gate /* builtins.c - the GRUB builtin commands */
27c478bd9Sstevel@tonic-gate /*
37c478bd9Sstevel@tonic-gate  *  GRUB  --  GRand Unified Bootloader
47c478bd9Sstevel@tonic-gate  *  Copyright (C) 1999,2000,2001,2002,2003,2004  Free Software Foundation, Inc.
57c478bd9Sstevel@tonic-gate  *
67c478bd9Sstevel@tonic-gate  *  This program is free software; you can redistribute it and/or modify
77c478bd9Sstevel@tonic-gate  *  it under the terms of the GNU General Public License as published by
87c478bd9Sstevel@tonic-gate  *  the Free Software Foundation; either version 2 of the License, or
97c478bd9Sstevel@tonic-gate  *  (at your option) any later version.
107c478bd9Sstevel@tonic-gate  *
117c478bd9Sstevel@tonic-gate  *  This program is distributed in the hope that it will be useful,
127c478bd9Sstevel@tonic-gate  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
137c478bd9Sstevel@tonic-gate  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
147c478bd9Sstevel@tonic-gate  *  GNU General Public License for more details.
157c478bd9Sstevel@tonic-gate  *
167c478bd9Sstevel@tonic-gate  *  You should have received a copy of the GNU General Public License
177c478bd9Sstevel@tonic-gate  *  along with this program; if not, write to the Free Software
187c478bd9Sstevel@tonic-gate  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
197c478bd9Sstevel@tonic-gate  */
20342440ecSPrasad Singamsetty 
21eb2bd662Svikram /*
22eb2bd662Svikram  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23eb2bd662Svikram  * Use is subject to license terms.
24eb2bd662Svikram  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /* Include stdio.h before shared.h, because we can't define
277c478bd9Sstevel@tonic-gate    WITHOUT_LIBC_STUBS here.  */
287c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
297c478bd9Sstevel@tonic-gate # include <stdio.h>
307c478bd9Sstevel@tonic-gate #endif
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include <shared.h>
337c478bd9Sstevel@tonic-gate #include <filesys.h>
347c478bd9Sstevel@tonic-gate #include <term.h>
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
377c478bd9Sstevel@tonic-gate # include <grub.h>
387c478bd9Sstevel@tonic-gate #endif
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate #ifdef SUPPORT_SERIAL
417c478bd9Sstevel@tonic-gate # include <serial.h>
427c478bd9Sstevel@tonic-gate # include <terminfo.h>
437c478bd9Sstevel@tonic-gate #endif
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
467c478bd9Sstevel@tonic-gate # include <device.h>
477c478bd9Sstevel@tonic-gate #else /* ! GRUB_UTIL */
487c478bd9Sstevel@tonic-gate # include <apic.h>
497c478bd9Sstevel@tonic-gate # include <smp-imps.h>
507c478bd9Sstevel@tonic-gate #endif /* ! GRUB_UTIL */
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate #ifdef USE_MD5_PASSWORDS
537c478bd9Sstevel@tonic-gate # include <md5.h>
547c478bd9Sstevel@tonic-gate #endif
557c478bd9Sstevel@tonic-gate 
56ae115bc7Smrj #include <cpu.h>
57ae115bc7Smrj 
587c478bd9Sstevel@tonic-gate /* The type of kernel loaded.  */
597c478bd9Sstevel@tonic-gate kernel_t kernel_type;
607c478bd9Sstevel@tonic-gate /* The boot device.  */
617c478bd9Sstevel@tonic-gate static int bootdev;
627c478bd9Sstevel@tonic-gate /* True when the debug mode is turned on, and false
637c478bd9Sstevel@tonic-gate    when it is turned off.  */
647c478bd9Sstevel@tonic-gate int debug = 0;
657c478bd9Sstevel@tonic-gate /* The default entry.  */
667c478bd9Sstevel@tonic-gate int default_entry = 0;
677c478bd9Sstevel@tonic-gate /* The fallback entry.  */
687c478bd9Sstevel@tonic-gate int fallback_entryno;
697c478bd9Sstevel@tonic-gate int fallback_entries[MAX_FALLBACK_ENTRIES];
707c478bd9Sstevel@tonic-gate /* The number of current entry.  */
717c478bd9Sstevel@tonic-gate int current_entryno;
727c478bd9Sstevel@tonic-gate /* The address for Multiboot command-line buffer.  */
737c478bd9Sstevel@tonic-gate static char *mb_cmdline;
747c478bd9Sstevel@tonic-gate /* The password.  */
757c478bd9Sstevel@tonic-gate char *password;
767c478bd9Sstevel@tonic-gate /* The password type.  */
777c478bd9Sstevel@tonic-gate password_t password_type;
787c478bd9Sstevel@tonic-gate /* The flag for indicating that the user is authoritative.  */
797c478bd9Sstevel@tonic-gate int auth = 0;
807c478bd9Sstevel@tonic-gate /* The timeout.  */
817c478bd9Sstevel@tonic-gate int grub_timeout = -1;
827c478bd9Sstevel@tonic-gate /* Whether to show the menu or not.  */
837c478bd9Sstevel@tonic-gate int show_menu = 1;
847c478bd9Sstevel@tonic-gate /* The BIOS drive map.  */
857c478bd9Sstevel@tonic-gate static unsigned short bios_drive_map[DRIVE_MAP_SIZE + 1];
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate /* Prototypes for allowing straightfoward calling of builtins functions
887c478bd9Sstevel@tonic-gate    inside other functions.  */
897c478bd9Sstevel@tonic-gate static int configfile_func (char *arg, int flags);
907c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
917c478bd9Sstevel@tonic-gate static void solaris_config_file (void);
927c478bd9Sstevel@tonic-gate #endif
937c478bd9Sstevel@tonic-gate 
94342440ecSPrasad Singamsetty static unsigned int min_mem64 = 0;
95342440ecSPrasad Singamsetty 
967c478bd9Sstevel@tonic-gate #if defined(__sun) && !defined(GRUB_UTIL)
977c478bd9Sstevel@tonic-gate extern void __enable_execute_stack (void *);
987c478bd9Sstevel@tonic-gate void
997c478bd9Sstevel@tonic-gate __enable_execute_stack (void *addr)
1007c478bd9Sstevel@tonic-gate {
1017c478bd9Sstevel@tonic-gate }
1027c478bd9Sstevel@tonic-gate #endif /* __sun && !GRUB_UTIL */
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate /* Initialize the data for builtins.  */
1057c478bd9Sstevel@tonic-gate void
1067c478bd9Sstevel@tonic-gate init_builtins (void)
1077c478bd9Sstevel@tonic-gate {
1087c478bd9Sstevel@tonic-gate   kernel_type = KERNEL_TYPE_NONE;
1097c478bd9Sstevel@tonic-gate   /* BSD and chainloading evil hacks!  */
1107c478bd9Sstevel@tonic-gate   bootdev = set_bootdev (0);
1117c478bd9Sstevel@tonic-gate   mb_cmdline = (char *) MB_CMDLINE_BUF;
1127c478bd9Sstevel@tonic-gate }
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate /* Initialize the data for the configuration file.  */
1157c478bd9Sstevel@tonic-gate void
1167c478bd9Sstevel@tonic-gate init_config (void)
1177c478bd9Sstevel@tonic-gate {
1187c478bd9Sstevel@tonic-gate   default_entry = 0;
1197c478bd9Sstevel@tonic-gate   password = 0;
1207c478bd9Sstevel@tonic-gate   fallback_entryno = -1;
1217c478bd9Sstevel@tonic-gate   fallback_entries[0] = -1;
1227c478bd9Sstevel@tonic-gate   grub_timeout = -1;
123b1b8ab34Slling   current_rootpool[0] = '\0';
124b1b8ab34Slling   current_bootfs[0] = '\0';
125e7cbe64fSgw   current_bootpath[0] = '\0';
126b1b8ab34Slling   current_bootfs_obj = 0;
127051aabe6Staylor   current_devid[0] = '\0';
128b1b8ab34Slling   is_zfs_mount = 0;
1297c478bd9Sstevel@tonic-gate }
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate /* Check a password for correctness.  Returns 0 if password was
1327c478bd9Sstevel@tonic-gate    correct, and a value != 0 for error, similarly to strcmp. */
1337c478bd9Sstevel@tonic-gate int
1347c478bd9Sstevel@tonic-gate check_password (char *entered, char* expected, password_t type)
1357c478bd9Sstevel@tonic-gate {
1367c478bd9Sstevel@tonic-gate   switch (type)
1377c478bd9Sstevel@tonic-gate     {
1387c478bd9Sstevel@tonic-gate     case PASSWORD_PLAIN:
1397c478bd9Sstevel@tonic-gate       return strcmp (entered, expected);
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate #ifdef USE_MD5_PASSWORDS
1427c478bd9Sstevel@tonic-gate     case PASSWORD_MD5:
1437c478bd9Sstevel@tonic-gate       return check_md5_password (entered, expected);
1447c478bd9Sstevel@tonic-gate #endif
1457c478bd9Sstevel@tonic-gate     default:
1467c478bd9Sstevel@tonic-gate       /* unsupported password type: be secure */
1477c478bd9Sstevel@tonic-gate       return 1;
1487c478bd9Sstevel@tonic-gate     }
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate /* Print which sector is read when loading a file.  */
1527c478bd9Sstevel@tonic-gate static void
153342440ecSPrasad Singamsetty disk_read_print_func(unsigned int sector, int offset, int length)
1547c478bd9Sstevel@tonic-gate {
155342440ecSPrasad Singamsetty   grub_printf ("[%u,%d,%d]", sector, offset, length);
1567c478bd9Sstevel@tonic-gate }
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate /* blocklist */
1607c478bd9Sstevel@tonic-gate static int
1617c478bd9Sstevel@tonic-gate blocklist_func (char *arg, int flags)
1627c478bd9Sstevel@tonic-gate {
1637c478bd9Sstevel@tonic-gate   char *dummy = (char *) RAW_ADDR (0x100000);
1641b8adde7SWilliam Kucharski   unsigned int start_sector = 0;
1657c478bd9Sstevel@tonic-gate   int num_sectors = 0;
1667c478bd9Sstevel@tonic-gate   int num_entries = 0;
1677c478bd9Sstevel@tonic-gate   int last_length = 0;
1687c478bd9Sstevel@tonic-gate 
1691b8adde7SWilliam Kucharski   auto void disk_read_blocklist_func (unsigned int sector, int offset,
1701b8adde7SWilliam Kucharski       int length);
1711b8adde7SWilliam Kucharski 
1727c478bd9Sstevel@tonic-gate   /* Collect contiguous blocks into one entry as many as possible,
1737c478bd9Sstevel@tonic-gate      and print the blocklist notation on the screen.  */
1741b8adde7SWilliam Kucharski   auto void disk_read_blocklist_func (unsigned int sector, int offset,
1751b8adde7SWilliam Kucharski       int length)
1767c478bd9Sstevel@tonic-gate     {
1777c478bd9Sstevel@tonic-gate       if (num_sectors > 0)
1787c478bd9Sstevel@tonic-gate 	{
1797c478bd9Sstevel@tonic-gate 	  if (start_sector + num_sectors == sector
1807c478bd9Sstevel@tonic-gate 	      && offset == 0 && last_length == SECTOR_SIZE)
1817c478bd9Sstevel@tonic-gate 	    {
1827c478bd9Sstevel@tonic-gate 	      num_sectors++;
1837c478bd9Sstevel@tonic-gate 	      last_length = length;
1847c478bd9Sstevel@tonic-gate 	      return;
1857c478bd9Sstevel@tonic-gate 	    }
1867c478bd9Sstevel@tonic-gate 	  else
1877c478bd9Sstevel@tonic-gate 	    {
1887c478bd9Sstevel@tonic-gate 	      if (last_length == SECTOR_SIZE)
1897c478bd9Sstevel@tonic-gate 		grub_printf ("%s%d+%d", num_entries ? "," : "",
1907c478bd9Sstevel@tonic-gate 			     start_sector - part_start, num_sectors);
1917c478bd9Sstevel@tonic-gate 	      else if (num_sectors > 1)
1927c478bd9Sstevel@tonic-gate 		grub_printf ("%s%d+%d,%d[0-%d]", num_entries ? "," : "",
1937c478bd9Sstevel@tonic-gate 			     start_sector - part_start, num_sectors-1,
1947c478bd9Sstevel@tonic-gate 			     start_sector + num_sectors-1 - part_start,
1957c478bd9Sstevel@tonic-gate 			     last_length);
1967c478bd9Sstevel@tonic-gate 	      else
1977c478bd9Sstevel@tonic-gate 		grub_printf ("%s%d[0-%d]", num_entries ? "," : "",
1987c478bd9Sstevel@tonic-gate 			     start_sector - part_start, last_length);
1997c478bd9Sstevel@tonic-gate 	      num_entries++;
2007c478bd9Sstevel@tonic-gate 	      num_sectors = 0;
2017c478bd9Sstevel@tonic-gate 	    }
2027c478bd9Sstevel@tonic-gate 	}
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate       if (offset > 0)
2057c478bd9Sstevel@tonic-gate 	{
2061b8adde7SWilliam Kucharski 	  grub_printf("%s%u[%d-%d]", num_entries ? "," : "",
2077c478bd9Sstevel@tonic-gate 		      sector-part_start, offset, offset+length);
2087c478bd9Sstevel@tonic-gate 	  num_entries++;
2097c478bd9Sstevel@tonic-gate 	}
2107c478bd9Sstevel@tonic-gate       else
2117c478bd9Sstevel@tonic-gate 	{
2127c478bd9Sstevel@tonic-gate 	  start_sector = sector;
2137c478bd9Sstevel@tonic-gate 	  num_sectors = 1;
2147c478bd9Sstevel@tonic-gate 	  last_length = length;
2157c478bd9Sstevel@tonic-gate 	}
2167c478bd9Sstevel@tonic-gate     }
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate   /* Open the file.  */
2197c478bd9Sstevel@tonic-gate   if (! grub_open (arg))
2207c478bd9Sstevel@tonic-gate     return 1;
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate   /* Print the device name.  */
2237c478bd9Sstevel@tonic-gate   grub_printf ("(%cd%d",
2247c478bd9Sstevel@tonic-gate 	       (current_drive & 0x80) ? 'h' : 'f',
2257c478bd9Sstevel@tonic-gate 	       current_drive & ~0x80);
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate   if ((current_partition & 0xFF0000) != 0xFF0000)
2287c478bd9Sstevel@tonic-gate     grub_printf (",%d", (current_partition >> 16) & 0xFF);
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate   if ((current_partition & 0x00FF00) != 0x00FF00)
2317c478bd9Sstevel@tonic-gate     grub_printf (",%c", 'a' + ((current_partition >> 8) & 0xFF));
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate   grub_printf (")");
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate   /* Read in the whole file to DUMMY.  */
2367c478bd9Sstevel@tonic-gate   disk_read_hook = disk_read_blocklist_func;
2377c478bd9Sstevel@tonic-gate   if (! grub_read (dummy, -1))
2387c478bd9Sstevel@tonic-gate     goto fail;
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate   /* The last entry may not be printed yet.  Don't check if it is a
2417c478bd9Sstevel@tonic-gate    * full sector, since it doesn't matter if we read too much. */
2427c478bd9Sstevel@tonic-gate   if (num_sectors > 0)
2437c478bd9Sstevel@tonic-gate     grub_printf ("%s%d+%d", num_entries ? "," : "",
2447c478bd9Sstevel@tonic-gate 		 start_sector - part_start, num_sectors);
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate   grub_printf ("\n");
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate  fail:
2497c478bd9Sstevel@tonic-gate   disk_read_hook = 0;
2507c478bd9Sstevel@tonic-gate   grub_close ();
2517c478bd9Sstevel@tonic-gate   return errnum;
2527c478bd9Sstevel@tonic-gate }
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate static struct builtin builtin_blocklist =
2557c478bd9Sstevel@tonic-gate {
2567c478bd9Sstevel@tonic-gate   "blocklist",
2577c478bd9Sstevel@tonic-gate   blocklist_func,
2587c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
2597c478bd9Sstevel@tonic-gate   "blocklist FILE",
2607c478bd9Sstevel@tonic-gate   "Print the blocklist notation of the file FILE."
2617c478bd9Sstevel@tonic-gate };
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate /* boot */
2647c478bd9Sstevel@tonic-gate static int
2657c478bd9Sstevel@tonic-gate boot_func (char *arg, int flags)
2667c478bd9Sstevel@tonic-gate {
2677c478bd9Sstevel@tonic-gate   /* Clear the int15 handler if we can boot the kernel successfully.
2687c478bd9Sstevel@tonic-gate      This assumes that the boot code never fails only if KERNEL_TYPE is
2697c478bd9Sstevel@tonic-gate      not KERNEL_TYPE_NONE. Is this assumption is bad?  */
2707c478bd9Sstevel@tonic-gate   if (kernel_type != KERNEL_TYPE_NONE)
2717c478bd9Sstevel@tonic-gate     unset_int15_handler ();
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
2747c478bd9Sstevel@tonic-gate   /* Shut down the networking.  */
2757c478bd9Sstevel@tonic-gate   cleanup_net ();
2767c478bd9Sstevel@tonic-gate #endif
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate   switch (kernel_type)
2797c478bd9Sstevel@tonic-gate     {
2807c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_FREEBSD:
2817c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_NETBSD:
2827c478bd9Sstevel@tonic-gate       /* *BSD */
2837c478bd9Sstevel@tonic-gate       bsd_boot (kernel_type, bootdev, (char *) mbi.cmdline);
2847c478bd9Sstevel@tonic-gate       break;
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_LINUX:
2877c478bd9Sstevel@tonic-gate       /* Linux */
2887c478bd9Sstevel@tonic-gate       linux_boot ();
2897c478bd9Sstevel@tonic-gate       break;
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_BIG_LINUX:
2927c478bd9Sstevel@tonic-gate       /* Big Linux */
2937c478bd9Sstevel@tonic-gate       big_linux_boot ();
2947c478bd9Sstevel@tonic-gate       break;
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_CHAINLOADER:
2977c478bd9Sstevel@tonic-gate       /* Chainloader */
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate       /* Check if we should set the int13 handler.  */
3007c478bd9Sstevel@tonic-gate       if (bios_drive_map[0] != 0)
3017c478bd9Sstevel@tonic-gate 	{
3027c478bd9Sstevel@tonic-gate 	  int i;
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	  /* Search for SAVED_DRIVE.  */
3057c478bd9Sstevel@tonic-gate 	  for (i = 0; i < DRIVE_MAP_SIZE; i++)
3067c478bd9Sstevel@tonic-gate 	    {
3077c478bd9Sstevel@tonic-gate 	      if (! bios_drive_map[i])
3087c478bd9Sstevel@tonic-gate 		break;
3097c478bd9Sstevel@tonic-gate 	      else if ((bios_drive_map[i] & 0xFF) == saved_drive)
3107c478bd9Sstevel@tonic-gate 		{
3117c478bd9Sstevel@tonic-gate 		  /* Exchage SAVED_DRIVE with the mapped drive.  */
3127c478bd9Sstevel@tonic-gate 		  saved_drive = (bios_drive_map[i] >> 8) & 0xFF;
3137c478bd9Sstevel@tonic-gate 		  break;
3147c478bd9Sstevel@tonic-gate 		}
3157c478bd9Sstevel@tonic-gate 	    }
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	  /* Set the handler. This is somewhat dangerous.  */
3187c478bd9Sstevel@tonic-gate 	  set_int13_handler (bios_drive_map);
3197c478bd9Sstevel@tonic-gate 	}
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate       gateA20 (0);
3227c478bd9Sstevel@tonic-gate       boot_drive = saved_drive;
3237c478bd9Sstevel@tonic-gate       chain_stage1 (0, BOOTSEC_LOCATION, boot_part_addr);
3247c478bd9Sstevel@tonic-gate       break;
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_MULTIBOOT:
3277c478bd9Sstevel@tonic-gate       /* Multiboot */
3287c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
3297c478bd9Sstevel@tonic-gate #ifdef SOLARIS_NETBOOT
3307c478bd9Sstevel@tonic-gate       if (current_drive == NETWORK_DRIVE) {
3317c478bd9Sstevel@tonic-gate     	/*
3327c478bd9Sstevel@tonic-gate 	 *  XXX Solaris hack: use drive_info to pass network information
3337c478bd9Sstevel@tonic-gate 	 *  Turn off the flag bit to the loader is technically
3347c478bd9Sstevel@tonic-gate 	 *  multiboot compliant.
3357c478bd9Sstevel@tonic-gate 	 */
3367c478bd9Sstevel@tonic-gate     	mbi.flags &= ~MB_INFO_DRIVE_INFO;
3377c478bd9Sstevel@tonic-gate   	mbi.drives_length = dhcpack_length;
3387c478bd9Sstevel@tonic-gate   	mbi.drives_addr = dhcpack_buf;
3397c478bd9Sstevel@tonic-gate       }
3407c478bd9Sstevel@tonic-gate #endif /* SOLARIS_NETBOOT */
3417c478bd9Sstevel@tonic-gate #endif
3427c478bd9Sstevel@tonic-gate       multi_boot ((int) entry_addr, (int) &mbi);
3437c478bd9Sstevel@tonic-gate       break;
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate     default:
3467c478bd9Sstevel@tonic-gate       errnum = ERR_BOOT_COMMAND;
3477c478bd9Sstevel@tonic-gate       return 1;
3487c478bd9Sstevel@tonic-gate     }
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate   return 0;
3517c478bd9Sstevel@tonic-gate }
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate static struct builtin builtin_boot =
3547c478bd9Sstevel@tonic-gate {
3557c478bd9Sstevel@tonic-gate   "boot",
3567c478bd9Sstevel@tonic-gate   boot_func,
3577c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
3587c478bd9Sstevel@tonic-gate   "boot",
3597c478bd9Sstevel@tonic-gate   "Boot the OS/chain-loader which has been loaded."
3607c478bd9Sstevel@tonic-gate };
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
3647c478bd9Sstevel@tonic-gate /* bootp */
3657c478bd9Sstevel@tonic-gate static int
3667c478bd9Sstevel@tonic-gate bootp_func (char *arg, int flags)
3677c478bd9Sstevel@tonic-gate {
3687c478bd9Sstevel@tonic-gate   int with_configfile = 0;
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate   if (grub_memcmp (arg, "--with-configfile", sizeof ("--with-configfile") - 1)
3717c478bd9Sstevel@tonic-gate       == 0)
3727c478bd9Sstevel@tonic-gate     {
3737c478bd9Sstevel@tonic-gate       with_configfile = 1;
3747c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
3757c478bd9Sstevel@tonic-gate     }
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate   if (! bootp ())
3787c478bd9Sstevel@tonic-gate     {
3797c478bd9Sstevel@tonic-gate       if (errnum == ERR_NONE)
3807c478bd9Sstevel@tonic-gate 	errnum = ERR_DEV_VALUES;
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate       return 1;
3837c478bd9Sstevel@tonic-gate     }
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate   /* Notify the configuration.  */
3867c478bd9Sstevel@tonic-gate   print_network_configuration ();
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate   /* XXX: this can cause an endless loop, but there is no easy way to
3897c478bd9Sstevel@tonic-gate      detect such a loop unfortunately.  */
3907c478bd9Sstevel@tonic-gate   if (with_configfile)
3917c478bd9Sstevel@tonic-gate     configfile_func (config_file, flags);
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate   return 0;
3947c478bd9Sstevel@tonic-gate }
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate static struct builtin builtin_bootp =
3977c478bd9Sstevel@tonic-gate {
3987c478bd9Sstevel@tonic-gate   "bootp",
3997c478bd9Sstevel@tonic-gate   bootp_func,
4007c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
4017c478bd9Sstevel@tonic-gate   "bootp [--with-configfile]",
4027c478bd9Sstevel@tonic-gate   "Initialize a network device via BOOTP. If the option `--with-configfile'"
4037c478bd9Sstevel@tonic-gate   " is given, try to load a configuration file specified by the 150 vendor"
4047c478bd9Sstevel@tonic-gate   " tag."
4057c478bd9Sstevel@tonic-gate };
4067c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate /* cat */
4107c478bd9Sstevel@tonic-gate static int
4117c478bd9Sstevel@tonic-gate cat_func (char *arg, int flags)
4127c478bd9Sstevel@tonic-gate {
4137c478bd9Sstevel@tonic-gate   char c;
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate   if (! grub_open (arg))
4167c478bd9Sstevel@tonic-gate     return 1;
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate   while (grub_read (&c, 1))
4197c478bd9Sstevel@tonic-gate     {
4207c478bd9Sstevel@tonic-gate       /* Because running "cat" with a binary file can confuse the terminal,
4217c478bd9Sstevel@tonic-gate 	 print only some characters as they are.  */
4227c478bd9Sstevel@tonic-gate       if (grub_isspace (c) || (c >= ' ' && c <= '~'))
4237c478bd9Sstevel@tonic-gate 	grub_putchar (c);
4247c478bd9Sstevel@tonic-gate       else
4257c478bd9Sstevel@tonic-gate 	grub_putchar ('?');
4267c478bd9Sstevel@tonic-gate     }
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate   grub_close ();
4297c478bd9Sstevel@tonic-gate   return 0;
4307c478bd9Sstevel@tonic-gate }
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate static struct builtin builtin_cat =
4337c478bd9Sstevel@tonic-gate {
4347c478bd9Sstevel@tonic-gate   "cat",
4357c478bd9Sstevel@tonic-gate   cat_func,
4367c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
4377c478bd9Sstevel@tonic-gate   "cat FILE",
4387c478bd9Sstevel@tonic-gate   "Print the contents of the file FILE."
4397c478bd9Sstevel@tonic-gate };
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate /* chainloader */
4437c478bd9Sstevel@tonic-gate static int
4447c478bd9Sstevel@tonic-gate chainloader_func (char *arg, int flags)
4457c478bd9Sstevel@tonic-gate {
4467c478bd9Sstevel@tonic-gate   int force = 0;
4477c478bd9Sstevel@tonic-gate   char *file = arg;
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate   /* If the option `--force' is specified?  */
4507c478bd9Sstevel@tonic-gate   if (substring ("--force", arg) <= 0)
4517c478bd9Sstevel@tonic-gate     {
4527c478bd9Sstevel@tonic-gate       force = 1;
4537c478bd9Sstevel@tonic-gate       file = skip_to (0, arg);
4547c478bd9Sstevel@tonic-gate     }
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate   /* Open the file.  */
4577c478bd9Sstevel@tonic-gate   if (! grub_open (file))
4587c478bd9Sstevel@tonic-gate     {
4597c478bd9Sstevel@tonic-gate       kernel_type = KERNEL_TYPE_NONE;
4607c478bd9Sstevel@tonic-gate       return 1;
4617c478bd9Sstevel@tonic-gate     }
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate   /* Read the first block.  */
4647c478bd9Sstevel@tonic-gate   if (grub_read ((char *) BOOTSEC_LOCATION, SECTOR_SIZE) != SECTOR_SIZE)
4657c478bd9Sstevel@tonic-gate     {
4667c478bd9Sstevel@tonic-gate       grub_close ();
4677c478bd9Sstevel@tonic-gate       kernel_type = KERNEL_TYPE_NONE;
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate       /* This below happens, if a file whose size is less than 512 bytes
4707c478bd9Sstevel@tonic-gate 	 is loaded.  */
4717c478bd9Sstevel@tonic-gate       if (errnum == ERR_NONE)
4727c478bd9Sstevel@tonic-gate 	errnum = ERR_EXEC_FORMAT;
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate       return 1;
4757c478bd9Sstevel@tonic-gate     }
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate   /* If not loading it forcibly, check for the signature.  */
4787c478bd9Sstevel@tonic-gate   if (! force
4797c478bd9Sstevel@tonic-gate       && (*((unsigned short *) (BOOTSEC_LOCATION + BOOTSEC_SIG_OFFSET))
4807c478bd9Sstevel@tonic-gate 	  != BOOTSEC_SIGNATURE))
4817c478bd9Sstevel@tonic-gate     {
4827c478bd9Sstevel@tonic-gate       grub_close ();
4837c478bd9Sstevel@tonic-gate       errnum = ERR_EXEC_FORMAT;
4847c478bd9Sstevel@tonic-gate       kernel_type = KERNEL_TYPE_NONE;
4857c478bd9Sstevel@tonic-gate       return 1;
4867c478bd9Sstevel@tonic-gate     }
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate   grub_close ();
4897c478bd9Sstevel@tonic-gate   kernel_type = KERNEL_TYPE_CHAINLOADER;
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate   /* XXX: Windows evil hack. For now, only the first five letters are
4927c478bd9Sstevel@tonic-gate      checked.  */
4937c478bd9Sstevel@tonic-gate   if (IS_PC_SLICE_TYPE_FAT (current_slice)
4947c478bd9Sstevel@tonic-gate       && ! grub_memcmp ((char *) BOOTSEC_LOCATION + BOOTSEC_BPB_SYSTEM_ID,
4957c478bd9Sstevel@tonic-gate 			"MSWIN", 5))
4967c478bd9Sstevel@tonic-gate     *((unsigned long *) (BOOTSEC_LOCATION + BOOTSEC_BPB_HIDDEN_SECTORS))
4977c478bd9Sstevel@tonic-gate       = part_start;
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate   errnum = ERR_NONE;
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate   return 0;
5027c478bd9Sstevel@tonic-gate }
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate static struct builtin builtin_chainloader =
5057c478bd9Sstevel@tonic-gate {
5067c478bd9Sstevel@tonic-gate   "chainloader",
5077c478bd9Sstevel@tonic-gate   chainloader_func,
5087c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
5097c478bd9Sstevel@tonic-gate   "chainloader [--force] FILE",
5107c478bd9Sstevel@tonic-gate   "Load the chain-loader FILE. If --force is specified, then load it"
5117c478bd9Sstevel@tonic-gate   " forcibly, whether the boot loader signature is present or not."
5127c478bd9Sstevel@tonic-gate };
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate /* This function could be used to debug new filesystem code. Put a file
5167c478bd9Sstevel@tonic-gate    in the new filesystem and the same file in a well-tested filesystem.
5177c478bd9Sstevel@tonic-gate    Then, run "cmp" with the files. If no output is obtained, probably
5187c478bd9Sstevel@tonic-gate    the code is good, otherwise investigate what's wrong...  */
5197c478bd9Sstevel@tonic-gate /* cmp FILE1 FILE2 */
5207c478bd9Sstevel@tonic-gate static int
5217c478bd9Sstevel@tonic-gate cmp_func (char *arg, int flags)
5227c478bd9Sstevel@tonic-gate {
5237c478bd9Sstevel@tonic-gate   /* The filenames.  */
5247c478bd9Sstevel@tonic-gate   char *file1, *file2;
5257c478bd9Sstevel@tonic-gate   /* The addresses.  */
5267c478bd9Sstevel@tonic-gate   char *addr1, *addr2;
5277c478bd9Sstevel@tonic-gate   int i;
5287c478bd9Sstevel@tonic-gate   /* The size of the file.  */
5297c478bd9Sstevel@tonic-gate   int size;
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate   /* Get the filenames from ARG.  */
5327c478bd9Sstevel@tonic-gate   file1 = arg;
5337c478bd9Sstevel@tonic-gate   file2 = skip_to (0, arg);
5347c478bd9Sstevel@tonic-gate   if (! *file1 || ! *file2)
5357c478bd9Sstevel@tonic-gate     {
5367c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
5377c478bd9Sstevel@tonic-gate       return 1;
5387c478bd9Sstevel@tonic-gate     }
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate   /* Terminate the filenames for convenience.  */
5417c478bd9Sstevel@tonic-gate   nul_terminate (file1);
5427c478bd9Sstevel@tonic-gate   nul_terminate (file2);
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate   /* Read the whole data from FILE1.  */
5457c478bd9Sstevel@tonic-gate   addr1 = (char *) RAW_ADDR (0x100000);
5467c478bd9Sstevel@tonic-gate   if (! grub_open (file1))
5477c478bd9Sstevel@tonic-gate     return 1;
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate   /* Get the size.  */
5507c478bd9Sstevel@tonic-gate   size = filemax;
5517c478bd9Sstevel@tonic-gate   if (grub_read (addr1, -1) != size)
5527c478bd9Sstevel@tonic-gate     {
5537c478bd9Sstevel@tonic-gate       grub_close ();
5547c478bd9Sstevel@tonic-gate       return 1;
5557c478bd9Sstevel@tonic-gate     }
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate   grub_close ();
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate   /* Read the whole data from FILE2.  */
5607c478bd9Sstevel@tonic-gate   addr2 = addr1 + size;
5617c478bd9Sstevel@tonic-gate   if (! grub_open (file2))
5627c478bd9Sstevel@tonic-gate     return 1;
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate   /* Check if the size of FILE2 is equal to the one of FILE2.  */
5657c478bd9Sstevel@tonic-gate   if (size != filemax)
5667c478bd9Sstevel@tonic-gate     {
5677c478bd9Sstevel@tonic-gate       grub_printf ("Differ in size: 0x%x [%s], 0x%x [%s]\n",
5687c478bd9Sstevel@tonic-gate 		   size, file1, filemax, file2);
5697c478bd9Sstevel@tonic-gate       grub_close ();
5707c478bd9Sstevel@tonic-gate       return 0;
5717c478bd9Sstevel@tonic-gate     }
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate   if (! grub_read (addr2, -1))
5747c478bd9Sstevel@tonic-gate     {
5757c478bd9Sstevel@tonic-gate       grub_close ();
5767c478bd9Sstevel@tonic-gate       return 1;
5777c478bd9Sstevel@tonic-gate     }
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate   grub_close ();
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate   /* Now compare ADDR1 with ADDR2.  */
5827c478bd9Sstevel@tonic-gate   for (i = 0; i < size; i++)
5837c478bd9Sstevel@tonic-gate     {
5847c478bd9Sstevel@tonic-gate       if (addr1[i] != addr2[i])
5857c478bd9Sstevel@tonic-gate 	grub_printf ("Differ at the offset %d: 0x%x [%s], 0x%x [%s]\n",
5867c478bd9Sstevel@tonic-gate 		     i, (unsigned) addr1[i], file1,
5877c478bd9Sstevel@tonic-gate 		     (unsigned) addr2[i], file2);
5887c478bd9Sstevel@tonic-gate     }
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate   return 0;
5917c478bd9Sstevel@tonic-gate }
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate static struct builtin builtin_cmp =
5947c478bd9Sstevel@tonic-gate {
5957c478bd9Sstevel@tonic-gate   "cmp",
5967c478bd9Sstevel@tonic-gate   cmp_func,
5977c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
5987c478bd9Sstevel@tonic-gate   "cmp FILE1 FILE2",
5997c478bd9Sstevel@tonic-gate   "Compare the file FILE1 with the FILE2 and inform the different values"
6007c478bd9Sstevel@tonic-gate   " if any."
6017c478bd9Sstevel@tonic-gate };
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate /* color */
6057c478bd9Sstevel@tonic-gate /* Set new colors used for the menu interface. Support two methods to
6067c478bd9Sstevel@tonic-gate    specify a color name: a direct integer representation and a symbolic
6077c478bd9Sstevel@tonic-gate    color name. An example of the latter is "blink-light-gray/blue".  */
6087c478bd9Sstevel@tonic-gate static int
6097c478bd9Sstevel@tonic-gate color_func (char *arg, int flags)
6107c478bd9Sstevel@tonic-gate {
6117c478bd9Sstevel@tonic-gate   char *normal;
6127c478bd9Sstevel@tonic-gate   char *highlight;
6137c478bd9Sstevel@tonic-gate   int new_normal_color;
6147c478bd9Sstevel@tonic-gate   int new_highlight_color;
6157c478bd9Sstevel@tonic-gate   static char *color_list[16] =
6167c478bd9Sstevel@tonic-gate   {
6177c478bd9Sstevel@tonic-gate     "black",
6187c478bd9Sstevel@tonic-gate     "blue",
6197c478bd9Sstevel@tonic-gate     "green",
6207c478bd9Sstevel@tonic-gate     "cyan",
6217c478bd9Sstevel@tonic-gate     "red",
6227c478bd9Sstevel@tonic-gate     "magenta",
6237c478bd9Sstevel@tonic-gate     "brown",
6247c478bd9Sstevel@tonic-gate     "light-gray",
6257c478bd9Sstevel@tonic-gate     "dark-gray",
6267c478bd9Sstevel@tonic-gate     "light-blue",
6277c478bd9Sstevel@tonic-gate     "light-green",
6287c478bd9Sstevel@tonic-gate     "light-cyan",
6297c478bd9Sstevel@tonic-gate     "light-red",
6307c478bd9Sstevel@tonic-gate     "light-magenta",
6317c478bd9Sstevel@tonic-gate     "yellow",
6327c478bd9Sstevel@tonic-gate     "white"
6337c478bd9Sstevel@tonic-gate   };
6347c478bd9Sstevel@tonic-gate 
6351b8adde7SWilliam Kucharski   auto int color_number (char *str);
6361b8adde7SWilliam Kucharski 
6377c478bd9Sstevel@tonic-gate   /* Convert the color name STR into the magical number.  */
6381b8adde7SWilliam Kucharski   auto int color_number (char *str)
6397c478bd9Sstevel@tonic-gate     {
6407c478bd9Sstevel@tonic-gate       char *ptr;
6417c478bd9Sstevel@tonic-gate       int i;
6427c478bd9Sstevel@tonic-gate       int color = 0;
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate       /* Find the separator.  */
6457c478bd9Sstevel@tonic-gate       for (ptr = str; *ptr && *ptr != '/'; ptr++)
6467c478bd9Sstevel@tonic-gate 	;
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate       /* If not found, return -1.  */
6497c478bd9Sstevel@tonic-gate       if (! *ptr)
6507c478bd9Sstevel@tonic-gate 	return -1;
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate       /* Terminate the string STR.  */
6537c478bd9Sstevel@tonic-gate       *ptr++ = 0;
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate       /* If STR contains the prefix "blink-", then set the `blink' bit
6567c478bd9Sstevel@tonic-gate 	 in COLOR.  */
6577c478bd9Sstevel@tonic-gate       if (substring ("blink-", str) <= 0)
6587c478bd9Sstevel@tonic-gate 	{
6597c478bd9Sstevel@tonic-gate 	  color = 0x80;
6607c478bd9Sstevel@tonic-gate 	  str += 6;
6617c478bd9Sstevel@tonic-gate 	}
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate       /* Search for the color name.  */
6647c478bd9Sstevel@tonic-gate       for (i = 0; i < 16; i++)
6657c478bd9Sstevel@tonic-gate 	if (grub_strcmp (color_list[i], str) == 0)
6667c478bd9Sstevel@tonic-gate 	  {
6677c478bd9Sstevel@tonic-gate 	    color |= i;
6687c478bd9Sstevel@tonic-gate 	    break;
6697c478bd9Sstevel@tonic-gate 	  }
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate       if (i == 16)
6727c478bd9Sstevel@tonic-gate 	return -1;
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate       str = ptr;
6757c478bd9Sstevel@tonic-gate       nul_terminate (str);
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate       /* Search for the color name.  */
6787c478bd9Sstevel@tonic-gate       for (i = 0; i < 8; i++)
6797c478bd9Sstevel@tonic-gate 	if (grub_strcmp (color_list[i], str) == 0)
6807c478bd9Sstevel@tonic-gate 	  {
6817c478bd9Sstevel@tonic-gate 	    color |= i << 4;
6827c478bd9Sstevel@tonic-gate 	    break;
6837c478bd9Sstevel@tonic-gate 	  }
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate       if (i == 8)
6867c478bd9Sstevel@tonic-gate 	return -1;
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate       return color;
6897c478bd9Sstevel@tonic-gate     }
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate   normal = arg;
6927c478bd9Sstevel@tonic-gate   highlight = skip_to (0, arg);
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate   new_normal_color = color_number (normal);
6957c478bd9Sstevel@tonic-gate   if (new_normal_color < 0 && ! safe_parse_maxint (&normal, &new_normal_color))
6967c478bd9Sstevel@tonic-gate     return 1;
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate   /* The second argument is optional, so set highlight_color
6997c478bd9Sstevel@tonic-gate      to inverted NORMAL_COLOR.  */
7007c478bd9Sstevel@tonic-gate   if (! *highlight)
7017c478bd9Sstevel@tonic-gate     new_highlight_color = ((new_normal_color >> 4)
7027c478bd9Sstevel@tonic-gate 			   | ((new_normal_color & 0xf) << 4));
7037c478bd9Sstevel@tonic-gate   else
7047c478bd9Sstevel@tonic-gate     {
7057c478bd9Sstevel@tonic-gate       new_highlight_color = color_number (highlight);
7067c478bd9Sstevel@tonic-gate       if (new_highlight_color < 0
7077c478bd9Sstevel@tonic-gate 	  && ! safe_parse_maxint (&highlight, &new_highlight_color))
7087c478bd9Sstevel@tonic-gate 	return 1;
7097c478bd9Sstevel@tonic-gate     }
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate   if (current_term->setcolor)
7127c478bd9Sstevel@tonic-gate     current_term->setcolor (new_normal_color, new_highlight_color);
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate   return 0;
7157c478bd9Sstevel@tonic-gate }
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate static struct builtin builtin_color =
7187c478bd9Sstevel@tonic-gate {
7197c478bd9Sstevel@tonic-gate   "color",
7207c478bd9Sstevel@tonic-gate   color_func,
7217c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
7227c478bd9Sstevel@tonic-gate   "color NORMAL [HIGHLIGHT]",
7237c478bd9Sstevel@tonic-gate   "Change the menu colors. The color NORMAL is used for most"
7247c478bd9Sstevel@tonic-gate   " lines in the menu, and the color HIGHLIGHT is used to highlight the"
7257c478bd9Sstevel@tonic-gate   " line where the cursor points. If you omit HIGHLIGHT, then the"
7267c478bd9Sstevel@tonic-gate   " inverted color of NORMAL is used for the highlighted line."
7277c478bd9Sstevel@tonic-gate   " The format of a color is \"FG/BG\". FG and BG are symbolic color names."
7287c478bd9Sstevel@tonic-gate   " A symbolic color name must be one of these: black, blue, green,"
7297c478bd9Sstevel@tonic-gate   " cyan, red, magenta, brown, light-gray, dark-gray, light-blue,"
7307c478bd9Sstevel@tonic-gate   " light-green, light-cyan, light-red, light-magenta, yellow and white."
7317c478bd9Sstevel@tonic-gate   " But only the first eight names can be used for BG. You can prefix"
7327c478bd9Sstevel@tonic-gate   " \"blink-\" to FG if you want a blinking foreground color."
7337c478bd9Sstevel@tonic-gate };
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate /* configfile */
7377c478bd9Sstevel@tonic-gate static int
7387c478bd9Sstevel@tonic-gate configfile_func (char *arg, int flags)
7397c478bd9Sstevel@tonic-gate {
7407c478bd9Sstevel@tonic-gate   char *new_config = config_file;
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate   /* Check if the file ARG is present.  */
7437c478bd9Sstevel@tonic-gate   if (! grub_open (arg))
7447c478bd9Sstevel@tonic-gate     return 1;
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate   grub_close ();
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate   /* Copy ARG to CONFIG_FILE.  */
7497c478bd9Sstevel@tonic-gate   while ((*new_config++ = *arg++) != 0)
7507c478bd9Sstevel@tonic-gate     ;
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
7537c478bd9Sstevel@tonic-gate   /* Force to load the configuration file.  */
7547c478bd9Sstevel@tonic-gate   use_config_file = 1;
7557c478bd9Sstevel@tonic-gate #endif
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate   /* Make sure that the user will not be authoritative.  */
7587c478bd9Sstevel@tonic-gate   auth = 0;
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate   /* Restart cmain.  */
7617c478bd9Sstevel@tonic-gate   grub_longjmp (restart_env, 0);
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate   /* Never reach here.  */
7647c478bd9Sstevel@tonic-gate   return 0;
7657c478bd9Sstevel@tonic-gate }
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate static struct builtin builtin_configfile =
7687c478bd9Sstevel@tonic-gate {
7697c478bd9Sstevel@tonic-gate   "configfile",
7707c478bd9Sstevel@tonic-gate   configfile_func,
7717c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
7727c478bd9Sstevel@tonic-gate   "configfile FILE",
7737c478bd9Sstevel@tonic-gate   "Load FILE as the configuration file."
7747c478bd9Sstevel@tonic-gate };
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate /* debug */
7787c478bd9Sstevel@tonic-gate static int
7797c478bd9Sstevel@tonic-gate debug_func (char *arg, int flags)
7807c478bd9Sstevel@tonic-gate {
7817c478bd9Sstevel@tonic-gate   if (debug)
7827c478bd9Sstevel@tonic-gate     {
7837c478bd9Sstevel@tonic-gate       debug = 0;
7847c478bd9Sstevel@tonic-gate       grub_printf (" Debug mode is turned off\n");
7857c478bd9Sstevel@tonic-gate     }
7867c478bd9Sstevel@tonic-gate   else
7877c478bd9Sstevel@tonic-gate     {
7887c478bd9Sstevel@tonic-gate       debug = 1;
7897c478bd9Sstevel@tonic-gate       grub_printf (" Debug mode is turned on\n");
7907c478bd9Sstevel@tonic-gate     }
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate   return 0;
7937c478bd9Sstevel@tonic-gate }
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate static struct builtin builtin_debug =
7967c478bd9Sstevel@tonic-gate {
7977c478bd9Sstevel@tonic-gate   "debug",
7987c478bd9Sstevel@tonic-gate   debug_func,
7997c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
8007c478bd9Sstevel@tonic-gate   "debug",
8017c478bd9Sstevel@tonic-gate   "Turn on/off the debug mode."
8027c478bd9Sstevel@tonic-gate };
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate /* default */
8067c478bd9Sstevel@tonic-gate static int
8077c478bd9Sstevel@tonic-gate default_func (char *arg, int flags)
8087c478bd9Sstevel@tonic-gate {
8097c478bd9Sstevel@tonic-gate #ifndef SUPPORT_DISKLESS
8107c478bd9Sstevel@tonic-gate   if (grub_strcmp (arg, "saved") == 0)
8117c478bd9Sstevel@tonic-gate     {
8127c478bd9Sstevel@tonic-gate       default_entry = saved_entryno;
8137c478bd9Sstevel@tonic-gate       return 0;
8147c478bd9Sstevel@tonic-gate     }
8157c478bd9Sstevel@tonic-gate #endif /* SUPPORT_DISKLESS */
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &default_entry))
8187c478bd9Sstevel@tonic-gate     return 1;
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate   return 0;
8217c478bd9Sstevel@tonic-gate }
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate static struct builtin builtin_default =
8247c478bd9Sstevel@tonic-gate {
8257c478bd9Sstevel@tonic-gate   "default",
8267c478bd9Sstevel@tonic-gate   default_func,
8277c478bd9Sstevel@tonic-gate   BUILTIN_MENU,
8287c478bd9Sstevel@tonic-gate #if 0
8297c478bd9Sstevel@tonic-gate   "default [NUM | `saved']",
8307c478bd9Sstevel@tonic-gate   "Set the default entry to entry number NUM (if not specified, it is"
8317c478bd9Sstevel@tonic-gate   " 0, the first entry) or the entry number saved by savedefault."
8327c478bd9Sstevel@tonic-gate #endif
8337c478bd9Sstevel@tonic-gate };
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
8377c478bd9Sstevel@tonic-gate /* device */
8387c478bd9Sstevel@tonic-gate static int
8397c478bd9Sstevel@tonic-gate device_func (char *arg, int flags)
8407c478bd9Sstevel@tonic-gate {
8417c478bd9Sstevel@tonic-gate   char *drive = arg;
8427c478bd9Sstevel@tonic-gate   char *device;
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate   /* Get the drive number from DRIVE.  */
8457c478bd9Sstevel@tonic-gate   if (! set_device (drive))
8467c478bd9Sstevel@tonic-gate     return 1;
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate   /* Get the device argument.  */
8497c478bd9Sstevel@tonic-gate   device = skip_to (0, drive);
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate   /* Terminate DEVICE.  */
8527c478bd9Sstevel@tonic-gate   nul_terminate (device);
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate   if (! *device || ! check_device (device))
8557c478bd9Sstevel@tonic-gate     {
8567c478bd9Sstevel@tonic-gate       errnum = ERR_FILE_NOT_FOUND;
8577c478bd9Sstevel@tonic-gate       return 1;
8587c478bd9Sstevel@tonic-gate     }
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate   assign_device_name (current_drive, device);
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate   return 0;
8637c478bd9Sstevel@tonic-gate }
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate static struct builtin builtin_device =
8667c478bd9Sstevel@tonic-gate {
8677c478bd9Sstevel@tonic-gate   "device",
8687c478bd9Sstevel@tonic-gate   device_func,
8697c478bd9Sstevel@tonic-gate   BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
8707c478bd9Sstevel@tonic-gate   "device DRIVE DEVICE",
8717c478bd9Sstevel@tonic-gate   "Specify DEVICE as the actual drive for a BIOS drive DRIVE. This command"
8727c478bd9Sstevel@tonic-gate   " can be used only in the grub shell."
8737c478bd9Sstevel@tonic-gate };
8747c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
8757c478bd9Sstevel@tonic-gate 
8767c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
8777c478bd9Sstevel@tonic-gate /* Debug Function for RPC */
8787c478bd9Sstevel@tonic-gate #ifdef RPC_DEBUG
8797c478bd9Sstevel@tonic-gate /* portmap */
8807c478bd9Sstevel@tonic-gate static int
8817c478bd9Sstevel@tonic-gate portmap_func (char *arg, int flags)
8827c478bd9Sstevel@tonic-gate {
8837c478bd9Sstevel@tonic-gate 	int port, prog, ver;
8847c478bd9Sstevel@tonic-gate 	if (! grub_eth_probe ()){
8857c478bd9Sstevel@tonic-gate 		grub_printf ("No ethernet card found.\n");
8867c478bd9Sstevel@tonic-gate 		errnum = ERR_DEV_VALUES;
8877c478bd9Sstevel@tonic-gate 		return 1;
8887c478bd9Sstevel@tonic-gate 	}
8897c478bd9Sstevel@tonic-gate 	if ((prog = getdec(&arg)) == -1){
8907c478bd9Sstevel@tonic-gate 		grub_printf("Error prog number\n");
8917c478bd9Sstevel@tonic-gate 		return 1;
8927c478bd9Sstevel@tonic-gate 	}
8937c478bd9Sstevel@tonic-gate 	arg = skip_to (0, arg);
8947c478bd9Sstevel@tonic-gate 	if ((ver = getdec(&arg)) == -1){
8957c478bd9Sstevel@tonic-gate 		grub_printf("Error ver number\n");
8967c478bd9Sstevel@tonic-gate 		return 1;
8977c478bd9Sstevel@tonic-gate 	}
8987c478bd9Sstevel@tonic-gate 	port = __pmapudp_getport(ARP_SERVER, prog, ver);
8997c478bd9Sstevel@tonic-gate 	printf("portmap getport %d", port);
9007c478bd9Sstevel@tonic-gate 	return 0;
9017c478bd9Sstevel@tonic-gate }
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate static struct builtin builtin_portmap =
9047c478bd9Sstevel@tonic-gate {
9057c478bd9Sstevel@tonic-gate 	"portmap",
9067c478bd9Sstevel@tonic-gate 	portmap_func,
9077c478bd9Sstevel@tonic-gate 	BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
9087c478bd9Sstevel@tonic-gate 	"portmap prog_number vers_number",
9097c478bd9Sstevel@tonic-gate 	"Do portmap with the prog_number and vers_number"
9107c478bd9Sstevel@tonic-gate };
9117c478bd9Sstevel@tonic-gate #endif /* RPC_DEBUG */
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate /* dhcp */
9147c478bd9Sstevel@tonic-gate static int
9157c478bd9Sstevel@tonic-gate dhcp_func (char *arg, int flags)
9167c478bd9Sstevel@tonic-gate {
9177c478bd9Sstevel@tonic-gate   int with_configfile = 0;
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate   if (grub_memcmp (arg, "--with-configfile", sizeof ("--with-configfile") - 1)
9207c478bd9Sstevel@tonic-gate       == 0)
9217c478bd9Sstevel@tonic-gate     {
9227c478bd9Sstevel@tonic-gate       with_configfile = 1;
9237c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
9247c478bd9Sstevel@tonic-gate     }
9257c478bd9Sstevel@tonic-gate 
9267c478bd9Sstevel@tonic-gate   if (! dhcp ())
9277c478bd9Sstevel@tonic-gate     {
9287c478bd9Sstevel@tonic-gate       if (errnum == ERR_NONE)
9297c478bd9Sstevel@tonic-gate 	errnum = ERR_DEV_VALUES;
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate       return 1;
9327c478bd9Sstevel@tonic-gate     }
9337c478bd9Sstevel@tonic-gate 
9347c478bd9Sstevel@tonic-gate   /* Notify the configuration.  */
9357c478bd9Sstevel@tonic-gate   print_network_configuration ();
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate   /* XXX: this can cause an endless loop, but there is no easy way to
9387c478bd9Sstevel@tonic-gate      detect such a loop unfortunately.  */
9397c478bd9Sstevel@tonic-gate   if (with_configfile)
9407c478bd9Sstevel@tonic-gate     configfile_func (config_file, flags);
9417c478bd9Sstevel@tonic-gate   else
9427c478bd9Sstevel@tonic-gate     solaris_config_file();
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate   return 0;
9457c478bd9Sstevel@tonic-gate }
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate static void solaris_config_file (void)
9487c478bd9Sstevel@tonic-gate {
9497c478bd9Sstevel@tonic-gate 	static char menufile[64];
9507c478bd9Sstevel@tonic-gate 	static char hexdigit[] = "0123456789ABCDEF";
9517c478bd9Sstevel@tonic-gate 	char *c = menufile;
9527c478bd9Sstevel@tonic-gate 	int i;
9536759d08fScasper 	int err;
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 	/* if config_file is from DHCP option 150, keep the setting */
9567c478bd9Sstevel@tonic-gate 	if (grub_strcmp(config_file, "/boot/grub/menu.lst") != 0)
9577c478bd9Sstevel@tonic-gate 		return;
9587c478bd9Sstevel@tonic-gate 
9592269adc8Sszhou 	/* default solaris configfile name menu.lst.01<ether_addr> */
9602269adc8Sszhou 	grub_strcpy(c, "menu.lst.01");
9617c478bd9Sstevel@tonic-gate 	c += grub_strlen(c);
9627c478bd9Sstevel@tonic-gate 	for (i = 0; i < ETH_ALEN; i++) {
9637c478bd9Sstevel@tonic-gate 		unsigned char b = arptable[ARP_CLIENT].node[i];
9647c478bd9Sstevel@tonic-gate 		*c++ = hexdigit[b >> 4];
9657c478bd9Sstevel@tonic-gate 		*c++ = hexdigit[b & 0xf];
9667c478bd9Sstevel@tonic-gate 	}
9677c478bd9Sstevel@tonic-gate 	*c = 0;
9687c478bd9Sstevel@tonic-gate 
9696759d08fScasper 	/*
9706759d08fScasper 	 * If the file exists, make it the default. Else, fallback
9716759d08fScasper 	 * to what it was.  Make sure we don't change errnum in the
9726759d08fScasper 	 * process.
9737c478bd9Sstevel@tonic-gate 	 */
9746759d08fScasper 	err = errnum;
9757c478bd9Sstevel@tonic-gate 	if (grub_open(menufile)) {
9767c478bd9Sstevel@tonic-gate 		grub_strcpy(config_file, menufile);
9777c478bd9Sstevel@tonic-gate 		grub_close();
9782269adc8Sszhou 	} else {
9792269adc8Sszhou 		char *cp = config_file;
9802269adc8Sszhou 		/* skip leading slashes for tftp */
981266095caSszhou 		while (*cp == '/')
982266095caSszhou 			++cp;
9832269adc8Sszhou 	  	grub_memmove (config_file, cp, strlen(cp) + 1);
9847c478bd9Sstevel@tonic-gate 	}
9856759d08fScasper 	errnum = err;
9867c478bd9Sstevel@tonic-gate }
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate static struct builtin builtin_dhcp =
9897c478bd9Sstevel@tonic-gate {
9907c478bd9Sstevel@tonic-gate   "dhcp",
9917c478bd9Sstevel@tonic-gate   dhcp_func,
9927c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
9937c478bd9Sstevel@tonic-gate   "dhcp",
9947c478bd9Sstevel@tonic-gate   "Initialize a network device via DHCP."
9957c478bd9Sstevel@tonic-gate };
9967c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
9977c478bd9Sstevel@tonic-gate 
9987c478bd9Sstevel@tonic-gate static int terminal_func (char *arg, int flags);
9997c478bd9Sstevel@tonic-gate 
10001fac5a60Ssetje static int verbose_func(char *arg, int flags) {
10011fac5a60Ssetje 
10021fac5a60Ssetje     if (grub_strcmp(arg, "off") == 0) {
10031fac5a60Ssetje       silent.status = DEFER_SILENT;
10041fac5a60Ssetje       return;
10051fac5a60Ssetje     } else
10061fac5a60Ssetje         if (flags == BUILTIN_CMDLINE) {
10071fac5a60Ssetje           silent.status = DEFER_VERBOSE;
10081fac5a60Ssetje           return;
10091fac5a60Ssetje         }
10101fac5a60Ssetje 
10111fac5a60Ssetje   silent.status = VERBOSE;
10121fac5a60Ssetje 
1013ae115bc7Smrj   /* get back to text console */
10141fac5a60Ssetje   if (current_term->shutdown) {
10151fac5a60Ssetje     (*current_term->shutdown)();
10161fac5a60Ssetje     current_term = term_table; /* assumption: console is first */
10171fac5a60Ssetje   }
10181fac5a60Ssetje 
10191fac5a60Ssetje   /* dump the buffer */
10201fac5a60Ssetje   if (!silent.looped) {
10211fac5a60Ssetje     /* if the buffer hasn't looped, just print it */
10221fac5a60Ssetje     printf("%s", silent.buffer);
10231fac5a60Ssetje   } else {
10241fac5a60Ssetje     /*
10251fac5a60Ssetje      * If the buffer has looped, first print the oldest part of the buffer,
10261fac5a60Ssetje      * which is one past the current null. Then print the newer part which
10271fac5a60Ssetje      * starts at the beginning of the buffer.
10281fac5a60Ssetje      */
10291fac5a60Ssetje     printf("%s", silent.buffer_start + 1);
10301fac5a60Ssetje     printf("%s", silent.buffer);
10311fac5a60Ssetje   }
10321fac5a60Ssetje 
10331fac5a60Ssetje   return 0;
10341fac5a60Ssetje }
10351fac5a60Ssetje 
10361fac5a60Ssetje static struct builtin builtin_verbose =
10371fac5a60Ssetje {
10381fac5a60Ssetje   "verbose",
10391fac5a60Ssetje   verbose_func,
10401fac5a60Ssetje   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_SCRIPT | BUILTIN_HELP_LIST,
10411fac5a60Ssetje   "verbose",
10421fac5a60Ssetje   "Verbose output during menu entry (script) execution."
10431fac5a60Ssetje };
10441fac5a60Ssetje 
10457c478bd9Sstevel@tonic-gate #ifdef SUPPORT_GRAPHICS
10467c478bd9Sstevel@tonic-gate 
10477c478bd9Sstevel@tonic-gate static int splashimage_func(char *arg, int flags) {
10487c478bd9Sstevel@tonic-gate     char splashimage[64];
10497c478bd9Sstevel@tonic-gate     int i;
10501fac5a60Ssetje 
10517c478bd9Sstevel@tonic-gate     /* filename can only be 64 characters due to our buffer size */
10527c478bd9Sstevel@tonic-gate     if (strlen(arg) > 63)
10537c478bd9Sstevel@tonic-gate 	return 1;
10547c478bd9Sstevel@tonic-gate 
10551fac5a60Ssetje     if (flags == BUILTIN_SCRIPT)
10561fac5a60Ssetje         flags = BUILTIN_CMDLINE;
10571fac5a60Ssetje 
1058*a6e28364SSuhasini Peddada     if (flags == BUILTIN_CMDLINE) {
1059*a6e28364SSuhasini Peddada 	if (!grub_open(arg))
1060*a6e28364SSuhasini Peddada 	    return 1;
1061*a6e28364SSuhasini Peddada 	grub_close();
1062*a6e28364SSuhasini Peddada     }
10637c478bd9Sstevel@tonic-gate 
1064*a6e28364SSuhasini Peddada     strcpy(splashimage, arg);
106541c4174fSWilliam Kucharski 
10667c478bd9Sstevel@tonic-gate     /* get rid of TERM_NEED_INIT from the graphics terminal. */
10677c478bd9Sstevel@tonic-gate     for (i = 0; term_table[i].name; i++) {
10687c478bd9Sstevel@tonic-gate 	if (grub_strcmp (term_table[i].name, "graphics") == 0) {
10697c478bd9Sstevel@tonic-gate 	    term_table[i].flags &= ~TERM_NEED_INIT;
10707c478bd9Sstevel@tonic-gate 	    break;
10717c478bd9Sstevel@tonic-gate 	}
10727c478bd9Sstevel@tonic-gate     }
10737c478bd9Sstevel@tonic-gate 
1074*a6e28364SSuhasini Peddada     graphics_set_splash(splashimage);
1075*a6e28364SSuhasini Peddada 
10767c478bd9Sstevel@tonic-gate     if (flags == BUILTIN_CMDLINE && graphics_inited) {
10771fac5a60Ssetje 	/*
10781fac5a60Ssetje 	 * calling graphics_end() here flickers the screen black. OTOH not
10791fac5a60Ssetje 	 * calling it gets us odd plane interlacing / early palette switching ?
10801fac5a60Ssetje 	 * ideally one should figure out how to double buffer and switch...
10811fac5a60Ssetje 	 */
10827c478bd9Sstevel@tonic-gate 	graphics_end();
10837c478bd9Sstevel@tonic-gate 	graphics_init();
10847c478bd9Sstevel@tonic-gate 	graphics_cls();
10857c478bd9Sstevel@tonic-gate     }
10867c478bd9Sstevel@tonic-gate 
10877c478bd9Sstevel@tonic-gate     /* FIXME: should we be explicitly switching the terminal as a
10887c478bd9Sstevel@tonic-gate      * side effect here? */
10897c478bd9Sstevel@tonic-gate     terminal_func("graphics", flags);
10907c478bd9Sstevel@tonic-gate 
10911fac5a60Ssetje     reset_term = 0;
10921fac5a60Ssetje 
10937c478bd9Sstevel@tonic-gate     return 0;
10947c478bd9Sstevel@tonic-gate }
10957c478bd9Sstevel@tonic-gate 
10967c478bd9Sstevel@tonic-gate static struct builtin builtin_splashimage =
10977c478bd9Sstevel@tonic-gate {
10987c478bd9Sstevel@tonic-gate   "splashimage",
10997c478bd9Sstevel@tonic-gate   splashimage_func,
11001fac5a60Ssetje   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_SCRIPT | BUILTIN_HELP_LIST,
11017c478bd9Sstevel@tonic-gate   "splashimage FILE",
11027c478bd9Sstevel@tonic-gate   "Load FILE as the background image when in graphics mode."
11037c478bd9Sstevel@tonic-gate };
11047c478bd9Sstevel@tonic-gate 
11057c478bd9Sstevel@tonic-gate 
11067c478bd9Sstevel@tonic-gate /* foreground */
11077c478bd9Sstevel@tonic-gate static int
11087c478bd9Sstevel@tonic-gate foreground_func(char *arg, int flags)
11097c478bd9Sstevel@tonic-gate {
11107c478bd9Sstevel@tonic-gate     if (grub_strlen(arg) == 6) {
11117c478bd9Sstevel@tonic-gate 	int r = ((hex(arg[0]) << 4) | hex(arg[1])) >> 2;
11127c478bd9Sstevel@tonic-gate 	int g = ((hex(arg[2]) << 4) | hex(arg[3])) >> 2;
11137c478bd9Sstevel@tonic-gate 	int b = ((hex(arg[4]) << 4) | hex(arg[5])) >> 2;
11147c478bd9Sstevel@tonic-gate 
11157c478bd9Sstevel@tonic-gate 	foreground = (r << 16) | (g << 8) | b;
11167c478bd9Sstevel@tonic-gate 	if (graphics_inited)
11177c478bd9Sstevel@tonic-gate 	    graphics_set_palette(15, r, g, b);
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate 	return (0);
11207c478bd9Sstevel@tonic-gate     }
11217c478bd9Sstevel@tonic-gate 
11227c478bd9Sstevel@tonic-gate     return (1);
11237c478bd9Sstevel@tonic-gate }
11247c478bd9Sstevel@tonic-gate 
11257c478bd9Sstevel@tonic-gate static struct builtin builtin_foreground =
11267c478bd9Sstevel@tonic-gate {
11277c478bd9Sstevel@tonic-gate   "foreground",
11287c478bd9Sstevel@tonic-gate   foreground_func,
112967ce1dadSJan Setje-Eilers   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST | BUILTIN_SCRIPT,
11307c478bd9Sstevel@tonic-gate   "foreground RRGGBB",
11317c478bd9Sstevel@tonic-gate   "Sets the foreground color when in graphics mode."
11327c478bd9Sstevel@tonic-gate   "RR is red, GG is green, and BB blue. Numbers must be in hexadecimal."
11337c478bd9Sstevel@tonic-gate };
11347c478bd9Sstevel@tonic-gate 
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate /* background */
11377c478bd9Sstevel@tonic-gate static int
11387c478bd9Sstevel@tonic-gate background_func(char *arg, int flags)
11397c478bd9Sstevel@tonic-gate {
11407c478bd9Sstevel@tonic-gate     if (grub_strlen(arg) == 6) {
11417c478bd9Sstevel@tonic-gate 	int r = ((hex(arg[0]) << 4) | hex(arg[1])) >> 2;
11427c478bd9Sstevel@tonic-gate 	int g = ((hex(arg[2]) << 4) | hex(arg[3])) >> 2;
11437c478bd9Sstevel@tonic-gate 	int b = ((hex(arg[4]) << 4) | hex(arg[5])) >> 2;
11447c478bd9Sstevel@tonic-gate 
11457c478bd9Sstevel@tonic-gate 	background = (r << 16) | (g << 8) | b;
11467c478bd9Sstevel@tonic-gate 	if (graphics_inited)
11477c478bd9Sstevel@tonic-gate 	    graphics_set_palette(0, r, g, b);
11487c478bd9Sstevel@tonic-gate 	return (0);
11497c478bd9Sstevel@tonic-gate     }
11507c478bd9Sstevel@tonic-gate 
11517c478bd9Sstevel@tonic-gate     return (1);
11527c478bd9Sstevel@tonic-gate }
11537c478bd9Sstevel@tonic-gate 
11547c478bd9Sstevel@tonic-gate static struct builtin builtin_background =
11557c478bd9Sstevel@tonic-gate {
11567c478bd9Sstevel@tonic-gate   "background",
11577c478bd9Sstevel@tonic-gate   background_func,
115867ce1dadSJan Setje-Eilers   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST | BUILTIN_SCRIPT,
11597c478bd9Sstevel@tonic-gate   "background RRGGBB",
11607c478bd9Sstevel@tonic-gate   "Sets the background color when in graphics mode."
11617c478bd9Sstevel@tonic-gate   "RR is red, GG is green, and BB blue. Numbers must be in hexadecimal."
11627c478bd9Sstevel@tonic-gate };
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate #endif /* SUPPORT_GRAPHICS */
11657c478bd9Sstevel@tonic-gate 
11667c478bd9Sstevel@tonic-gate 
11677c478bd9Sstevel@tonic-gate /* clear */
11687c478bd9Sstevel@tonic-gate static int
11697c478bd9Sstevel@tonic-gate clear_func()
11707c478bd9Sstevel@tonic-gate {
11717c478bd9Sstevel@tonic-gate   if (current_term->cls)
11727c478bd9Sstevel@tonic-gate     current_term->cls();
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate   return 0;
11757c478bd9Sstevel@tonic-gate }
11767c478bd9Sstevel@tonic-gate 
11777c478bd9Sstevel@tonic-gate static struct builtin builtin_clear =
11787c478bd9Sstevel@tonic-gate {
11797c478bd9Sstevel@tonic-gate   "clear",
11807c478bd9Sstevel@tonic-gate   clear_func,
11817c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
11827c478bd9Sstevel@tonic-gate   "clear",
11837c478bd9Sstevel@tonic-gate   "Clear the screen"
11847c478bd9Sstevel@tonic-gate };
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate /* displayapm */
11877c478bd9Sstevel@tonic-gate static int
11887c478bd9Sstevel@tonic-gate displayapm_func (char *arg, int flags)
11897c478bd9Sstevel@tonic-gate {
11907c478bd9Sstevel@tonic-gate   if (mbi.flags & MB_INFO_APM_TABLE)
11917c478bd9Sstevel@tonic-gate     {
11927c478bd9Sstevel@tonic-gate       grub_printf ("APM BIOS information:\n"
11937c478bd9Sstevel@tonic-gate 		   " Version:          0x%x\n"
11947c478bd9Sstevel@tonic-gate 		   " 32-bit CS:        0x%x\n"
11957c478bd9Sstevel@tonic-gate 		   " Offset:           0x%x\n"
11967c478bd9Sstevel@tonic-gate 		   " 16-bit CS:        0x%x\n"
11977c478bd9Sstevel@tonic-gate 		   " 16-bit DS:        0x%x\n"
11987c478bd9Sstevel@tonic-gate 		   " 32-bit CS length: 0x%x\n"
11997c478bd9Sstevel@tonic-gate 		   " 16-bit CS length: 0x%x\n"
12007c478bd9Sstevel@tonic-gate 		   " 16-bit DS length: 0x%x\n",
12017c478bd9Sstevel@tonic-gate 		   (unsigned) apm_bios_info.version,
12027c478bd9Sstevel@tonic-gate 		   (unsigned) apm_bios_info.cseg,
12037c478bd9Sstevel@tonic-gate 		   apm_bios_info.offset,
12047c478bd9Sstevel@tonic-gate 		   (unsigned) apm_bios_info.cseg_16,
12057c478bd9Sstevel@tonic-gate 		   (unsigned) apm_bios_info.dseg_16,
12067c478bd9Sstevel@tonic-gate 		   (unsigned) apm_bios_info.cseg_len,
12077c478bd9Sstevel@tonic-gate 		   (unsigned) apm_bios_info.cseg_16_len,
12087c478bd9Sstevel@tonic-gate 		   (unsigned) apm_bios_info.dseg_16_len);
12097c478bd9Sstevel@tonic-gate     }
12107c478bd9Sstevel@tonic-gate   else
12117c478bd9Sstevel@tonic-gate     {
12127c478bd9Sstevel@tonic-gate       grub_printf ("No APM BIOS found or probe failed\n");
12137c478bd9Sstevel@tonic-gate     }
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate   return 0;
12167c478bd9Sstevel@tonic-gate }
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate static struct builtin builtin_displayapm =
12197c478bd9Sstevel@tonic-gate {
12207c478bd9Sstevel@tonic-gate   "displayapm",
12217c478bd9Sstevel@tonic-gate   displayapm_func,
12227c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
12237c478bd9Sstevel@tonic-gate   "displayapm",
12247c478bd9Sstevel@tonic-gate   "Display APM BIOS information."
12257c478bd9Sstevel@tonic-gate };
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 
12287c478bd9Sstevel@tonic-gate /* displaymem */
12297c478bd9Sstevel@tonic-gate static int
12307c478bd9Sstevel@tonic-gate displaymem_func (char *arg, int flags)
12317c478bd9Sstevel@tonic-gate {
12327c478bd9Sstevel@tonic-gate   if (get_eisamemsize () != -1)
12337c478bd9Sstevel@tonic-gate     grub_printf (" EISA Memory BIOS Interface is present\n");
12347c478bd9Sstevel@tonic-gate   if (get_mmap_entry ((void *) SCRATCHADDR, 0) != 0
12357c478bd9Sstevel@tonic-gate       || *((int *) SCRATCHADDR) != 0)
12367c478bd9Sstevel@tonic-gate     grub_printf (" Address Map BIOS Interface is present\n");
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate   grub_printf (" Lower memory: %uK, "
12397c478bd9Sstevel@tonic-gate 	       "Upper memory (to first chipset hole): %uK\n",
12407c478bd9Sstevel@tonic-gate 	       mbi.mem_lower, mbi.mem_upper);
12417c478bd9Sstevel@tonic-gate 
1242342440ecSPrasad Singamsetty   if (min_mem64 != 0)
1243342440ecSPrasad Singamsetty   	grub_printf (" Memory limit for 64-bit ISADIR expansion: %uMB\n",
1244342440ecSPrasad Singamsetty 	    min_mem64);
1245342440ecSPrasad Singamsetty 
12467c478bd9Sstevel@tonic-gate   if (mbi.flags & MB_INFO_MEM_MAP)
12477c478bd9Sstevel@tonic-gate     {
12487c478bd9Sstevel@tonic-gate       struct AddrRangeDesc *map = (struct AddrRangeDesc *) mbi.mmap_addr;
12497c478bd9Sstevel@tonic-gate       int end_addr = mbi.mmap_addr + mbi.mmap_length;
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate       grub_printf (" [Address Range Descriptor entries "
12527c478bd9Sstevel@tonic-gate 		   "immediately follow (values are 64-bit)]\n");
12537c478bd9Sstevel@tonic-gate       while (end_addr > (int) map)
12547c478bd9Sstevel@tonic-gate 	{
12557c478bd9Sstevel@tonic-gate 	  char *str;
12567c478bd9Sstevel@tonic-gate 
12577c478bd9Sstevel@tonic-gate 	  if (map->Type == MB_ARD_MEMORY)
12587c478bd9Sstevel@tonic-gate 	    str = "Usable RAM";
12597c478bd9Sstevel@tonic-gate 	  else
12607c478bd9Sstevel@tonic-gate 	    str = "Reserved";
12617c478bd9Sstevel@tonic-gate 	  grub_printf ("   %s:  Base Address:  0x%x X 4GB + 0x%x,\n"
1262342440ecSPrasad Singamsetty 		"      Length:   0x%x X 4GB + 0x%x bytes\n",
1263342440ecSPrasad Singamsetty 		str,
1264342440ecSPrasad Singamsetty 		(unsigned long) (map->BaseAddr >> 32),
1265342440ecSPrasad Singamsetty 		(unsigned long) (map->BaseAddr & 0xFFFFFFFF),
1266342440ecSPrasad Singamsetty 		(unsigned long) (map->Length >> 32),
1267342440ecSPrasad Singamsetty 		(unsigned long) (map->Length & 0xFFFFFFFF));
12687c478bd9Sstevel@tonic-gate 
12697c478bd9Sstevel@tonic-gate 	  map = ((struct AddrRangeDesc *) (((int) map) + 4 + map->size));
12707c478bd9Sstevel@tonic-gate 	}
12717c478bd9Sstevel@tonic-gate     }
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate   return 0;
12747c478bd9Sstevel@tonic-gate }
12757c478bd9Sstevel@tonic-gate 
12767c478bd9Sstevel@tonic-gate static struct builtin builtin_displaymem =
12777c478bd9Sstevel@tonic-gate {
12787c478bd9Sstevel@tonic-gate   "displaymem",
12797c478bd9Sstevel@tonic-gate   displaymem_func,
12807c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
12817c478bd9Sstevel@tonic-gate   "displaymem",
12827c478bd9Sstevel@tonic-gate   "Display what GRUB thinks the system address space map of the"
12837c478bd9Sstevel@tonic-gate   " machine is, including all regions of physical RAM installed."
12847c478bd9Sstevel@tonic-gate };
12857c478bd9Sstevel@tonic-gate 
12867c478bd9Sstevel@tonic-gate 
12877c478bd9Sstevel@tonic-gate /* dump FROM TO */
12887c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
12897c478bd9Sstevel@tonic-gate static int
12907c478bd9Sstevel@tonic-gate dump_func (char *arg, int flags)
12917c478bd9Sstevel@tonic-gate {
12927c478bd9Sstevel@tonic-gate   char *from, *to;
12937c478bd9Sstevel@tonic-gate   FILE *fp;
12947c478bd9Sstevel@tonic-gate   char c;
12957c478bd9Sstevel@tonic-gate 
12967c478bd9Sstevel@tonic-gate   from = arg;
12977c478bd9Sstevel@tonic-gate   to = skip_to (0, arg);
12987c478bd9Sstevel@tonic-gate   if (! *from || ! *to)
12997c478bd9Sstevel@tonic-gate     {
13007c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
13017c478bd9Sstevel@tonic-gate       return 1;
13027c478bd9Sstevel@tonic-gate     }
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate   nul_terminate (from);
13057c478bd9Sstevel@tonic-gate   nul_terminate (to);
13067c478bd9Sstevel@tonic-gate 
13077c478bd9Sstevel@tonic-gate   if (! grub_open (from))
13087c478bd9Sstevel@tonic-gate     return 1;
13097c478bd9Sstevel@tonic-gate 
13107c478bd9Sstevel@tonic-gate   fp = fopen (to, "w");
13117c478bd9Sstevel@tonic-gate   if (! fp)
13127c478bd9Sstevel@tonic-gate     {
13137c478bd9Sstevel@tonic-gate       errnum = ERR_WRITE;
13147c478bd9Sstevel@tonic-gate       return 1;
13157c478bd9Sstevel@tonic-gate     }
13167c478bd9Sstevel@tonic-gate 
13177c478bd9Sstevel@tonic-gate   while (grub_read (&c, 1))
13187c478bd9Sstevel@tonic-gate     if (fputc (c, fp) == EOF)
13197c478bd9Sstevel@tonic-gate       {
13207c478bd9Sstevel@tonic-gate 	errnum = ERR_WRITE;
13217c478bd9Sstevel@tonic-gate 	fclose (fp);
13227c478bd9Sstevel@tonic-gate 	return 1;
13237c478bd9Sstevel@tonic-gate       }
13247c478bd9Sstevel@tonic-gate 
13257c478bd9Sstevel@tonic-gate   if (fclose (fp) == EOF)
13267c478bd9Sstevel@tonic-gate     {
13277c478bd9Sstevel@tonic-gate       errnum = ERR_WRITE;
13287c478bd9Sstevel@tonic-gate       return 1;
13297c478bd9Sstevel@tonic-gate     }
13307c478bd9Sstevel@tonic-gate 
13317c478bd9Sstevel@tonic-gate   grub_close ();
13327c478bd9Sstevel@tonic-gate   return 0;
13337c478bd9Sstevel@tonic-gate }
13347c478bd9Sstevel@tonic-gate 
13357c478bd9Sstevel@tonic-gate static struct builtin builtin_dump =
13367c478bd9Sstevel@tonic-gate   {
13377c478bd9Sstevel@tonic-gate     "dump",
13387c478bd9Sstevel@tonic-gate     dump_func,
13397c478bd9Sstevel@tonic-gate     BUILTIN_CMDLINE,
13407c478bd9Sstevel@tonic-gate     "dump FROM TO",
13417c478bd9Sstevel@tonic-gate     "Dump the contents of the file FROM to the file TO. FROM must be"
13427c478bd9Sstevel@tonic-gate     " a GRUB file and TO must be an OS file."
13437c478bd9Sstevel@tonic-gate   };
13447c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
13457c478bd9Sstevel@tonic-gate 
13467c478bd9Sstevel@tonic-gate 
13477c478bd9Sstevel@tonic-gate static char embed_info[32];
13487c478bd9Sstevel@tonic-gate /* embed */
13497c478bd9Sstevel@tonic-gate /* Embed a Stage 1.5 in the first cylinder after MBR or in the
13507c478bd9Sstevel@tonic-gate    bootloader block in a FFS.  */
13517c478bd9Sstevel@tonic-gate static int
13527c478bd9Sstevel@tonic-gate embed_func (char *arg, int flags)
13537c478bd9Sstevel@tonic-gate {
13547c478bd9Sstevel@tonic-gate   char *stage1_5;
13557c478bd9Sstevel@tonic-gate   char *device;
13567c478bd9Sstevel@tonic-gate   char *stage1_5_buffer = (char *) RAW_ADDR (0x100000);
13577c478bd9Sstevel@tonic-gate   int len, size;
13587c478bd9Sstevel@tonic-gate   int sector;
13597c478bd9Sstevel@tonic-gate 
13607c478bd9Sstevel@tonic-gate   stage1_5 = arg;
13617c478bd9Sstevel@tonic-gate   device = skip_to (0, stage1_5);
13627c478bd9Sstevel@tonic-gate 
13637c478bd9Sstevel@tonic-gate   /* Open a Stage 1.5.  */
13647c478bd9Sstevel@tonic-gate   if (! grub_open (stage1_5))
13657c478bd9Sstevel@tonic-gate     return 1;
13667c478bd9Sstevel@tonic-gate 
13677c478bd9Sstevel@tonic-gate   /* Read the whole of the Stage 1.5.  */
13687c478bd9Sstevel@tonic-gate   len = grub_read (stage1_5_buffer, -1);
13697c478bd9Sstevel@tonic-gate   grub_close ();
13707c478bd9Sstevel@tonic-gate 
13717c478bd9Sstevel@tonic-gate   if (errnum)
13727c478bd9Sstevel@tonic-gate     return 1;
13737c478bd9Sstevel@tonic-gate 
13747c478bd9Sstevel@tonic-gate   size = (len + SECTOR_SIZE - 1) / SECTOR_SIZE;
13757c478bd9Sstevel@tonic-gate 
13767c478bd9Sstevel@tonic-gate   /* Get the device where the Stage 1.5 will be embedded.  */
13777c478bd9Sstevel@tonic-gate   set_device (device);
13787c478bd9Sstevel@tonic-gate   if (errnum)
13797c478bd9Sstevel@tonic-gate     return 1;
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate   if (current_partition == 0xFFFFFF)
13827c478bd9Sstevel@tonic-gate     {
13837c478bd9Sstevel@tonic-gate       /* Embed it after the MBR.  */
13847c478bd9Sstevel@tonic-gate 
13857c478bd9Sstevel@tonic-gate       char mbr[SECTOR_SIZE];
13867c478bd9Sstevel@tonic-gate       char ezbios_check[2*SECTOR_SIZE];
13877c478bd9Sstevel@tonic-gate       int i;
13887c478bd9Sstevel@tonic-gate 
13897c478bd9Sstevel@tonic-gate       /* Open the partition.  */
13907c478bd9Sstevel@tonic-gate       if (! open_partition ())
13917c478bd9Sstevel@tonic-gate 	return 1;
13927c478bd9Sstevel@tonic-gate 
13937c478bd9Sstevel@tonic-gate       /* No floppy has MBR.  */
13947c478bd9Sstevel@tonic-gate       if (! (current_drive & 0x80))
13957c478bd9Sstevel@tonic-gate 	{
13967c478bd9Sstevel@tonic-gate 	  errnum = ERR_DEV_VALUES;
13977c478bd9Sstevel@tonic-gate 	  return 1;
13987c478bd9Sstevel@tonic-gate 	}
13997c478bd9Sstevel@tonic-gate 
14007c478bd9Sstevel@tonic-gate       /* Read the MBR of CURRENT_DRIVE.  */
14017c478bd9Sstevel@tonic-gate       if (! rawread (current_drive, PC_MBR_SECTOR, 0, SECTOR_SIZE, mbr))
14027c478bd9Sstevel@tonic-gate 	return 1;
14037c478bd9Sstevel@tonic-gate 
14047c478bd9Sstevel@tonic-gate       /* Sanity check.  */
14057c478bd9Sstevel@tonic-gate       if (! PC_MBR_CHECK_SIG (mbr))
14067c478bd9Sstevel@tonic-gate 	{
14077c478bd9Sstevel@tonic-gate 	  errnum = ERR_BAD_PART_TABLE;
14087c478bd9Sstevel@tonic-gate 	  return 1;
14097c478bd9Sstevel@tonic-gate 	}
14107c478bd9Sstevel@tonic-gate 
14117c478bd9Sstevel@tonic-gate       /* Check if the disk can store the Stage 1.5.  */
14127c478bd9Sstevel@tonic-gate       for (i = 0; i < 4; i++)
14137c478bd9Sstevel@tonic-gate 	if (PC_SLICE_TYPE (mbr, i) && PC_SLICE_START (mbr, i) - 1 < size)
14147c478bd9Sstevel@tonic-gate 	  {
14157c478bd9Sstevel@tonic-gate 	    errnum = ERR_NO_DISK_SPACE;
14167c478bd9Sstevel@tonic-gate 	    return 1;
14177c478bd9Sstevel@tonic-gate 	  }
14187c478bd9Sstevel@tonic-gate 
14197c478bd9Sstevel@tonic-gate       /* Check for EZ-BIOS signature. It should be in the third
14207c478bd9Sstevel@tonic-gate        * sector, but due to remapping it can appear in the second, so
14217c478bd9Sstevel@tonic-gate        * load and check both.
14227c478bd9Sstevel@tonic-gate        */
14237c478bd9Sstevel@tonic-gate       if (! rawread (current_drive, 1, 0, 2 * SECTOR_SIZE, ezbios_check))
14247c478bd9Sstevel@tonic-gate 	return 1;
14257c478bd9Sstevel@tonic-gate 
14267c478bd9Sstevel@tonic-gate       if (! memcmp (ezbios_check + 3, "AERMH", 5)
14277c478bd9Sstevel@tonic-gate 	  || ! memcmp (ezbios_check + 512 + 3, "AERMH", 5))
14287c478bd9Sstevel@tonic-gate 	{
14297c478bd9Sstevel@tonic-gate 	  /* The space after the MBR is used by EZ-BIOS which we must
14307c478bd9Sstevel@tonic-gate 	   * not overwrite.
14317c478bd9Sstevel@tonic-gate 	   */
14327c478bd9Sstevel@tonic-gate 	  errnum = ERR_NO_DISK_SPACE;
14337c478bd9Sstevel@tonic-gate 	  return 1;
14347c478bd9Sstevel@tonic-gate 	}
14357c478bd9Sstevel@tonic-gate 
14367c478bd9Sstevel@tonic-gate       sector = 1;
14377c478bd9Sstevel@tonic-gate     }
14387c478bd9Sstevel@tonic-gate   else
14397c478bd9Sstevel@tonic-gate     {
14407c478bd9Sstevel@tonic-gate       /* Embed it in the bootloader block in the filesystem.  */
14417c478bd9Sstevel@tonic-gate       int start_sector;
14427c478bd9Sstevel@tonic-gate 
14437c478bd9Sstevel@tonic-gate       /* Open the partition.  */
14447c478bd9Sstevel@tonic-gate       if (! open_device ())
14457c478bd9Sstevel@tonic-gate 	return 1;
14467c478bd9Sstevel@tonic-gate 
14477c478bd9Sstevel@tonic-gate       /* Check if the current slice supports embedding.  */
14487c478bd9Sstevel@tonic-gate       if (fsys_table[fsys_type].embed_func == 0
14497c478bd9Sstevel@tonic-gate 	  || ! fsys_table[fsys_type].embed_func (&start_sector, size))
14507c478bd9Sstevel@tonic-gate 	{
14517c478bd9Sstevel@tonic-gate 	  errnum = ERR_DEV_VALUES;
14527c478bd9Sstevel@tonic-gate 	  return 1;
14537c478bd9Sstevel@tonic-gate 	}
14547c478bd9Sstevel@tonic-gate 
14557c478bd9Sstevel@tonic-gate       sector = part_start + start_sector;
14567c478bd9Sstevel@tonic-gate     }
14577c478bd9Sstevel@tonic-gate 
14587c478bd9Sstevel@tonic-gate   /* Clear the cache.  */
1459342440ecSPrasad Singamsetty   buf_track = BUF_CACHE_INVALID;
14607c478bd9Sstevel@tonic-gate 
14617c478bd9Sstevel@tonic-gate   /* Now perform the embedding.  */
14627c478bd9Sstevel@tonic-gate   if (! devwrite (sector - part_start, size, stage1_5_buffer))
14637c478bd9Sstevel@tonic-gate     return 1;
14647c478bd9Sstevel@tonic-gate 
14657c478bd9Sstevel@tonic-gate   grub_printf (" %d sectors are embedded.\n", size);
14667c478bd9Sstevel@tonic-gate   grub_sprintf (embed_info, "%d+%d", sector - part_start, size);
14677c478bd9Sstevel@tonic-gate   return 0;
14687c478bd9Sstevel@tonic-gate }
14697c478bd9Sstevel@tonic-gate 
14707c478bd9Sstevel@tonic-gate static struct builtin builtin_embed =
14717c478bd9Sstevel@tonic-gate {
14727c478bd9Sstevel@tonic-gate   "embed",
14737c478bd9Sstevel@tonic-gate   embed_func,
14747c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
14757c478bd9Sstevel@tonic-gate   "embed STAGE1_5 DEVICE",
14767c478bd9Sstevel@tonic-gate   "Embed the Stage 1.5 STAGE1_5 in the sectors after MBR if DEVICE"
14777c478bd9Sstevel@tonic-gate   " is a drive, or in the \"bootloader\" area if DEVICE is a FFS partition."
14787c478bd9Sstevel@tonic-gate   " Print the number of sectors which STAGE1_5 occupies if successful."
14797c478bd9Sstevel@tonic-gate };
14807c478bd9Sstevel@tonic-gate 
14817c478bd9Sstevel@tonic-gate 
14827c478bd9Sstevel@tonic-gate /* fallback */
14837c478bd9Sstevel@tonic-gate static int
14847c478bd9Sstevel@tonic-gate fallback_func (char *arg, int flags)
14857c478bd9Sstevel@tonic-gate {
14867c478bd9Sstevel@tonic-gate   int i = 0;
14877c478bd9Sstevel@tonic-gate 
14887c478bd9Sstevel@tonic-gate   while (*arg)
14897c478bd9Sstevel@tonic-gate     {
14907c478bd9Sstevel@tonic-gate       int entry;
14917c478bd9Sstevel@tonic-gate       int j;
14927c478bd9Sstevel@tonic-gate 
14937c478bd9Sstevel@tonic-gate       if (! safe_parse_maxint (&arg, &entry))
14947c478bd9Sstevel@tonic-gate 	return 1;
14957c478bd9Sstevel@tonic-gate 
14967c478bd9Sstevel@tonic-gate       /* Remove duplications to prevent infinite looping.  */
14977c478bd9Sstevel@tonic-gate       for (j = 0; j < i; j++)
14987c478bd9Sstevel@tonic-gate 	if (entry == fallback_entries[j])
14997c478bd9Sstevel@tonic-gate 	  break;
15007c478bd9Sstevel@tonic-gate       if (j != i)
15017c478bd9Sstevel@tonic-gate 	continue;
15027c478bd9Sstevel@tonic-gate 
15037c478bd9Sstevel@tonic-gate       fallback_entries[i++] = entry;
15047c478bd9Sstevel@tonic-gate       if (i == MAX_FALLBACK_ENTRIES)
15057c478bd9Sstevel@tonic-gate 	break;
15067c478bd9Sstevel@tonic-gate 
15077c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
15087c478bd9Sstevel@tonic-gate     }
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate   if (i < MAX_FALLBACK_ENTRIES)
15117c478bd9Sstevel@tonic-gate     fallback_entries[i] = -1;
15127c478bd9Sstevel@tonic-gate 
15137c478bd9Sstevel@tonic-gate   fallback_entryno = (i == 0) ? -1 : 0;
15147c478bd9Sstevel@tonic-gate 
15157c478bd9Sstevel@tonic-gate   return 0;
15167c478bd9Sstevel@tonic-gate }
15177c478bd9Sstevel@tonic-gate 
15187c478bd9Sstevel@tonic-gate static struct builtin builtin_fallback =
15197c478bd9Sstevel@tonic-gate {
15207c478bd9Sstevel@tonic-gate   "fallback",
15217c478bd9Sstevel@tonic-gate   fallback_func,
15227c478bd9Sstevel@tonic-gate   BUILTIN_MENU,
15237c478bd9Sstevel@tonic-gate #if 0
15247c478bd9Sstevel@tonic-gate   "fallback NUM...",
15257c478bd9Sstevel@tonic-gate   "Go into unattended boot mode: if the default boot entry has any"
15267c478bd9Sstevel@tonic-gate   " errors, instead of waiting for the user to do anything, it"
15277c478bd9Sstevel@tonic-gate   " immediately starts over using the NUM entry (same numbering as the"
15287c478bd9Sstevel@tonic-gate   " `default' command). This obviously won't help if the machine"
15297c478bd9Sstevel@tonic-gate   " was rebooted by a kernel that GRUB loaded."
15307c478bd9Sstevel@tonic-gate #endif
15317c478bd9Sstevel@tonic-gate };
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate 
1534051aabe6Staylor 
1535051aabe6Staylor void
1536051aabe6Staylor set_root (char *root, unsigned long drive, unsigned long part)
1537051aabe6Staylor {
1538051aabe6Staylor   int bsd_part = (part >> 8) & 0xFF;
1539051aabe6Staylor   int pc_slice = part >> 16;
1540051aabe6Staylor 
1541051aabe6Staylor   if (bsd_part == 0xFF) {
1542051aabe6Staylor     grub_sprintf (root, "(hd%d,%d)\n", drive - 0x80, pc_slice);
1543051aabe6Staylor   } else {
1544051aabe6Staylor     grub_sprintf (root, "(hd%d,%d,%c)\n",
1545051aabe6Staylor 		 drive - 0x80, pc_slice, bsd_part + 'a');
1546051aabe6Staylor   }
1547051aabe6Staylor }
1548051aabe6Staylor 
15497c478bd9Sstevel@tonic-gate static int
1550eb2bd662Svikram find_common (char *arg, char *root, int for_root, int flags)
15517c478bd9Sstevel@tonic-gate {
1552eb2bd662Svikram   char *filename = NULL;
1553eb2bd662Svikram   static char argpart[32];
1554eb2bd662Svikram   static char device[32];
1555eb2bd662Svikram   char *tmp_argpart = NULL;
15567c478bd9Sstevel@tonic-gate   unsigned long drive;
15577c478bd9Sstevel@tonic-gate   unsigned long tmp_drive = saved_drive;
15587c478bd9Sstevel@tonic-gate   unsigned long tmp_partition = saved_partition;
15597c478bd9Sstevel@tonic-gate   int got_file = 0;
1560eb2bd662Svikram   static char bootsign[BOOTSIGN_LEN];
1561eb2bd662Svikram 
1562eb2bd662Svikram   /*
1563eb2bd662Svikram    * If argument has partition information (findroot command only), then
1564eb2bd662Svikram    * it can't be a floppy
1565eb2bd662Svikram    */
1566eb2bd662Svikram   if (for_root && arg[0] == '(') {
1567eb2bd662Svikram 	tmp_argpart = grub_strchr(arg + 1, ',');
1568eb2bd662Svikram         if (tmp_argpart == NULL)
1569eb2bd662Svikram 		goto out;
1570eb2bd662Svikram 	grub_strcpy(argpart, tmp_argpart);
1571eb2bd662Svikram 	*tmp_argpart = '\0';
1572eb2bd662Svikram 	arg++;
1573eb2bd662Svikram         grub_sprintf(bootsign, "%s/%s", BOOTSIGN_DIR, arg);
1574eb2bd662Svikram 	filename = bootsign;
1575eb2bd662Svikram 	goto harddisk;
1576eb2bd662Svikram   } else if (for_root) {
1577eb2bd662Svikram 	/* Boot signature without partition/slice information */
1578eb2bd662Svikram         grub_sprintf(bootsign, "%s/%s", BOOTSIGN_DIR, arg);
1579eb2bd662Svikram 	filename = bootsign;
1580eb2bd662Svikram   } else {
1581eb2bd662Svikram 	/* plain vanilla find cmd */
1582eb2bd662Svikram 	filename = arg;
1583eb2bd662Svikram   }
15847c478bd9Sstevel@tonic-gate 
15857c478bd9Sstevel@tonic-gate   /* Floppies.  */
15867c478bd9Sstevel@tonic-gate   for (drive = 0; drive < 8; drive++)
15877c478bd9Sstevel@tonic-gate     {
15887c478bd9Sstevel@tonic-gate       current_drive = drive;
15897c478bd9Sstevel@tonic-gate       current_partition = 0xFFFFFF;
15907c478bd9Sstevel@tonic-gate 
15917c478bd9Sstevel@tonic-gate       if (open_device ())
15927c478bd9Sstevel@tonic-gate 	{
15937c478bd9Sstevel@tonic-gate 	  saved_drive = current_drive;
15947c478bd9Sstevel@tonic-gate 	  saved_partition = current_partition;
15957c478bd9Sstevel@tonic-gate 	  if (grub_open (filename))
15967c478bd9Sstevel@tonic-gate 	    {
15977c478bd9Sstevel@tonic-gate 	      grub_close ();
15987c478bd9Sstevel@tonic-gate 	      got_file = 1;
1599eb2bd662Svikram 	      if (for_root) {
1600eb2bd662Svikram 		 grub_sprintf(root, "(fd%d)", drive);
1601eb2bd662Svikram 		 goto out;
1602eb2bd662Svikram 	      } else
1603eb2bd662Svikram 	         grub_printf (" (fd%d)\n", drive);
16047c478bd9Sstevel@tonic-gate 	    }
16057c478bd9Sstevel@tonic-gate 	}
16067c478bd9Sstevel@tonic-gate 
16077c478bd9Sstevel@tonic-gate       errnum = ERR_NONE;
16087c478bd9Sstevel@tonic-gate     }
16097c478bd9Sstevel@tonic-gate 
1610eb2bd662Svikram harddisk:
16117c478bd9Sstevel@tonic-gate   /* Hard disks.  */
16127c478bd9Sstevel@tonic-gate   for (drive = 0x80; drive < 0x88; drive++)
16137c478bd9Sstevel@tonic-gate     {
16147c478bd9Sstevel@tonic-gate       unsigned long part = 0xFFFFFF;
16157c478bd9Sstevel@tonic-gate       unsigned long start, len, offset, ext_offset;
16167c478bd9Sstevel@tonic-gate       int type, entry;
16177c478bd9Sstevel@tonic-gate       char buf[SECTOR_SIZE];
16187c478bd9Sstevel@tonic-gate 
1619eb2bd662Svikram       if (for_root && tmp_argpart) {
1620051aabe6Staylor 	grub_sprintf(device, "(hd%d%s", drive - 0x80, argpart);
1621eb2bd662Svikram 	set_device(device);
1622eb2bd662Svikram         errnum = ERR_NONE;
1623eb2bd662Svikram 	part = current_partition;
1624eb2bd662Svikram 	if (open_device ()) {
1625eb2bd662Svikram 	   saved_drive = current_drive;
1626eb2bd662Svikram 	   saved_partition = current_partition;
1627eb2bd662Svikram            errnum = ERR_NONE;
1628eb2bd662Svikram 	   if (grub_open (filename)) {
1629eb2bd662Svikram 	      grub_close ();
1630eb2bd662Svikram 	      got_file = 1;
1631051aabe6Staylor 	      if (is_zfs_mount == 0) {
1632051aabe6Staylor 	        set_root(root, current_drive, current_partition);
1633051aabe6Staylor 	        goto out;
1634051aabe6Staylor 	      } else {
1635051aabe6Staylor 		best_drive = current_drive;
1636051aabe6Staylor 		best_part = current_partition;
1637051aabe6Staylor 	      }
1638eb2bd662Svikram            }
1639eb2bd662Svikram 	}
1640eb2bd662Svikram         errnum = ERR_NONE;
1641eb2bd662Svikram 	continue;
1642eb2bd662Svikram       }
16437c478bd9Sstevel@tonic-gate       current_drive = drive;
16447c478bd9Sstevel@tonic-gate       while (next_partition (drive, 0xFFFFFF, &part, &type,
16457c478bd9Sstevel@tonic-gate 			     &start, &len, &offset, &entry,
16467c478bd9Sstevel@tonic-gate 			     &ext_offset, buf))
16477c478bd9Sstevel@tonic-gate 	{
16487c478bd9Sstevel@tonic-gate 	  if (type != PC_SLICE_TYPE_NONE
16497c478bd9Sstevel@tonic-gate 	      && ! IS_PC_SLICE_TYPE_BSD (type)
16507c478bd9Sstevel@tonic-gate 	      && ! IS_PC_SLICE_TYPE_EXTENDED (type))
16517c478bd9Sstevel@tonic-gate 	    {
16527c478bd9Sstevel@tonic-gate 	      current_partition = part;
16537c478bd9Sstevel@tonic-gate 	      if (open_device ())
16547c478bd9Sstevel@tonic-gate 		{
16557c478bd9Sstevel@tonic-gate 		  saved_drive = current_drive;
16567c478bd9Sstevel@tonic-gate 		  saved_partition = current_partition;
16577c478bd9Sstevel@tonic-gate 		  if (grub_open (filename))
16587c478bd9Sstevel@tonic-gate 		    {
1659051aabe6Staylor 		      char tmproot[32];
1660051aabe6Staylor 
16617c478bd9Sstevel@tonic-gate 		      grub_close ();
1662eb2bd662Svikram 		      got_file = 1;
1663051aabe6Staylor 		      set_root(tmproot, drive, part);
1664051aabe6Staylor 		      if (for_root) {
1665051aabe6Staylor 		 	grub_memcpy(root, tmproot, sizeof(tmproot));
1666051aabe6Staylor 			if (is_zfs_mount == 0) {
1667051aabe6Staylor 			      goto out;
1668051aabe6Staylor 			} else {
1669051aabe6Staylor 			      best_drive = current_drive;
1670051aabe6Staylor 			      best_part = current_partition;
1671051aabe6Staylor 			}
1672eb2bd662Svikram 		      } else {
1673051aabe6Staylor 			grub_printf("%s", tmproot);
1674eb2bd662Svikram 		      }
16757c478bd9Sstevel@tonic-gate 		    }
16767c478bd9Sstevel@tonic-gate 		}
16777c478bd9Sstevel@tonic-gate 	    }
16787c478bd9Sstevel@tonic-gate 
16797c478bd9Sstevel@tonic-gate 	  /* We want to ignore any error here.  */
16807c478bd9Sstevel@tonic-gate 	  errnum = ERR_NONE;
16817c478bd9Sstevel@tonic-gate 	}
16827c478bd9Sstevel@tonic-gate 
16837c478bd9Sstevel@tonic-gate       /* next_partition always sets ERRNUM in the last call, so clear
16847c478bd9Sstevel@tonic-gate 	 it.  */
16857c478bd9Sstevel@tonic-gate       errnum = ERR_NONE;
16867c478bd9Sstevel@tonic-gate     }
16877c478bd9Sstevel@tonic-gate 
1688eb2bd662Svikram out:
1689051aabe6Staylor   if (is_zfs_mount && for_root) {
1690051aabe6Staylor         set_root(root, best_drive, best_part);
1691051aabe6Staylor 	buf_drive = -1;
1692051aabe6Staylor   } else {
1693051aabe6Staylor 	saved_drive = tmp_drive;
1694051aabe6Staylor 	saved_partition = tmp_partition;
1695051aabe6Staylor   }
1696eb2bd662Svikram   if (tmp_argpart)
1697eb2bd662Svikram 	*tmp_argpart = ',';
16987c478bd9Sstevel@tonic-gate 
16997c478bd9Sstevel@tonic-gate   if (got_file)
17007c478bd9Sstevel@tonic-gate     {
17017c478bd9Sstevel@tonic-gate       errnum = ERR_NONE;
17027c478bd9Sstevel@tonic-gate       return 0;
17037c478bd9Sstevel@tonic-gate     }
17047c478bd9Sstevel@tonic-gate 
17057c478bd9Sstevel@tonic-gate   errnum = ERR_FILE_NOT_FOUND;
17067c478bd9Sstevel@tonic-gate   return 1;
17077c478bd9Sstevel@tonic-gate }
17087c478bd9Sstevel@tonic-gate 
1709eb2bd662Svikram /* find */
1710eb2bd662Svikram /* Search for the filename ARG in all of partitions.  */
1711eb2bd662Svikram static int
1712eb2bd662Svikram find_func (char *arg, int flags)
1713eb2bd662Svikram {
1714eb2bd662Svikram 	return (find_common(arg, NULL, 0, flags));
1715eb2bd662Svikram }
1716eb2bd662Svikram 
17177c478bd9Sstevel@tonic-gate static struct builtin builtin_find =
17187c478bd9Sstevel@tonic-gate {
17197c478bd9Sstevel@tonic-gate   "find",
17207c478bd9Sstevel@tonic-gate   find_func,
17217c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
17227c478bd9Sstevel@tonic-gate   "find FILENAME",
17237c478bd9Sstevel@tonic-gate   "Search for the filename FILENAME in all of partitions and print the list of"
17247c478bd9Sstevel@tonic-gate   " the devices which contain the file."
17257c478bd9Sstevel@tonic-gate };
17267c478bd9Sstevel@tonic-gate 
17277c478bd9Sstevel@tonic-gate 
17287c478bd9Sstevel@tonic-gate /* fstest */
17297c478bd9Sstevel@tonic-gate static int
17307c478bd9Sstevel@tonic-gate fstest_func (char *arg, int flags)
17317c478bd9Sstevel@tonic-gate {
17327c478bd9Sstevel@tonic-gate   if (disk_read_hook)
17337c478bd9Sstevel@tonic-gate     {
17347c478bd9Sstevel@tonic-gate       disk_read_hook = NULL;
17357c478bd9Sstevel@tonic-gate       printf (" Filesystem tracing is now off\n");
17367c478bd9Sstevel@tonic-gate     }
17377c478bd9Sstevel@tonic-gate   else
17387c478bd9Sstevel@tonic-gate     {
17397c478bd9Sstevel@tonic-gate       disk_read_hook = disk_read_print_func;
17407c478bd9Sstevel@tonic-gate       printf (" Filesystem tracing is now on\n");
17417c478bd9Sstevel@tonic-gate     }
17427c478bd9Sstevel@tonic-gate 
17437c478bd9Sstevel@tonic-gate   return 0;
17447c478bd9Sstevel@tonic-gate }
17457c478bd9Sstevel@tonic-gate 
17467c478bd9Sstevel@tonic-gate static struct builtin builtin_fstest =
17477c478bd9Sstevel@tonic-gate {
17487c478bd9Sstevel@tonic-gate   "fstest",
17497c478bd9Sstevel@tonic-gate   fstest_func,
17507c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
17517c478bd9Sstevel@tonic-gate   "fstest",
17527c478bd9Sstevel@tonic-gate   "Toggle filesystem test mode."
17537c478bd9Sstevel@tonic-gate };
17547c478bd9Sstevel@tonic-gate 
17557c478bd9Sstevel@tonic-gate 
17567c478bd9Sstevel@tonic-gate /* geometry */
17577c478bd9Sstevel@tonic-gate static int
17587c478bd9Sstevel@tonic-gate geometry_func (char *arg, int flags)
17597c478bd9Sstevel@tonic-gate {
17607c478bd9Sstevel@tonic-gate   struct geometry geom;
17617c478bd9Sstevel@tonic-gate   char *msg;
17627c478bd9Sstevel@tonic-gate   char *device = arg;
17637c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
17647c478bd9Sstevel@tonic-gate   char *ptr;
17657c478bd9Sstevel@tonic-gate #endif
17667c478bd9Sstevel@tonic-gate 
17677c478bd9Sstevel@tonic-gate   /* Get the device number.  */
17687c478bd9Sstevel@tonic-gate   set_device (device);
17697c478bd9Sstevel@tonic-gate   if (errnum)
17707c478bd9Sstevel@tonic-gate     return 1;
17717c478bd9Sstevel@tonic-gate 
17727c478bd9Sstevel@tonic-gate   /* Check for the geometry.  */
17737c478bd9Sstevel@tonic-gate   if (get_diskinfo (current_drive, &geom))
17747c478bd9Sstevel@tonic-gate     {
17757c478bd9Sstevel@tonic-gate       errnum = ERR_NO_DISK;
17767c478bd9Sstevel@tonic-gate       return 1;
17777c478bd9Sstevel@tonic-gate     }
17787c478bd9Sstevel@tonic-gate 
17797c478bd9Sstevel@tonic-gate   /* Attempt to read the first sector, because some BIOSes turns out not
17807c478bd9Sstevel@tonic-gate      to support LBA even though they set the bit 0 in the support
17817c478bd9Sstevel@tonic-gate      bitmap, only after reading something actually.  */
17827c478bd9Sstevel@tonic-gate   if (biosdisk (BIOSDISK_READ, current_drive, &geom, 0, 1, SCRATCHSEG))
17837c478bd9Sstevel@tonic-gate     {
17847c478bd9Sstevel@tonic-gate       errnum = ERR_READ;
17857c478bd9Sstevel@tonic-gate       return 1;
17867c478bd9Sstevel@tonic-gate     }
17877c478bd9Sstevel@tonic-gate 
17887c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
17897c478bd9Sstevel@tonic-gate   ptr = skip_to (0, device);
17907c478bd9Sstevel@tonic-gate   if (*ptr)
17917c478bd9Sstevel@tonic-gate     {
17927c478bd9Sstevel@tonic-gate       char *cylinder, *head, *sector, *total_sector;
17937c478bd9Sstevel@tonic-gate       int num_cylinder, num_head, num_sector, num_total_sector;
17947c478bd9Sstevel@tonic-gate 
17957c478bd9Sstevel@tonic-gate       cylinder = ptr;
17967c478bd9Sstevel@tonic-gate       head = skip_to (0, cylinder);
17977c478bd9Sstevel@tonic-gate       sector = skip_to (0, head);
17987c478bd9Sstevel@tonic-gate       total_sector = skip_to (0, sector);
17997c478bd9Sstevel@tonic-gate       if (! safe_parse_maxint (&cylinder, &num_cylinder)
18007c478bd9Sstevel@tonic-gate 	  || ! safe_parse_maxint (&head, &num_head)
18017c478bd9Sstevel@tonic-gate 	  || ! safe_parse_maxint (&sector, &num_sector))
18027c478bd9Sstevel@tonic-gate 	return 1;
18037c478bd9Sstevel@tonic-gate 
18047c478bd9Sstevel@tonic-gate       disks[current_drive].cylinders = num_cylinder;
18057c478bd9Sstevel@tonic-gate       disks[current_drive].heads = num_head;
18067c478bd9Sstevel@tonic-gate       disks[current_drive].sectors = num_sector;
18077c478bd9Sstevel@tonic-gate 
18087c478bd9Sstevel@tonic-gate       if (safe_parse_maxint (&total_sector, &num_total_sector))
18097c478bd9Sstevel@tonic-gate 	disks[current_drive].total_sectors = num_total_sector;
18107c478bd9Sstevel@tonic-gate       else
18117c478bd9Sstevel@tonic-gate 	disks[current_drive].total_sectors
18127c478bd9Sstevel@tonic-gate 	  = num_cylinder * num_head * num_sector;
18137c478bd9Sstevel@tonic-gate       errnum = 0;
18147c478bd9Sstevel@tonic-gate 
18157c478bd9Sstevel@tonic-gate       geom = disks[current_drive];
18167c478bd9Sstevel@tonic-gate       buf_drive = -1;
18177c478bd9Sstevel@tonic-gate     }
18187c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
18197c478bd9Sstevel@tonic-gate 
18207c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
18217c478bd9Sstevel@tonic-gate   msg = device_map[current_drive];
18227c478bd9Sstevel@tonic-gate #else
18237c478bd9Sstevel@tonic-gate   if (geom.flags & BIOSDISK_FLAG_LBA_EXTENSION)
18247c478bd9Sstevel@tonic-gate     msg = "LBA";
18257c478bd9Sstevel@tonic-gate   else
18267c478bd9Sstevel@tonic-gate     msg = "CHS";
18277c478bd9Sstevel@tonic-gate #endif
18287c478bd9Sstevel@tonic-gate 
18297c478bd9Sstevel@tonic-gate   grub_printf ("drive 0x%x: C/H/S = %d/%d/%d, "
1830342440ecSPrasad Singamsetty 	       "The number of sectors = %u, %s\n",
18317c478bd9Sstevel@tonic-gate 	       current_drive,
18327c478bd9Sstevel@tonic-gate 	       geom.cylinders, geom.heads, geom.sectors,
18337c478bd9Sstevel@tonic-gate 	       geom.total_sectors, msg);
18347c478bd9Sstevel@tonic-gate   real_open_partition (1);
18357c478bd9Sstevel@tonic-gate 
18367c478bd9Sstevel@tonic-gate   return 0;
18377c478bd9Sstevel@tonic-gate }
18387c478bd9Sstevel@tonic-gate 
18397c478bd9Sstevel@tonic-gate static struct builtin builtin_geometry =
18407c478bd9Sstevel@tonic-gate {
18417c478bd9Sstevel@tonic-gate   "geometry",
18427c478bd9Sstevel@tonic-gate   geometry_func,
18437c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
18447c478bd9Sstevel@tonic-gate   "geometry DRIVE [CYLINDER HEAD SECTOR [TOTAL_SECTOR]]",
18457c478bd9Sstevel@tonic-gate   "Print the information for a drive DRIVE. In the grub shell, you can"
18467c478bd9Sstevel@tonic-gate   " set the geometry of the drive arbitrarily. The number of the cylinders,"
18477c478bd9Sstevel@tonic-gate   " the one of the heads, the one of the sectors and the one of the total"
18487c478bd9Sstevel@tonic-gate   " sectors are set to CYLINDER, HEAD, SECTOR and TOTAL_SECTOR,"
18497c478bd9Sstevel@tonic-gate   " respectively. If you omit TOTAL_SECTOR, then it will be calculated based"
18507c478bd9Sstevel@tonic-gate   " on the C/H/S values automatically."
18517c478bd9Sstevel@tonic-gate };
18527c478bd9Sstevel@tonic-gate 
18537c478bd9Sstevel@tonic-gate 
18547c478bd9Sstevel@tonic-gate /* halt */
18557c478bd9Sstevel@tonic-gate static int
18567c478bd9Sstevel@tonic-gate halt_func (char *arg, int flags)
18577c478bd9Sstevel@tonic-gate {
18587c478bd9Sstevel@tonic-gate   int no_apm;
18597c478bd9Sstevel@tonic-gate 
18607c478bd9Sstevel@tonic-gate   no_apm = (grub_memcmp (arg, "--no-apm", 8) == 0);
18617c478bd9Sstevel@tonic-gate   grub_halt (no_apm);
18627c478bd9Sstevel@tonic-gate 
18637c478bd9Sstevel@tonic-gate   /* Never reach here.  */
18647c478bd9Sstevel@tonic-gate   return 1;
18657c478bd9Sstevel@tonic-gate }
18667c478bd9Sstevel@tonic-gate 
18677c478bd9Sstevel@tonic-gate static struct builtin builtin_halt =
18687c478bd9Sstevel@tonic-gate {
18697c478bd9Sstevel@tonic-gate   "halt",
18707c478bd9Sstevel@tonic-gate   halt_func,
18717c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
18727c478bd9Sstevel@tonic-gate   "halt [--no-apm]",
18737c478bd9Sstevel@tonic-gate   "Halt your system. If APM is avaiable on it, turn off the power using"
18747c478bd9Sstevel@tonic-gate   " the APM BIOS, unless you specify the option `--no-apm'."
18757c478bd9Sstevel@tonic-gate };
18767c478bd9Sstevel@tonic-gate 
18777c478bd9Sstevel@tonic-gate 
18787c478bd9Sstevel@tonic-gate /* help */
18797c478bd9Sstevel@tonic-gate #define MAX_SHORT_DOC_LEN	39
18807c478bd9Sstevel@tonic-gate #define MAX_LONG_DOC_LEN	66
18817c478bd9Sstevel@tonic-gate 
18827c478bd9Sstevel@tonic-gate static int
18837c478bd9Sstevel@tonic-gate help_func (char *arg, int flags)
18847c478bd9Sstevel@tonic-gate {
18857c478bd9Sstevel@tonic-gate   int all = 0;
18867c478bd9Sstevel@tonic-gate 
18877c478bd9Sstevel@tonic-gate   if (grub_memcmp (arg, "--all", sizeof ("--all") - 1) == 0)
18887c478bd9Sstevel@tonic-gate     {
18897c478bd9Sstevel@tonic-gate       all = 1;
18907c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
18917c478bd9Sstevel@tonic-gate     }
18927c478bd9Sstevel@tonic-gate 
18937c478bd9Sstevel@tonic-gate   if (! *arg)
18947c478bd9Sstevel@tonic-gate     {
18957c478bd9Sstevel@tonic-gate       /* Invoked with no argument. Print the list of the short docs.  */
18967c478bd9Sstevel@tonic-gate       struct builtin **builtin;
18977c478bd9Sstevel@tonic-gate       int left = 1;
18987c478bd9Sstevel@tonic-gate 
18997c478bd9Sstevel@tonic-gate       for (builtin = builtin_table; *builtin != 0; builtin++)
19007c478bd9Sstevel@tonic-gate 	{
19017c478bd9Sstevel@tonic-gate 	  int len;
19027c478bd9Sstevel@tonic-gate 	  int i;
19037c478bd9Sstevel@tonic-gate 
19047c478bd9Sstevel@tonic-gate 	  /* If this cannot be used in the command-line interface,
19057c478bd9Sstevel@tonic-gate 	     skip this.  */
19067c478bd9Sstevel@tonic-gate 	  if (! ((*builtin)->flags & BUILTIN_CMDLINE))
19077c478bd9Sstevel@tonic-gate 	    continue;
19087c478bd9Sstevel@tonic-gate 
19097c478bd9Sstevel@tonic-gate 	  /* If this doesn't need to be listed automatically and "--all"
19107c478bd9Sstevel@tonic-gate 	     is not specified, skip this.  */
19117c478bd9Sstevel@tonic-gate 	  if (! all && ! ((*builtin)->flags & BUILTIN_HELP_LIST))
19127c478bd9Sstevel@tonic-gate 	    continue;
19137c478bd9Sstevel@tonic-gate 
19147c478bd9Sstevel@tonic-gate 	  len = grub_strlen ((*builtin)->short_doc);
19157c478bd9Sstevel@tonic-gate 	  /* If the length of SHORT_DOC is too long, truncate it.  */
19167c478bd9Sstevel@tonic-gate 	  if (len > MAX_SHORT_DOC_LEN - 1)
19177c478bd9Sstevel@tonic-gate 	    len = MAX_SHORT_DOC_LEN - 1;
19187c478bd9Sstevel@tonic-gate 
19197c478bd9Sstevel@tonic-gate 	  for (i = 0; i < len; i++)
19207c478bd9Sstevel@tonic-gate 	    grub_putchar ((*builtin)->short_doc[i]);
19217c478bd9Sstevel@tonic-gate 
19227c478bd9Sstevel@tonic-gate 	  for (; i < MAX_SHORT_DOC_LEN; i++)
19237c478bd9Sstevel@tonic-gate 	    grub_putchar (' ');
19247c478bd9Sstevel@tonic-gate 
19257c478bd9Sstevel@tonic-gate 	  if (! left)
19267c478bd9Sstevel@tonic-gate 	    grub_putchar ('\n');
19277c478bd9Sstevel@tonic-gate 
19287c478bd9Sstevel@tonic-gate 	  left = ! left;
19297c478bd9Sstevel@tonic-gate 	}
19307c478bd9Sstevel@tonic-gate 
19317c478bd9Sstevel@tonic-gate       /* If the last entry was at the left column, no newline was printed
19327c478bd9Sstevel@tonic-gate 	 at the end.  */
19337c478bd9Sstevel@tonic-gate       if (! left)
19347c478bd9Sstevel@tonic-gate 	grub_putchar ('\n');
19357c478bd9Sstevel@tonic-gate     }
19367c478bd9Sstevel@tonic-gate   else
19377c478bd9Sstevel@tonic-gate     {
19387c478bd9Sstevel@tonic-gate       /* Invoked with one or more patterns.  */
19397c478bd9Sstevel@tonic-gate       do
19407c478bd9Sstevel@tonic-gate 	{
19417c478bd9Sstevel@tonic-gate 	  struct builtin **builtin;
19427c478bd9Sstevel@tonic-gate 	  char *next_arg;
19437c478bd9Sstevel@tonic-gate 
19447c478bd9Sstevel@tonic-gate 	  /* Get the next argument.  */
19457c478bd9Sstevel@tonic-gate 	  next_arg = skip_to (0, arg);
19467c478bd9Sstevel@tonic-gate 
19477c478bd9Sstevel@tonic-gate 	  /* Terminate ARG.  */
19487c478bd9Sstevel@tonic-gate 	  nul_terminate (arg);
19497c478bd9Sstevel@tonic-gate 
19507c478bd9Sstevel@tonic-gate 	  for (builtin = builtin_table; *builtin; builtin++)
19517c478bd9Sstevel@tonic-gate 	    {
19527c478bd9Sstevel@tonic-gate 	      /* Skip this if this is only for the configuration file.  */
19537c478bd9Sstevel@tonic-gate 	      if (! ((*builtin)->flags & BUILTIN_CMDLINE))
19547c478bd9Sstevel@tonic-gate 		continue;
19557c478bd9Sstevel@tonic-gate 
19567c478bd9Sstevel@tonic-gate 	      if (substring (arg, (*builtin)->name) < 1)
19577c478bd9Sstevel@tonic-gate 		{
19587c478bd9Sstevel@tonic-gate 		  char *doc = (*builtin)->long_doc;
19597c478bd9Sstevel@tonic-gate 
19607c478bd9Sstevel@tonic-gate 		  /* At first, print the name and the short doc.  */
19617c478bd9Sstevel@tonic-gate 		  grub_printf ("%s: %s\n",
19627c478bd9Sstevel@tonic-gate 			       (*builtin)->name, (*builtin)->short_doc);
19637c478bd9Sstevel@tonic-gate 
19647c478bd9Sstevel@tonic-gate 		  /* Print the long doc.  */
19657c478bd9Sstevel@tonic-gate 		  while (*doc)
19667c478bd9Sstevel@tonic-gate 		    {
19677c478bd9Sstevel@tonic-gate 		      int len = grub_strlen (doc);
19687c478bd9Sstevel@tonic-gate 		      int i;
19697c478bd9Sstevel@tonic-gate 
19707c478bd9Sstevel@tonic-gate 		      /* If LEN is too long, fold DOC.  */
19717c478bd9Sstevel@tonic-gate 		      if (len > MAX_LONG_DOC_LEN)
19727c478bd9Sstevel@tonic-gate 			{
19737c478bd9Sstevel@tonic-gate 			  /* Fold this line at the position of a space.  */
19747c478bd9Sstevel@tonic-gate 			  for (len = MAX_LONG_DOC_LEN; len > 0; len--)
19757c478bd9Sstevel@tonic-gate 			    if (doc[len - 1] == ' ')
19767c478bd9Sstevel@tonic-gate 			      break;
19777c478bd9Sstevel@tonic-gate 			}
19787c478bd9Sstevel@tonic-gate 
19797c478bd9Sstevel@tonic-gate 		      grub_printf ("    ");
19807c478bd9Sstevel@tonic-gate 		      for (i = 0; i < len; i++)
19817c478bd9Sstevel@tonic-gate 			grub_putchar (*doc++);
19827c478bd9Sstevel@tonic-gate 		      grub_putchar ('\n');
19837c478bd9Sstevel@tonic-gate 		    }
19847c478bd9Sstevel@tonic-gate 		}
19857c478bd9Sstevel@tonic-gate 	    }
19867c478bd9Sstevel@tonic-gate 
19877c478bd9Sstevel@tonic-gate 	  arg = next_arg;
19887c478bd9Sstevel@tonic-gate 	}
19897c478bd9Sstevel@tonic-gate       while (*arg);
19907c478bd9Sstevel@tonic-gate     }
19917c478bd9Sstevel@tonic-gate 
19927c478bd9Sstevel@tonic-gate   return 0;
19937c478bd9Sstevel@tonic-gate }
19947c478bd9Sstevel@tonic-gate 
19957c478bd9Sstevel@tonic-gate static struct builtin builtin_help =
19967c478bd9Sstevel@tonic-gate {
19977c478bd9Sstevel@tonic-gate   "help",
19987c478bd9Sstevel@tonic-gate   help_func,
19997c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
20007c478bd9Sstevel@tonic-gate   "help [--all] [PATTERN ...]",
20017c478bd9Sstevel@tonic-gate   "Display helpful information about builtin commands. Not all commands"
20027c478bd9Sstevel@tonic-gate   " aren't shown without the option `--all'."
20037c478bd9Sstevel@tonic-gate };
20047c478bd9Sstevel@tonic-gate 
20057c478bd9Sstevel@tonic-gate 
20067c478bd9Sstevel@tonic-gate /* hiddenmenu */
20077c478bd9Sstevel@tonic-gate static int
20087c478bd9Sstevel@tonic-gate hiddenmenu_func (char *arg, int flags)
20097c478bd9Sstevel@tonic-gate {
20107c478bd9Sstevel@tonic-gate   show_menu = 0;
20117c478bd9Sstevel@tonic-gate   return 0;
20127c478bd9Sstevel@tonic-gate }
20137c478bd9Sstevel@tonic-gate 
20147c478bd9Sstevel@tonic-gate static struct builtin builtin_hiddenmenu =
20157c478bd9Sstevel@tonic-gate {
20167c478bd9Sstevel@tonic-gate   "hiddenmenu",
20177c478bd9Sstevel@tonic-gate   hiddenmenu_func,
20187c478bd9Sstevel@tonic-gate   BUILTIN_MENU,
20197c478bd9Sstevel@tonic-gate #if 0
20207c478bd9Sstevel@tonic-gate   "hiddenmenu",
20217c478bd9Sstevel@tonic-gate   "Hide the menu."
20227c478bd9Sstevel@tonic-gate #endif
20237c478bd9Sstevel@tonic-gate };
20247c478bd9Sstevel@tonic-gate 
20257c478bd9Sstevel@tonic-gate 
20267c478bd9Sstevel@tonic-gate /* hide */
20277c478bd9Sstevel@tonic-gate static int
20287c478bd9Sstevel@tonic-gate hide_func (char *arg, int flags)
20297c478bd9Sstevel@tonic-gate {
20307c478bd9Sstevel@tonic-gate   if (! set_device (arg))
20317c478bd9Sstevel@tonic-gate     return 1;
20327c478bd9Sstevel@tonic-gate 
20337c478bd9Sstevel@tonic-gate   if (! set_partition_hidden_flag (1))
20347c478bd9Sstevel@tonic-gate     return 1;
20357c478bd9Sstevel@tonic-gate 
20367c478bd9Sstevel@tonic-gate   return 0;
20377c478bd9Sstevel@tonic-gate }
20387c478bd9Sstevel@tonic-gate 
20397c478bd9Sstevel@tonic-gate static struct builtin builtin_hide =
20407c478bd9Sstevel@tonic-gate {
20417c478bd9Sstevel@tonic-gate   "hide",
20427c478bd9Sstevel@tonic-gate   hide_func,
20437c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
20447c478bd9Sstevel@tonic-gate   "hide PARTITION",
20457c478bd9Sstevel@tonic-gate   "Hide PARTITION by setting the \"hidden\" bit in"
20467c478bd9Sstevel@tonic-gate   " its partition type code."
20477c478bd9Sstevel@tonic-gate };
20487c478bd9Sstevel@tonic-gate 
20497c478bd9Sstevel@tonic-gate 
20507c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
20517c478bd9Sstevel@tonic-gate /* ifconfig */
20527c478bd9Sstevel@tonic-gate static int
20537c478bd9Sstevel@tonic-gate ifconfig_func (char *arg, int flags)
20547c478bd9Sstevel@tonic-gate {
20557c478bd9Sstevel@tonic-gate   char *svr = 0, *ip = 0, *gw = 0, *sm = 0;
20567c478bd9Sstevel@tonic-gate 
20577c478bd9Sstevel@tonic-gate   if (! grub_eth_probe ())
20587c478bd9Sstevel@tonic-gate     {
20597c478bd9Sstevel@tonic-gate       grub_printf ("No ethernet card found.\n");
20607c478bd9Sstevel@tonic-gate       errnum = ERR_DEV_VALUES;
20617c478bd9Sstevel@tonic-gate       return 1;
20627c478bd9Sstevel@tonic-gate     }
20637c478bd9Sstevel@tonic-gate 
20647c478bd9Sstevel@tonic-gate   while (*arg)
20657c478bd9Sstevel@tonic-gate     {
20667c478bd9Sstevel@tonic-gate       if (! grub_memcmp ("--server=", arg, sizeof ("--server=") - 1))
20677c478bd9Sstevel@tonic-gate 	svr = arg + sizeof("--server=") - 1;
20687c478bd9Sstevel@tonic-gate       else if (! grub_memcmp ("--address=", arg, sizeof ("--address=") - 1))
20697c478bd9Sstevel@tonic-gate 	ip = arg + sizeof ("--address=") - 1;
20707c478bd9Sstevel@tonic-gate       else if (! grub_memcmp ("--gateway=", arg, sizeof ("--gateway=") - 1))
20717c478bd9Sstevel@tonic-gate 	gw = arg + sizeof ("--gateway=") - 1;
20727c478bd9Sstevel@tonic-gate       else if (! grub_memcmp ("--mask=", arg, sizeof("--mask=") - 1))
20737c478bd9Sstevel@tonic-gate 	sm = arg + sizeof ("--mask=") - 1;
20747c478bd9Sstevel@tonic-gate       else
20757c478bd9Sstevel@tonic-gate 	{
20767c478bd9Sstevel@tonic-gate 	  errnum = ERR_BAD_ARGUMENT;
20777c478bd9Sstevel@tonic-gate 	  return 1;
20787c478bd9Sstevel@tonic-gate 	}
20797c478bd9Sstevel@tonic-gate 
20807c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
20817c478bd9Sstevel@tonic-gate     }
20827c478bd9Sstevel@tonic-gate 
20837c478bd9Sstevel@tonic-gate   if (! ifconfig (ip, sm, gw, svr))
20847c478bd9Sstevel@tonic-gate     {
20857c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
20867c478bd9Sstevel@tonic-gate       return 1;
20877c478bd9Sstevel@tonic-gate     }
20887c478bd9Sstevel@tonic-gate 
20897c478bd9Sstevel@tonic-gate   print_network_configuration ();
20907c478bd9Sstevel@tonic-gate   return 0;
20917c478bd9Sstevel@tonic-gate }
20927c478bd9Sstevel@tonic-gate 
20937c478bd9Sstevel@tonic-gate static struct builtin builtin_ifconfig =
20947c478bd9Sstevel@tonic-gate {
20957c478bd9Sstevel@tonic-gate   "ifconfig",
20967c478bd9Sstevel@tonic-gate   ifconfig_func,
20977c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
20987c478bd9Sstevel@tonic-gate   "ifconfig [--address=IP] [--gateway=IP] [--mask=MASK] [--server=IP]",
20997c478bd9Sstevel@tonic-gate   "Configure the IP address, the netmask, the gateway and the server"
21007c478bd9Sstevel@tonic-gate   " address or print current network configuration."
21017c478bd9Sstevel@tonic-gate };
21027c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
21037c478bd9Sstevel@tonic-gate 
21047c478bd9Sstevel@tonic-gate 
21057c478bd9Sstevel@tonic-gate /* impsprobe */
21067c478bd9Sstevel@tonic-gate static int
21077c478bd9Sstevel@tonic-gate impsprobe_func (char *arg, int flags)
21087c478bd9Sstevel@tonic-gate {
21097c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
21107c478bd9Sstevel@tonic-gate   /* In the grub shell, we cannot probe IMPS.  */
21117c478bd9Sstevel@tonic-gate   errnum = ERR_UNRECOGNIZED;
21127c478bd9Sstevel@tonic-gate   return 1;
21137c478bd9Sstevel@tonic-gate #else /* ! GRUB_UTIL */
21147c478bd9Sstevel@tonic-gate   if (!imps_probe ())
21157c478bd9Sstevel@tonic-gate     printf (" No MPS information found or probe failed\n");
21167c478bd9Sstevel@tonic-gate 
21177c478bd9Sstevel@tonic-gate   return 0;
21187c478bd9Sstevel@tonic-gate #endif /* ! GRUB_UTIL */
21197c478bd9Sstevel@tonic-gate }
21207c478bd9Sstevel@tonic-gate 
21217c478bd9Sstevel@tonic-gate static struct builtin builtin_impsprobe =
21227c478bd9Sstevel@tonic-gate {
21237c478bd9Sstevel@tonic-gate   "impsprobe",
21247c478bd9Sstevel@tonic-gate   impsprobe_func,
21257c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
21267c478bd9Sstevel@tonic-gate   "impsprobe",
21277c478bd9Sstevel@tonic-gate   "Probe the Intel Multiprocessor Specification 1.1 or 1.4"
21287c478bd9Sstevel@tonic-gate   " configuration table and boot the various CPUs which are found into"
21297c478bd9Sstevel@tonic-gate   " a tight loop."
21307c478bd9Sstevel@tonic-gate };
21317c478bd9Sstevel@tonic-gate 
21327c478bd9Sstevel@tonic-gate 
21337c478bd9Sstevel@tonic-gate /* initrd */
21347c478bd9Sstevel@tonic-gate static int
21357c478bd9Sstevel@tonic-gate initrd_func (char *arg, int flags)
21367c478bd9Sstevel@tonic-gate {
21377c478bd9Sstevel@tonic-gate   switch (kernel_type)
21387c478bd9Sstevel@tonic-gate     {
21397c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_LINUX:
21407c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_BIG_LINUX:
21417c478bd9Sstevel@tonic-gate       if (! load_initrd (arg))
21427c478bd9Sstevel@tonic-gate 	return 1;
21437c478bd9Sstevel@tonic-gate       break;
21447c478bd9Sstevel@tonic-gate 
21457c478bd9Sstevel@tonic-gate     default:
21467c478bd9Sstevel@tonic-gate       errnum = ERR_NEED_LX_KERNEL;
21477c478bd9Sstevel@tonic-gate       return 1;
21487c478bd9Sstevel@tonic-gate     }
21497c478bd9Sstevel@tonic-gate 
21507c478bd9Sstevel@tonic-gate   return 0;
21517c478bd9Sstevel@tonic-gate }
21527c478bd9Sstevel@tonic-gate 
21537c478bd9Sstevel@tonic-gate static struct builtin builtin_initrd =
21547c478bd9Sstevel@tonic-gate {
21557c478bd9Sstevel@tonic-gate   "initrd",
21567c478bd9Sstevel@tonic-gate   initrd_func,
21577c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
21587c478bd9Sstevel@tonic-gate   "initrd FILE [ARG ...]",
21597c478bd9Sstevel@tonic-gate   "Load an initial ramdisk FILE for a Linux format boot image and set the"
21607c478bd9Sstevel@tonic-gate   " appropriate parameters in the Linux setup area in memory."
21617c478bd9Sstevel@tonic-gate };
21627c478bd9Sstevel@tonic-gate 
21637c478bd9Sstevel@tonic-gate 
21647c478bd9Sstevel@tonic-gate /* install */
21657c478bd9Sstevel@tonic-gate static int
21667c478bd9Sstevel@tonic-gate install_func (char *arg, int flags)
21677c478bd9Sstevel@tonic-gate {
21687c478bd9Sstevel@tonic-gate   char *stage1_file, *dest_dev, *file, *addr;
21697c478bd9Sstevel@tonic-gate   char *stage1_buffer = (char *) RAW_ADDR (0x100000);
21707c478bd9Sstevel@tonic-gate   char *stage2_buffer = stage1_buffer + SECTOR_SIZE;
21717c478bd9Sstevel@tonic-gate   char *old_sect = stage2_buffer + SECTOR_SIZE;
21727c478bd9Sstevel@tonic-gate   char *stage2_first_buffer = old_sect + SECTOR_SIZE;
21737c478bd9Sstevel@tonic-gate   char *stage2_second_buffer = stage2_first_buffer + SECTOR_SIZE;
21747c478bd9Sstevel@tonic-gate   /* XXX: Probably SECTOR_SIZE is reasonable.  */
21757c478bd9Sstevel@tonic-gate   char *config_filename = stage2_second_buffer + SECTOR_SIZE;
21767c478bd9Sstevel@tonic-gate   char *dummy = config_filename + SECTOR_SIZE;
21777c478bd9Sstevel@tonic-gate   int new_drive = GRUB_INVALID_DRIVE;
2178342440ecSPrasad Singamsetty   int dest_drive, dest_partition;
2179342440ecSPrasad Singamsetty   unsigned int dest_sector;
21807c478bd9Sstevel@tonic-gate   int src_drive, src_partition, src_part_start;
21817c478bd9Sstevel@tonic-gate   int i;
21827c478bd9Sstevel@tonic-gate   struct geometry dest_geom, src_geom;
2183342440ecSPrasad Singamsetty   unsigned int saved_sector;
2184342440ecSPrasad Singamsetty   unsigned int stage2_first_sector, stage2_second_sector;
21857c478bd9Sstevel@tonic-gate   char *ptr;
21867c478bd9Sstevel@tonic-gate   int installaddr, installlist;
21877c478bd9Sstevel@tonic-gate   /* Point to the location of the name of a configuration file in Stage 2.  */
21887c478bd9Sstevel@tonic-gate   char *config_file_location;
21897c478bd9Sstevel@tonic-gate   /* If FILE is a Stage 1.5?  */
21907c478bd9Sstevel@tonic-gate   int is_stage1_5 = 0;
21917c478bd9Sstevel@tonic-gate   /* Must call grub_close?  */
21927c478bd9Sstevel@tonic-gate   int is_open = 0;
21937c478bd9Sstevel@tonic-gate   /* If LBA is forced?  */
21947c478bd9Sstevel@tonic-gate   int is_force_lba = 0;
21957c478bd9Sstevel@tonic-gate   /* Was the last sector full? */
21967c478bd9Sstevel@tonic-gate   int last_length = SECTOR_SIZE;
21977c478bd9Sstevel@tonic-gate 
21987c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
21997c478bd9Sstevel@tonic-gate   /* If the Stage 2 is in a partition mounted by an OS, this will store
22007c478bd9Sstevel@tonic-gate      the filename under the OS.  */
22017c478bd9Sstevel@tonic-gate   char *stage2_os_file = 0;
22027c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
22037c478bd9Sstevel@tonic-gate 
22041b8adde7SWilliam Kucharski   auto void disk_read_savesect_func (unsigned int sector, int offset,
22051b8adde7SWilliam Kucharski       int length);
22061b8adde7SWilliam Kucharski   auto void disk_read_blocklist_func (unsigned int sector, int offset,
22071b8adde7SWilliam Kucharski       int length);
22081b8adde7SWilliam Kucharski 
22097c478bd9Sstevel@tonic-gate   /* Save the first sector of Stage2 in STAGE2_SECT.  */
22101b8adde7SWilliam Kucharski   auto void disk_read_savesect_func (unsigned int sector, int offset,
22111b8adde7SWilliam Kucharski       int length)
22127c478bd9Sstevel@tonic-gate     {
22137c478bd9Sstevel@tonic-gate       if (debug)
2214342440ecSPrasad Singamsetty 	printf ("[%u]", sector);
22157c478bd9Sstevel@tonic-gate 
22167c478bd9Sstevel@tonic-gate       /* ReiserFS has files which sometimes contain data not aligned
22177c478bd9Sstevel@tonic-gate          on sector boundaries.  Returning an error is better than
22187c478bd9Sstevel@tonic-gate          silently failing. */
22197c478bd9Sstevel@tonic-gate       if (offset != 0 || length != SECTOR_SIZE)
22207c478bd9Sstevel@tonic-gate 	errnum = ERR_UNALIGNED;
22217c478bd9Sstevel@tonic-gate 
22227c478bd9Sstevel@tonic-gate       saved_sector = sector;
22237c478bd9Sstevel@tonic-gate     }
22247c478bd9Sstevel@tonic-gate 
22257c478bd9Sstevel@tonic-gate   /* Write SECTOR to INSTALLLIST, and update INSTALLADDR and
22267c478bd9Sstevel@tonic-gate      INSTALLSECT.  */
22271b8adde7SWilliam Kucharski   auto void disk_read_blocklist_func (unsigned int sector, int offset,
22281b8adde7SWilliam Kucharski       int length)
22297c478bd9Sstevel@tonic-gate     {
22307c478bd9Sstevel@tonic-gate       if (debug)
2231342440ecSPrasad Singamsetty 	printf("[%u]", sector);
22327c478bd9Sstevel@tonic-gate 
22337c478bd9Sstevel@tonic-gate       if (offset != 0 || last_length != SECTOR_SIZE)
22347c478bd9Sstevel@tonic-gate 	{
22357c478bd9Sstevel@tonic-gate 	  /* We found a non-sector-aligned data block. */
22367c478bd9Sstevel@tonic-gate 	  errnum = ERR_UNALIGNED;
22377c478bd9Sstevel@tonic-gate 	  return;
22387c478bd9Sstevel@tonic-gate 	}
22397c478bd9Sstevel@tonic-gate 
22407c478bd9Sstevel@tonic-gate       last_length = length;
22417c478bd9Sstevel@tonic-gate 
22427c478bd9Sstevel@tonic-gate       if (*((unsigned long *) (installlist - 4))
22437c478bd9Sstevel@tonic-gate 	  + *((unsigned short *) installlist) != sector
22447c478bd9Sstevel@tonic-gate 	  || installlist == (int) stage2_first_buffer + SECTOR_SIZE + 4)
22457c478bd9Sstevel@tonic-gate 	{
22467c478bd9Sstevel@tonic-gate 	  installlist -= 8;
22477c478bd9Sstevel@tonic-gate 
22487c478bd9Sstevel@tonic-gate 	  if (*((unsigned long *) (installlist - 8)))
22497c478bd9Sstevel@tonic-gate 	    errnum = ERR_WONT_FIT;
22507c478bd9Sstevel@tonic-gate 	  else
22517c478bd9Sstevel@tonic-gate 	    {
22527c478bd9Sstevel@tonic-gate 	      *((unsigned short *) (installlist + 2)) = (installaddr >> 4);
22537c478bd9Sstevel@tonic-gate 	      *((unsigned long *) (installlist - 4)) = sector;
22547c478bd9Sstevel@tonic-gate 	    }
22557c478bd9Sstevel@tonic-gate 	}
22567c478bd9Sstevel@tonic-gate 
22577c478bd9Sstevel@tonic-gate       *((unsigned short *) installlist) += 1;
22587c478bd9Sstevel@tonic-gate       installaddr += 512;
22597c478bd9Sstevel@tonic-gate     }
22607c478bd9Sstevel@tonic-gate 
22617c478bd9Sstevel@tonic-gate   /* First, check the GNU-style long option.  */
22627c478bd9Sstevel@tonic-gate   while (1)
22637c478bd9Sstevel@tonic-gate     {
22647c478bd9Sstevel@tonic-gate       if (grub_memcmp ("--force-lba", arg, sizeof ("--force-lba") - 1) == 0)
22657c478bd9Sstevel@tonic-gate 	{
22667c478bd9Sstevel@tonic-gate 	  is_force_lba = 1;
22677c478bd9Sstevel@tonic-gate 	  arg = skip_to (0, arg);
22687c478bd9Sstevel@tonic-gate 	}
22697c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
22707c478bd9Sstevel@tonic-gate       else if (grub_memcmp ("--stage2=", arg, sizeof ("--stage2=") - 1) == 0)
22717c478bd9Sstevel@tonic-gate 	{
22727c478bd9Sstevel@tonic-gate 	  stage2_os_file = arg + sizeof ("--stage2=") - 1;
22737c478bd9Sstevel@tonic-gate 	  arg = skip_to (0, arg);
22747c478bd9Sstevel@tonic-gate 	  nul_terminate (stage2_os_file);
22757c478bd9Sstevel@tonic-gate 	}
22767c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
22777c478bd9Sstevel@tonic-gate       else
22787c478bd9Sstevel@tonic-gate 	break;
22797c478bd9Sstevel@tonic-gate     }
22807c478bd9Sstevel@tonic-gate 
22817c478bd9Sstevel@tonic-gate   stage1_file = arg;
22827c478bd9Sstevel@tonic-gate   dest_dev = skip_to (0, stage1_file);
22837c478bd9Sstevel@tonic-gate   if (*dest_dev == 'd')
22847c478bd9Sstevel@tonic-gate     {
22857c478bd9Sstevel@tonic-gate       new_drive = 0;
22867c478bd9Sstevel@tonic-gate       dest_dev = skip_to (0, dest_dev);
22877c478bd9Sstevel@tonic-gate     }
22887c478bd9Sstevel@tonic-gate   file = skip_to (0, dest_dev);
22897c478bd9Sstevel@tonic-gate   addr = skip_to (0, file);
22907c478bd9Sstevel@tonic-gate 
22917c478bd9Sstevel@tonic-gate   /* Get the installation address.  */
22927c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&addr, &installaddr))
22937c478bd9Sstevel@tonic-gate     {
22947c478bd9Sstevel@tonic-gate       /* ADDR is not specified.  */
22957c478bd9Sstevel@tonic-gate       installaddr = 0;
22967c478bd9Sstevel@tonic-gate       ptr = addr;
22977c478bd9Sstevel@tonic-gate       errnum = 0;
22987c478bd9Sstevel@tonic-gate     }
22997c478bd9Sstevel@tonic-gate   else
23007c478bd9Sstevel@tonic-gate     ptr = skip_to (0, addr);
23017c478bd9Sstevel@tonic-gate 
23027c478bd9Sstevel@tonic-gate #ifndef NO_DECOMPRESSION
23037c478bd9Sstevel@tonic-gate   /* Do not decompress Stage 1 or Stage 2.  */
23047c478bd9Sstevel@tonic-gate   no_decompression = 1;
23057c478bd9Sstevel@tonic-gate #endif
23067c478bd9Sstevel@tonic-gate 
23077c478bd9Sstevel@tonic-gate   /* Read Stage 1.  */
23087c478bd9Sstevel@tonic-gate   is_open = grub_open (stage1_file);
23097c478bd9Sstevel@tonic-gate   if (! is_open
23107c478bd9Sstevel@tonic-gate       || ! grub_read (stage1_buffer, SECTOR_SIZE) == SECTOR_SIZE)
23117c478bd9Sstevel@tonic-gate     goto fail;
23127c478bd9Sstevel@tonic-gate 
23137c478bd9Sstevel@tonic-gate   /* Read the old sector from DEST_DEV.  */
23147c478bd9Sstevel@tonic-gate   if (! set_device (dest_dev)
23157c478bd9Sstevel@tonic-gate       || ! open_partition ()
23167c478bd9Sstevel@tonic-gate       || ! devread (0, 0, SECTOR_SIZE, old_sect))
23177c478bd9Sstevel@tonic-gate     goto fail;
23187c478bd9Sstevel@tonic-gate 
23197c478bd9Sstevel@tonic-gate   /* Store the information for the destination device.  */
23207c478bd9Sstevel@tonic-gate   dest_drive = current_drive;
23217c478bd9Sstevel@tonic-gate   dest_partition = current_partition;
23227c478bd9Sstevel@tonic-gate   dest_geom = buf_geom;
23237c478bd9Sstevel@tonic-gate   dest_sector = part_start;
23247c478bd9Sstevel@tonic-gate 
23257c478bd9Sstevel@tonic-gate   /* Copy the possible DOS BPB, 59 bytes at byte offset 3.  */
23267c478bd9Sstevel@tonic-gate   grub_memmove (stage1_buffer + BOOTSEC_BPB_OFFSET,
23277c478bd9Sstevel@tonic-gate 		old_sect + BOOTSEC_BPB_OFFSET,
23287c478bd9Sstevel@tonic-gate 		BOOTSEC_BPB_LENGTH);
23297c478bd9Sstevel@tonic-gate 
23307c478bd9Sstevel@tonic-gate   /* If for a hard disk, copy the possible MBR/extended part table.  */
23317c478bd9Sstevel@tonic-gate   if (dest_drive & 0x80)
23327c478bd9Sstevel@tonic-gate     grub_memmove (stage1_buffer + STAGE1_WINDOWS_NT_MAGIC,
23337c478bd9Sstevel@tonic-gate 		  old_sect + STAGE1_WINDOWS_NT_MAGIC,
23347c478bd9Sstevel@tonic-gate 		  STAGE1_PARTEND - STAGE1_WINDOWS_NT_MAGIC);
23357c478bd9Sstevel@tonic-gate 
23367c478bd9Sstevel@tonic-gate   /* Check for the version and the signature of Stage 1.  */
23377c478bd9Sstevel@tonic-gate   if (*((short *)(stage1_buffer + STAGE1_VER_MAJ_OFFS)) != COMPAT_VERSION
23387c478bd9Sstevel@tonic-gate       || (*((unsigned short *) (stage1_buffer + BOOTSEC_SIG_OFFSET))
23397c478bd9Sstevel@tonic-gate 	  != BOOTSEC_SIGNATURE))
23407c478bd9Sstevel@tonic-gate     {
23417c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_VERSION;
23427c478bd9Sstevel@tonic-gate       goto fail;
23437c478bd9Sstevel@tonic-gate     }
23447c478bd9Sstevel@tonic-gate 
23457c478bd9Sstevel@tonic-gate   /* This below is not true any longer. But should we leave this alone?  */
23467c478bd9Sstevel@tonic-gate 
23477c478bd9Sstevel@tonic-gate   /* If DEST_DRIVE is a floppy, Stage 2 must have the iteration probe
23487c478bd9Sstevel@tonic-gate      routine.  */
23497c478bd9Sstevel@tonic-gate   if (! (dest_drive & 0x80)
23507c478bd9Sstevel@tonic-gate       && (*((unsigned char *) (stage1_buffer + BOOTSEC_PART_OFFSET)) == 0x80
23517c478bd9Sstevel@tonic-gate 	  || stage1_buffer[BOOTSEC_PART_OFFSET] == 0))
23527c478bd9Sstevel@tonic-gate     {
23537c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_VERSION;
23547c478bd9Sstevel@tonic-gate       goto fail;
23557c478bd9Sstevel@tonic-gate     }
23567c478bd9Sstevel@tonic-gate 
23577c478bd9Sstevel@tonic-gate   grub_close ();
23587c478bd9Sstevel@tonic-gate 
23597c478bd9Sstevel@tonic-gate   /* Open Stage 2.  */
23607c478bd9Sstevel@tonic-gate   is_open = grub_open (file);
23617c478bd9Sstevel@tonic-gate   if (! is_open)
23627c478bd9Sstevel@tonic-gate     goto fail;
23637c478bd9Sstevel@tonic-gate 
23647c478bd9Sstevel@tonic-gate   src_drive = current_drive;
23657c478bd9Sstevel@tonic-gate   src_partition = current_partition;
23667c478bd9Sstevel@tonic-gate   src_part_start = part_start;
23677c478bd9Sstevel@tonic-gate   src_geom = buf_geom;
23687c478bd9Sstevel@tonic-gate 
23697c478bd9Sstevel@tonic-gate   if (! new_drive)
23707c478bd9Sstevel@tonic-gate     new_drive = src_drive;
23717c478bd9Sstevel@tonic-gate   else if (src_drive != dest_drive)
23727c478bd9Sstevel@tonic-gate     grub_printf ("Warning: the option `d' was not used, but the Stage 1 will"
23737c478bd9Sstevel@tonic-gate 		 " be installed on a\ndifferent drive than the drive where"
23747c478bd9Sstevel@tonic-gate 		 " the Stage 2 resides.\n");
23757c478bd9Sstevel@tonic-gate 
23767c478bd9Sstevel@tonic-gate   /* Set the boot drive.  */
23777c478bd9Sstevel@tonic-gate   *((unsigned char *) (stage1_buffer + STAGE1_BOOT_DRIVE)) = new_drive;
23787c478bd9Sstevel@tonic-gate 
23797c478bd9Sstevel@tonic-gate   /* Set the "force LBA" flag.  */
23807c478bd9Sstevel@tonic-gate   *((unsigned char *) (stage1_buffer + STAGE1_FORCE_LBA)) = is_force_lba;
23817c478bd9Sstevel@tonic-gate 
23821b8adde7SWilliam Kucharski   /* If DEST_DRIVE is a hard disk, enable the workaround, which is
23831b8adde7SWilliam Kucharski      for buggy BIOSes which don't pass boot drive correctly. Instead,
23841b8adde7SWilliam Kucharski      they pass 0x00 or 0x01 even when booted from 0x80.  */
23851b8adde7SWilliam Kucharski   if (dest_drive & BIOS_FLAG_FIXED_DISK)
23861b8adde7SWilliam Kucharski     /* Replace the jmp (2 bytes) with double nop's.  */
23871b8adde7SWilliam Kucharski     *((unsigned short *) (stage1_buffer + STAGE1_BOOT_DRIVE_CHECK))
23881b8adde7SWilliam Kucharski       = 0x9090;
23891b8adde7SWilliam Kucharski 
23907c478bd9Sstevel@tonic-gate   /* Read the first sector of Stage 2.  */
23917c478bd9Sstevel@tonic-gate   disk_read_hook = disk_read_savesect_func;
23927c478bd9Sstevel@tonic-gate   if (grub_read (stage2_first_buffer, SECTOR_SIZE) != SECTOR_SIZE)
23937c478bd9Sstevel@tonic-gate     goto fail;
23947c478bd9Sstevel@tonic-gate 
23957c478bd9Sstevel@tonic-gate   stage2_first_sector = saved_sector;
23967c478bd9Sstevel@tonic-gate 
23977c478bd9Sstevel@tonic-gate   /* Read the second sector of Stage 2.  */
23987c478bd9Sstevel@tonic-gate   if (grub_read (stage2_second_buffer, SECTOR_SIZE) != SECTOR_SIZE)
23997c478bd9Sstevel@tonic-gate     goto fail;
24007c478bd9Sstevel@tonic-gate 
24017c478bd9Sstevel@tonic-gate   stage2_second_sector = saved_sector;
24027c478bd9Sstevel@tonic-gate 
24037c478bd9Sstevel@tonic-gate   /* Check for the version of Stage 2.  */
24047c478bd9Sstevel@tonic-gate   if (*((short *) (stage2_second_buffer + STAGE2_VER_MAJ_OFFS))
24057c478bd9Sstevel@tonic-gate       != COMPAT_VERSION)
24067c478bd9Sstevel@tonic-gate     {
24077c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_VERSION;
24087c478bd9Sstevel@tonic-gate       goto fail;
24097c478bd9Sstevel@tonic-gate     }
24107c478bd9Sstevel@tonic-gate 
24117c478bd9Sstevel@tonic-gate   /* Check for the Stage 2 id.  */
24127c478bd9Sstevel@tonic-gate   if (stage2_second_buffer[STAGE2_STAGE2_ID] != STAGE2_ID_STAGE2)
24137c478bd9Sstevel@tonic-gate     is_stage1_5 = 1;
24147c478bd9Sstevel@tonic-gate 
24157c478bd9Sstevel@tonic-gate   /* If INSTALLADDR is not specified explicitly in the command-line,
24167c478bd9Sstevel@tonic-gate      determine it by the Stage 2 id.  */
24177c478bd9Sstevel@tonic-gate   if (! installaddr)
24187c478bd9Sstevel@tonic-gate     {
24197c478bd9Sstevel@tonic-gate       if (! is_stage1_5)
24207c478bd9Sstevel@tonic-gate 	/* Stage 2.  */
24217c478bd9Sstevel@tonic-gate 	installaddr = 0x8000;
24227c478bd9Sstevel@tonic-gate       else
24237c478bd9Sstevel@tonic-gate 	/* Stage 1.5.  */
24247c478bd9Sstevel@tonic-gate 	installaddr = 0x2000;
24257c478bd9Sstevel@tonic-gate     }
24267c478bd9Sstevel@tonic-gate 
24277c478bd9Sstevel@tonic-gate   *((unsigned long *) (stage1_buffer + STAGE1_STAGE2_SECTOR))
24287c478bd9Sstevel@tonic-gate     = stage2_first_sector;
24297c478bd9Sstevel@tonic-gate   *((unsigned short *) (stage1_buffer + STAGE1_STAGE2_ADDRESS))
24307c478bd9Sstevel@tonic-gate     = installaddr;
24317c478bd9Sstevel@tonic-gate   *((unsigned short *) (stage1_buffer + STAGE1_STAGE2_SEGMENT))
24327c478bd9Sstevel@tonic-gate     = installaddr >> 4;
24337c478bd9Sstevel@tonic-gate 
24347c478bd9Sstevel@tonic-gate   i = (int) stage2_first_buffer + SECTOR_SIZE - 4;
24357c478bd9Sstevel@tonic-gate   while (*((unsigned long *) i))
24367c478bd9Sstevel@tonic-gate     {
24377c478bd9Sstevel@tonic-gate       if (i < (int) stage2_first_buffer
24387c478bd9Sstevel@tonic-gate 	  || (*((int *) (i - 4)) & 0x80000000)
24397c478bd9Sstevel@tonic-gate 	  || *((unsigned short *) i) >= 0xA00
24407c478bd9Sstevel@tonic-gate 	  || *((short *) (i + 2)) == 0)
24417c478bd9Sstevel@tonic-gate 	{
24427c478bd9Sstevel@tonic-gate 	  errnum = ERR_BAD_VERSION;
24437c478bd9Sstevel@tonic-gate 	  goto fail;
24447c478bd9Sstevel@tonic-gate 	}
24457c478bd9Sstevel@tonic-gate 
24467c478bd9Sstevel@tonic-gate       *((int *) i) = 0;
24477c478bd9Sstevel@tonic-gate       *((int *) (i - 4)) = 0;
24487c478bd9Sstevel@tonic-gate       i -= 8;
24497c478bd9Sstevel@tonic-gate     }
24507c478bd9Sstevel@tonic-gate 
24517c478bd9Sstevel@tonic-gate   installlist = (int) stage2_first_buffer + SECTOR_SIZE + 4;
24527c478bd9Sstevel@tonic-gate   installaddr += SECTOR_SIZE;
24537c478bd9Sstevel@tonic-gate 
24547c478bd9Sstevel@tonic-gate   /* Read the whole of Stage2 except for the first sector.  */
24557c478bd9Sstevel@tonic-gate   grub_seek (SECTOR_SIZE);
24567c478bd9Sstevel@tonic-gate 
24577c478bd9Sstevel@tonic-gate   disk_read_hook = disk_read_blocklist_func;
24587c478bd9Sstevel@tonic-gate   if (! grub_read (dummy, -1))
24597c478bd9Sstevel@tonic-gate     goto fail;
24607c478bd9Sstevel@tonic-gate 
24617c478bd9Sstevel@tonic-gate   disk_read_hook = 0;
24627c478bd9Sstevel@tonic-gate 
24637c478bd9Sstevel@tonic-gate   /* Find a string for the configuration filename.  */
24647c478bd9Sstevel@tonic-gate   config_file_location = stage2_second_buffer + STAGE2_VER_STR_OFFS;
24657c478bd9Sstevel@tonic-gate   while (*(config_file_location++))
24667c478bd9Sstevel@tonic-gate     ;
24677c478bd9Sstevel@tonic-gate 
24687c478bd9Sstevel@tonic-gate   /* Set the "force LBA" flag for Stage2.  */
24697c478bd9Sstevel@tonic-gate   *((unsigned char *) (stage2_second_buffer + STAGE2_FORCE_LBA))
24707c478bd9Sstevel@tonic-gate     = is_force_lba;
24717c478bd9Sstevel@tonic-gate 
24727c478bd9Sstevel@tonic-gate   if (*ptr == 'p')
24737c478bd9Sstevel@tonic-gate     {
24747c478bd9Sstevel@tonic-gate       *((long *) (stage2_second_buffer + STAGE2_INSTALLPART))
24757c478bd9Sstevel@tonic-gate 	= src_partition;
24767c478bd9Sstevel@tonic-gate       if (is_stage1_5)
24777c478bd9Sstevel@tonic-gate 	{
24787c478bd9Sstevel@tonic-gate 	  /* Reset the device information in FILE if it is a Stage 1.5.  */
24797c478bd9Sstevel@tonic-gate 	  unsigned long device = 0xFFFFFFFF;
24807c478bd9Sstevel@tonic-gate 
24817c478bd9Sstevel@tonic-gate 	  grub_memmove (config_file_location, (char *) &device,
24827c478bd9Sstevel@tonic-gate 			sizeof (device));
24837c478bd9Sstevel@tonic-gate 	}
24847c478bd9Sstevel@tonic-gate 
24857c478bd9Sstevel@tonic-gate       ptr = skip_to (0, ptr);
24867c478bd9Sstevel@tonic-gate     }
24877c478bd9Sstevel@tonic-gate 
24887c478bd9Sstevel@tonic-gate   if (*ptr)
24897c478bd9Sstevel@tonic-gate     {
24907c478bd9Sstevel@tonic-gate       grub_strcpy (config_filename, ptr);
24917c478bd9Sstevel@tonic-gate       nul_terminate (config_filename);
24927c478bd9Sstevel@tonic-gate 
24937c478bd9Sstevel@tonic-gate       if (! is_stage1_5)
24947c478bd9Sstevel@tonic-gate 	/* If it is a Stage 2, just copy PTR to CONFIG_FILE_LOCATION.  */
24957c478bd9Sstevel@tonic-gate 	grub_strcpy (config_file_location, ptr);
24967c478bd9Sstevel@tonic-gate       else
24977c478bd9Sstevel@tonic-gate 	{
24987c478bd9Sstevel@tonic-gate 	  char *real_config;
24997c478bd9Sstevel@tonic-gate 	  unsigned long device;
25007c478bd9Sstevel@tonic-gate 
25017c478bd9Sstevel@tonic-gate 	  /* Translate the external device syntax to the internal device
25027c478bd9Sstevel@tonic-gate 	     syntax.  */
25037c478bd9Sstevel@tonic-gate 	  if (! (real_config = set_device (ptr)))
25047c478bd9Sstevel@tonic-gate 	    {
25057c478bd9Sstevel@tonic-gate 	      /* The Stage 2 PTR does not contain the device name, so
25067c478bd9Sstevel@tonic-gate 		 use the root device instead.  */
25077c478bd9Sstevel@tonic-gate 	      errnum = ERR_NONE;
25087c478bd9Sstevel@tonic-gate 	      current_drive = saved_drive;
25097c478bd9Sstevel@tonic-gate 	      current_partition = saved_partition;
25107c478bd9Sstevel@tonic-gate 	      real_config = ptr;
25117c478bd9Sstevel@tonic-gate 	    }
25127c478bd9Sstevel@tonic-gate 
25137c478bd9Sstevel@tonic-gate 	  if (current_drive == src_drive)
25147c478bd9Sstevel@tonic-gate 	    {
25157c478bd9Sstevel@tonic-gate 	      /* If the drive where the Stage 2 resides is the same as
25167c478bd9Sstevel@tonic-gate 		 the one where the Stage 1.5 resides, do not embed the
25177c478bd9Sstevel@tonic-gate 		 drive number.  */
25187c478bd9Sstevel@tonic-gate 	      current_drive = GRUB_INVALID_DRIVE;
25197c478bd9Sstevel@tonic-gate 	    }
25207c478bd9Sstevel@tonic-gate 
25217c478bd9Sstevel@tonic-gate 	  device = (current_drive << 24) | current_partition;
25227c478bd9Sstevel@tonic-gate 	  grub_memmove (config_file_location, (char *) &device,
25237c478bd9Sstevel@tonic-gate 			sizeof (device));
25247c478bd9Sstevel@tonic-gate 	  grub_strcpy (config_file_location + sizeof (device),
25257c478bd9Sstevel@tonic-gate 		       real_config);
25267c478bd9Sstevel@tonic-gate 	}
25277c478bd9Sstevel@tonic-gate 
25287c478bd9Sstevel@tonic-gate       /* If a Stage 1.5 is used, then we need to modify the Stage2.  */
25297c478bd9Sstevel@tonic-gate       if (is_stage1_5)
25307c478bd9Sstevel@tonic-gate 	{
25317c478bd9Sstevel@tonic-gate 	  char *real_config_filename = skip_to (0, ptr);
25327c478bd9Sstevel@tonic-gate 
25337c478bd9Sstevel@tonic-gate 	  is_open = grub_open (config_filename);
25347c478bd9Sstevel@tonic-gate 	  if (! is_open)
25357c478bd9Sstevel@tonic-gate 	    goto fail;
25367c478bd9Sstevel@tonic-gate 
25377c478bd9Sstevel@tonic-gate 	  /* Skip the first sector.  */
25387c478bd9Sstevel@tonic-gate 	  grub_seek (SECTOR_SIZE);
25397c478bd9Sstevel@tonic-gate 
25407c478bd9Sstevel@tonic-gate 	  disk_read_hook = disk_read_savesect_func;
25417c478bd9Sstevel@tonic-gate 	  if (grub_read (stage2_buffer, SECTOR_SIZE) != SECTOR_SIZE)
25427c478bd9Sstevel@tonic-gate 	    goto fail;
25437c478bd9Sstevel@tonic-gate 
25447c478bd9Sstevel@tonic-gate 	  disk_read_hook = 0;
25457c478bd9Sstevel@tonic-gate 	  grub_close ();
25467c478bd9Sstevel@tonic-gate 	  is_open = 0;
25477c478bd9Sstevel@tonic-gate 
25487c478bd9Sstevel@tonic-gate 	  /* Sanity check.  */
25497c478bd9Sstevel@tonic-gate 	  if (*(stage2_buffer + STAGE2_STAGE2_ID) != STAGE2_ID_STAGE2)
25507c478bd9Sstevel@tonic-gate 	    {
25517c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_VERSION;
25527c478bd9Sstevel@tonic-gate 	      goto fail;
25537c478bd9Sstevel@tonic-gate 	    }
25547c478bd9Sstevel@tonic-gate 
25557c478bd9Sstevel@tonic-gate 	  /* Set the "force LBA" flag for Stage2.  */
25567c478bd9Sstevel@tonic-gate 	  *(stage2_buffer + STAGE2_FORCE_LBA) = is_force_lba;
25577c478bd9Sstevel@tonic-gate 
25587c478bd9Sstevel@tonic-gate 	  /* If REAL_CONFIG_FILENAME is specified, copy it to the Stage2.  */
25597c478bd9Sstevel@tonic-gate 	  if (*real_config_filename)
25607c478bd9Sstevel@tonic-gate 	    {
25617c478bd9Sstevel@tonic-gate 	      /* Specified */
25627c478bd9Sstevel@tonic-gate 	      char *location;
25637c478bd9Sstevel@tonic-gate 
25647c478bd9Sstevel@tonic-gate 	      /* Find a string for the configuration filename.  */
25657c478bd9Sstevel@tonic-gate 	      location = stage2_buffer + STAGE2_VER_STR_OFFS;
25667c478bd9Sstevel@tonic-gate 	      while (*(location++))
25677c478bd9Sstevel@tonic-gate 		;
25687c478bd9Sstevel@tonic-gate 
25697c478bd9Sstevel@tonic-gate 	      /* Copy the name.  */
25707c478bd9Sstevel@tonic-gate 	      grub_strcpy (location, real_config_filename);
25717c478bd9Sstevel@tonic-gate 	    }
25727c478bd9Sstevel@tonic-gate 
25737c478bd9Sstevel@tonic-gate 	  /* Write it to the disk.  */
2574342440ecSPrasad Singamsetty 	  buf_track = BUF_CACHE_INVALID;
25757c478bd9Sstevel@tonic-gate 
25767c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
25777c478bd9Sstevel@tonic-gate 	  /* In the grub shell, access the Stage 2 via the OS filesystem
25787c478bd9Sstevel@tonic-gate 	     service, if possible.  */
25797c478bd9Sstevel@tonic-gate 	  if (stage2_os_file)
25807c478bd9Sstevel@tonic-gate 	    {
25817c478bd9Sstevel@tonic-gate 	      FILE *fp;
25827c478bd9Sstevel@tonic-gate 
25837c478bd9Sstevel@tonic-gate 	      fp = fopen (stage2_os_file, "r+");
25847c478bd9Sstevel@tonic-gate 	      if (! fp)
25857c478bd9Sstevel@tonic-gate 		{
25867c478bd9Sstevel@tonic-gate 		  errnum = ERR_FILE_NOT_FOUND;
25877c478bd9Sstevel@tonic-gate 		  goto fail;
25887c478bd9Sstevel@tonic-gate 		}
25897c478bd9Sstevel@tonic-gate 
25907c478bd9Sstevel@tonic-gate 	      if (fseek (fp, SECTOR_SIZE, SEEK_SET) != 0)
25917c478bd9Sstevel@tonic-gate 		{
25927c478bd9Sstevel@tonic-gate 		  fclose (fp);
25937c478bd9Sstevel@tonic-gate 		  errnum = ERR_BAD_VERSION;
25947c478bd9Sstevel@tonic-gate 		  goto fail;
25957c478bd9Sstevel@tonic-gate 		}
25967c478bd9Sstevel@tonic-gate 
25977c478bd9Sstevel@tonic-gate 	      if (fwrite (stage2_buffer, 1, SECTOR_SIZE, fp)
25987c478bd9Sstevel@tonic-gate 		  != SECTOR_SIZE)
25997c478bd9Sstevel@tonic-gate 		{
26007c478bd9Sstevel@tonic-gate 		  fclose (fp);
26017c478bd9Sstevel@tonic-gate 		  errnum = ERR_WRITE;
26027c478bd9Sstevel@tonic-gate 		  goto fail;
26037c478bd9Sstevel@tonic-gate 		}
26047c478bd9Sstevel@tonic-gate 
26057c478bd9Sstevel@tonic-gate 	      fclose (fp);
26067c478bd9Sstevel@tonic-gate 	    }
26077c478bd9Sstevel@tonic-gate 	  else
26087c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
26097c478bd9Sstevel@tonic-gate 	    {
26107c478bd9Sstevel@tonic-gate 	      if (! devwrite (saved_sector - part_start, 1, stage2_buffer))
26117c478bd9Sstevel@tonic-gate 		goto fail;
26127c478bd9Sstevel@tonic-gate 	    }
26137c478bd9Sstevel@tonic-gate 	}
26147c478bd9Sstevel@tonic-gate     }
26157c478bd9Sstevel@tonic-gate 
26167c478bd9Sstevel@tonic-gate   /* Clear the cache.  */
2617342440ecSPrasad Singamsetty   buf_track = BUF_CACHE_INVALID;
26187c478bd9Sstevel@tonic-gate 
26197c478bd9Sstevel@tonic-gate   /* Write the modified sectors of Stage2 to the disk.  */
26207c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
26217c478bd9Sstevel@tonic-gate   if (! is_stage1_5 && stage2_os_file)
26227c478bd9Sstevel@tonic-gate     {
26237c478bd9Sstevel@tonic-gate       FILE *fp;
26247c478bd9Sstevel@tonic-gate 
26257c478bd9Sstevel@tonic-gate       fp = fopen (stage2_os_file, "r+");
26267c478bd9Sstevel@tonic-gate       if (! fp)
26277c478bd9Sstevel@tonic-gate 	{
26287c478bd9Sstevel@tonic-gate 	  errnum = ERR_FILE_NOT_FOUND;
26297c478bd9Sstevel@tonic-gate 	  goto fail;
26307c478bd9Sstevel@tonic-gate 	}
26317c478bd9Sstevel@tonic-gate 
26327c478bd9Sstevel@tonic-gate       if (fwrite (stage2_first_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE)
26337c478bd9Sstevel@tonic-gate 	{
26347c478bd9Sstevel@tonic-gate 	  fclose (fp);
26357c478bd9Sstevel@tonic-gate 	  errnum = ERR_WRITE;
26367c478bd9Sstevel@tonic-gate 	  goto fail;
26377c478bd9Sstevel@tonic-gate 	}
26387c478bd9Sstevel@tonic-gate 
26397c478bd9Sstevel@tonic-gate       if (fwrite (stage2_second_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE)
26407c478bd9Sstevel@tonic-gate 	{
26417c478bd9Sstevel@tonic-gate 	  fclose (fp);
26427c478bd9Sstevel@tonic-gate 	  errnum = ERR_WRITE;
26437c478bd9Sstevel@tonic-gate 	  goto fail;
26447c478bd9Sstevel@tonic-gate 	}
26457c478bd9Sstevel@tonic-gate 
26467c478bd9Sstevel@tonic-gate       fclose (fp);
26477c478bd9Sstevel@tonic-gate     }
26487c478bd9Sstevel@tonic-gate   else
26497c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
26507c478bd9Sstevel@tonic-gate     {
26517c478bd9Sstevel@tonic-gate       /* The first.  */
26527c478bd9Sstevel@tonic-gate       current_drive = src_drive;
26537c478bd9Sstevel@tonic-gate       current_partition = src_partition;
26547c478bd9Sstevel@tonic-gate 
26557c478bd9Sstevel@tonic-gate       if (! open_partition ())
26567c478bd9Sstevel@tonic-gate 	goto fail;
26577c478bd9Sstevel@tonic-gate 
26587c478bd9Sstevel@tonic-gate       if (! devwrite (stage2_first_sector - src_part_start, 1,
26597c478bd9Sstevel@tonic-gate 		      stage2_first_buffer))
26607c478bd9Sstevel@tonic-gate 	goto fail;
26617c478bd9Sstevel@tonic-gate 
26627c478bd9Sstevel@tonic-gate       if (! devwrite (stage2_second_sector - src_part_start, 1,
26637c478bd9Sstevel@tonic-gate 		      stage2_second_buffer))
26647c478bd9Sstevel@tonic-gate 	goto fail;
26657c478bd9Sstevel@tonic-gate     }
26667c478bd9Sstevel@tonic-gate 
26677c478bd9Sstevel@tonic-gate   /* Write the modified sector of Stage 1 to the disk.  */
26687c478bd9Sstevel@tonic-gate   current_drive = dest_drive;
26697c478bd9Sstevel@tonic-gate   current_partition = dest_partition;
26707c478bd9Sstevel@tonic-gate   if (! open_partition ())
26717c478bd9Sstevel@tonic-gate     goto fail;
26727c478bd9Sstevel@tonic-gate 
26737c478bd9Sstevel@tonic-gate   devwrite (0, 1, stage1_buffer);
26747c478bd9Sstevel@tonic-gate 
26757c478bd9Sstevel@tonic-gate  fail:
26767c478bd9Sstevel@tonic-gate   if (is_open)
26777c478bd9Sstevel@tonic-gate     grub_close ();
26787c478bd9Sstevel@tonic-gate 
26797c478bd9Sstevel@tonic-gate   disk_read_hook = 0;
26807c478bd9Sstevel@tonic-gate 
26817c478bd9Sstevel@tonic-gate #ifndef NO_DECOMPRESSION
26827c478bd9Sstevel@tonic-gate   no_decompression = 0;
26837c478bd9Sstevel@tonic-gate #endif
26847c478bd9Sstevel@tonic-gate 
26857c478bd9Sstevel@tonic-gate   return errnum;
26867c478bd9Sstevel@tonic-gate }
26877c478bd9Sstevel@tonic-gate 
26887c478bd9Sstevel@tonic-gate static struct builtin builtin_install =
26897c478bd9Sstevel@tonic-gate {
26907c478bd9Sstevel@tonic-gate   "install",
26917c478bd9Sstevel@tonic-gate   install_func,
26927c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
26937c478bd9Sstevel@tonic-gate   "install [--stage2=STAGE2_FILE] [--force-lba] STAGE1 [d] DEVICE STAGE2 [ADDR] [p] [CONFIG_FILE] [REAL_CONFIG_FILE]",
26947c478bd9Sstevel@tonic-gate   "Install STAGE1 on DEVICE, and install a blocklist for loading STAGE2"
26957c478bd9Sstevel@tonic-gate   " as a Stage 2. If the option `d' is present, the Stage 1 will always"
26967c478bd9Sstevel@tonic-gate   " look for the disk where STAGE2 was installed, rather than using"
26977c478bd9Sstevel@tonic-gate   " the booting drive. The Stage 2 will be loaded at address ADDR, which"
26987c478bd9Sstevel@tonic-gate   " will be determined automatically if you don't specify it. If"
26997c478bd9Sstevel@tonic-gate   " the option `p' or CONFIG_FILE is present, then the first block"
27007c478bd9Sstevel@tonic-gate   " of Stage 2 is patched with new values of the partition and name"
27017c478bd9Sstevel@tonic-gate   " of the configuration file used by the true Stage 2 (for a Stage 1.5,"
27027c478bd9Sstevel@tonic-gate   " this is the name of the true Stage 2) at boot time. If STAGE2 is a Stage"
27037c478bd9Sstevel@tonic-gate   " 1.5 and REAL_CONFIG_FILE is present, then the Stage 2 CONFIG_FILE is"
27047c478bd9Sstevel@tonic-gate   " patched with the configuration filename REAL_CONFIG_FILE."
27057c478bd9Sstevel@tonic-gate   " If the option `--force-lba' is specified, disable some sanity checks"
27067c478bd9Sstevel@tonic-gate   " for LBA mode. If the option `--stage2' is specified, rewrite the Stage"
27077c478bd9Sstevel@tonic-gate   " 2 via your OS's filesystem instead of the raw device."
27087c478bd9Sstevel@tonic-gate };
27097c478bd9Sstevel@tonic-gate 
27107c478bd9Sstevel@tonic-gate 
27117c478bd9Sstevel@tonic-gate /* ioprobe */
27127c478bd9Sstevel@tonic-gate static int
27137c478bd9Sstevel@tonic-gate ioprobe_func (char *arg, int flags)
27147c478bd9Sstevel@tonic-gate {
27157c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
27167c478bd9Sstevel@tonic-gate 
27177c478bd9Sstevel@tonic-gate   errnum = ERR_UNRECOGNIZED;
27187c478bd9Sstevel@tonic-gate   return 1;
27197c478bd9Sstevel@tonic-gate 
27207c478bd9Sstevel@tonic-gate #else /* ! GRUB_UTIL */
27217c478bd9Sstevel@tonic-gate 
27227c478bd9Sstevel@tonic-gate   unsigned short *port;
27237c478bd9Sstevel@tonic-gate 
27247c478bd9Sstevel@tonic-gate   /* Get the drive number.  */
27257c478bd9Sstevel@tonic-gate   set_device (arg);
27267c478bd9Sstevel@tonic-gate   if (errnum)
27277c478bd9Sstevel@tonic-gate     return 1;
27287c478bd9Sstevel@tonic-gate 
27297c478bd9Sstevel@tonic-gate   /* Clean out IO_MAP.  */
27307c478bd9Sstevel@tonic-gate   grub_memset ((char *) io_map, 0, IO_MAP_SIZE * sizeof (unsigned short));
27317c478bd9Sstevel@tonic-gate 
27327c478bd9Sstevel@tonic-gate   /* Track the int13 handler.  */
27337c478bd9Sstevel@tonic-gate   track_int13 (current_drive);
27347c478bd9Sstevel@tonic-gate 
27357c478bd9Sstevel@tonic-gate   /* Print out the result.  */
27367c478bd9Sstevel@tonic-gate   for (port = io_map; *port != 0; port++)
27377c478bd9Sstevel@tonic-gate     grub_printf (" 0x%x", (unsigned int) *port);
27387c478bd9Sstevel@tonic-gate 
27397c478bd9Sstevel@tonic-gate   return 0;
27407c478bd9Sstevel@tonic-gate 
27417c478bd9Sstevel@tonic-gate #endif /* ! GRUB_UTIL */
27427c478bd9Sstevel@tonic-gate }
27437c478bd9Sstevel@tonic-gate 
27447c478bd9Sstevel@tonic-gate static struct builtin builtin_ioprobe =
27457c478bd9Sstevel@tonic-gate {
27467c478bd9Sstevel@tonic-gate   "ioprobe",
27477c478bd9Sstevel@tonic-gate   ioprobe_func,
27487c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
27497c478bd9Sstevel@tonic-gate   "ioprobe DRIVE",
27507c478bd9Sstevel@tonic-gate   "Probe I/O ports used for the drive DRIVE."
27517c478bd9Sstevel@tonic-gate };
27527c478bd9Sstevel@tonic-gate 
27537c478bd9Sstevel@tonic-gate 
2754b1b8ab34Slling /*
2755b1b8ab34Slling  * To boot from a ZFS root filesystem, the kernel$ or module$ commands
2756ffb5616eSLin Ling  * must include "-B $ZFS-BOOTFS" to expand to the zfs-bootfs, bootpath,
2757ffb5616eSLin Ling  * and diskdevid boot property values for passing to the kernel:
2758b1b8ab34Slling  *
2759b1b8ab34Slling  * e.g.
2760b1b8ab34Slling  * kernel$ /platform/i86pc/kernel/$ISADIR/unix -B $ZFS-BOOTFS,console=ttya
2761b1b8ab34Slling  *
2762ffb5616eSLin Ling  * $ZFS-BOOTFS is expanded to
2763ffb5616eSLin Ling  *
2764ffb5616eSLin Ling  *    zfs-bootfs=<rootpool-name/zfs-rootfilesystem-object-num>,
2765ffb5616eSLin Ling  *    bootpath=<device phys path>,
2766ffb5616eSLin Ling  *    diskdevid=<device id>
2767ffb5616eSLin Ling  *
2768ffb5616eSLin Ling  * if both bootpath and diskdevid can be found.
2769ffb5616eSLin Ling  * e.g
2770ffb5616eSLin Ling  *    zfs-bootfs=rpool/85,
2771ffb5616eSLin Ling  *    bootpath="/pci@0,0/pci1022,7450@a/pci17c2,10@4/sd@0,0:a",
2772ffb5616eSLin Ling  *    diskdevid="id1,sd@SSEAGATE_ST336607LC______3JA0LNHE0000741326W6/a"
2773b1b8ab34Slling  */
2774b1b8ab34Slling static int
2775b1b8ab34Slling expand_dollar_bootfs(char *in, char *out)
2776b1b8ab34Slling {
2777b1b8ab34Slling 	char *token, *tmpout = out;
2778b1b8ab34Slling 	int outlen, blen;
2779bf82a41bSeschrock 	int postcomma = 0;
2780b1b8ab34Slling 
278138614cc7SLin Ling 	/* no op if this is not zfs */
278238614cc7SLin Ling 	if (is_zfs_mount == 0)
278338614cc7SLin Ling 		return (0);
278438614cc7SLin Ling 
2785ffb5616eSLin Ling 	if (current_bootpath[0] == '\0' && current_devid[0] == '\0') {
2786ffb5616eSLin Ling 		errnum = ERR_NO_BOOTPATH;
2787ffb5616eSLin Ling 		return (1);
2788ffb5616eSLin Ling 	}
2789ffb5616eSLin Ling 
2790b1b8ab34Slling 	outlen = strlen(in);
2791b1b8ab34Slling 	blen = current_bootfs_obj == 0 ? strlen(current_rootpool) :
2792b1b8ab34Slling 	    strlen(current_rootpool) + 11;
2793b1b8ab34Slling 
2794b1b8ab34Slling 	out[0] = '\0';
2795b1b8ab34Slling 	while (token = strstr(in, "$ZFS-BOOTFS")) {
2796b1b8ab34Slling 
2797ffb5616eSLin Ling 		if ((outlen += blen) >= MAX_CMDLINE) {
2798b1b8ab34Slling 			errnum = ERR_WONT_FIT;
2799b1b8ab34Slling 			return (1);
2800b1b8ab34Slling 		}
2801b1b8ab34Slling 
2802b1b8ab34Slling 		token[0] = '\0';
2803b1b8ab34Slling 		grub_sprintf(tmpout, "%s", in);
2804b1b8ab34Slling 		token[0] = '$';
2805051aabe6Staylor 		in = token + 11; /* skip over $ZFS-BOOTFS */
2806b1b8ab34Slling 		tmpout = out + strlen(out);
2807b1b8ab34Slling 
2808b1b8ab34Slling 		/* Note: %u only fits 32 bit integer; */
2809b1b8ab34Slling 		if (current_bootfs_obj > 0)
2810b1b8ab34Slling 			grub_sprintf(tmpout, "zfs-bootfs=%s/%u",
2811b1b8ab34Slling 			    current_rootpool, current_bootfs_obj);
2812b1b8ab34Slling 		else
2813b1b8ab34Slling 			grub_sprintf(tmpout, "zfs-bootfs=%s",
2814b1b8ab34Slling 			    current_rootpool);
2815b1b8ab34Slling 		tmpout = out + strlen(out);
2816b1b8ab34Slling 	}
2817b1b8ab34Slling 
2818e7cbe64fSgw 	/*
2819bf82a41bSeschrock 	 * Check to see if 'zfs-bootfs' was explicitly specified on the command
2820bf82a41bSeschrock 	 * line so that we can insert the 'bootpath' property.
2821bf82a41bSeschrock 	 */
2822bf82a41bSeschrock 	if ((tmpout == out) && (token = strstr(in, "zfs-bootfs")) != NULL) {
2823bf82a41bSeschrock 		token[0] = '\0';
2824bf82a41bSeschrock 		grub_strcpy(tmpout, in);
2825bf82a41bSeschrock 		token[0] = 'z';
2826bf82a41bSeschrock 		in = token;
2827bf82a41bSeschrock 
2828bf82a41bSeschrock 		tmpout = out + strlen(out);
2829bf82a41bSeschrock 		postcomma = 1;
2830bf82a41bSeschrock 	}
2831bf82a41bSeschrock 
2832bf82a41bSeschrock 	/*
2833bf82a41bSeschrock 	 * Set the 'bootpath' property if a ZFS dataset was specified, either
2834bf82a41bSeschrock 	 * through '$ZFS-BOOTFS' or an explicit 'zfs-bootfs' setting.
2835e7cbe64fSgw 	 */
2836e7cbe64fSgw 	if (tmpout != out) {
2837ffb5616eSLin Ling 		if (current_bootpath[0] != '\0') {
2838ffb5616eSLin Ling 			if ((outlen += 12 + strlen(current_bootpath))
2839ffb5616eSLin Ling 			    >= MAX_CMDLINE) {
2840ffb5616eSLin Ling 				errnum = ERR_WONT_FIT;
2841ffb5616eSLin Ling 				return (1);
2842ffb5616eSLin Ling 			}
2843ffb5616eSLin Ling 			grub_sprintf(tmpout,
2844ffb5616eSLin Ling 			    postcomma ? "bootpath=\"%s\"," : ",bootpath=\"%s\"",
2845ffb5616eSLin Ling 			    current_bootpath);
2846ffb5616eSLin Ling 			tmpout = out + strlen(out);
2847e7cbe64fSgw 		}
2848ffb5616eSLin Ling 
2849ffb5616eSLin Ling 		if (current_devid[0] != '\0') {
2850ffb5616eSLin Ling 			if ((outlen += 13 + strlen(current_devid))
2851ffb5616eSLin Ling 			    >= MAX_CMDLINE) {
2852ffb5616eSLin Ling 				errnum = ERR_WONT_FIT;
2853ffb5616eSLin Ling 				return (1);
2854ffb5616eSLin Ling 			}
2855ffb5616eSLin Ling 			grub_sprintf(tmpout,
2856ffb5616eSLin Ling 			    postcomma ? "diskdevid=\"%s\"," : ",diskdevid=\"%s\"",
2857ffb5616eSLin Ling 			    current_devid);
2858051aabe6Staylor 		}
2859e7cbe64fSgw 	}
2860e7cbe64fSgw 
2861b1b8ab34Slling 	strncat(out, in, MAX_CMDLINE);
2862b1b8ab34Slling 	return (0);
2863b1b8ab34Slling }
2864b1b8ab34Slling 
28657c478bd9Sstevel@tonic-gate /* kernel */
28667c478bd9Sstevel@tonic-gate static int
28677c478bd9Sstevel@tonic-gate kernel_func (char *arg, int flags)
28687c478bd9Sstevel@tonic-gate {
28697c478bd9Sstevel@tonic-gate   int len;
28707c478bd9Sstevel@tonic-gate   kernel_t suggested_type = KERNEL_TYPE_NONE;
28717c478bd9Sstevel@tonic-gate   unsigned long load_flags = 0;
28727c478bd9Sstevel@tonic-gate 
28737c478bd9Sstevel@tonic-gate #ifndef AUTO_LINUX_MEM_OPT
28747c478bd9Sstevel@tonic-gate   load_flags |= KERNEL_LOAD_NO_MEM_OPTION;
28757c478bd9Sstevel@tonic-gate #endif
28767c478bd9Sstevel@tonic-gate 
28777c478bd9Sstevel@tonic-gate   /* Deal with GNU-style long options.  */
28787c478bd9Sstevel@tonic-gate   while (1)
28797c478bd9Sstevel@tonic-gate     {
28807c478bd9Sstevel@tonic-gate       /* If the option `--type=TYPE' is specified, convert the string to
28817c478bd9Sstevel@tonic-gate 	 a kernel type.  */
28827c478bd9Sstevel@tonic-gate       if (grub_memcmp (arg, "--type=", 7) == 0)
28837c478bd9Sstevel@tonic-gate 	{
28847c478bd9Sstevel@tonic-gate 	  arg += 7;
28857c478bd9Sstevel@tonic-gate 
28867c478bd9Sstevel@tonic-gate 	  if (grub_memcmp (arg, "netbsd", 6) == 0)
28877c478bd9Sstevel@tonic-gate 	    suggested_type = KERNEL_TYPE_NETBSD;
28887c478bd9Sstevel@tonic-gate 	  else if (grub_memcmp (arg, "freebsd", 7) == 0)
28897c478bd9Sstevel@tonic-gate 	    suggested_type = KERNEL_TYPE_FREEBSD;
28907c478bd9Sstevel@tonic-gate 	  else if (grub_memcmp (arg, "openbsd", 7) == 0)
28917c478bd9Sstevel@tonic-gate 	    /* XXX: For now, OpenBSD is identical to NetBSD, from GRUB's
28927c478bd9Sstevel@tonic-gate 	       point of view.  */
28937c478bd9Sstevel@tonic-gate 	    suggested_type = KERNEL_TYPE_NETBSD;
28947c478bd9Sstevel@tonic-gate 	  else if (grub_memcmp (arg, "linux", 5) == 0)
28957c478bd9Sstevel@tonic-gate 	    suggested_type = KERNEL_TYPE_LINUX;
28967c478bd9Sstevel@tonic-gate 	  else if (grub_memcmp (arg, "biglinux", 8) == 0)
28977c478bd9Sstevel@tonic-gate 	    suggested_type = KERNEL_TYPE_BIG_LINUX;
28987c478bd9Sstevel@tonic-gate 	  else if (grub_memcmp (arg, "multiboot", 9) == 0)
28997c478bd9Sstevel@tonic-gate 	    suggested_type = KERNEL_TYPE_MULTIBOOT;
29007c478bd9Sstevel@tonic-gate 	  else
29017c478bd9Sstevel@tonic-gate 	    {
29027c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_ARGUMENT;
29037c478bd9Sstevel@tonic-gate 	      return 1;
29047c478bd9Sstevel@tonic-gate 	    }
29057c478bd9Sstevel@tonic-gate 	}
29067c478bd9Sstevel@tonic-gate       /* If the `--no-mem-option' is specified, don't pass a Linux's mem
29077c478bd9Sstevel@tonic-gate 	 option automatically. If the kernel is another type, this flag
29087c478bd9Sstevel@tonic-gate 	 has no effect.  */
29097c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--no-mem-option", 15) == 0)
29107c478bd9Sstevel@tonic-gate 	load_flags |= KERNEL_LOAD_NO_MEM_OPTION;
29117c478bd9Sstevel@tonic-gate       else
29127c478bd9Sstevel@tonic-gate 	break;
29137c478bd9Sstevel@tonic-gate 
29147c478bd9Sstevel@tonic-gate       /* Try the next.  */
29157c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
29167c478bd9Sstevel@tonic-gate     }
29177c478bd9Sstevel@tonic-gate 
29187c478bd9Sstevel@tonic-gate   len = grub_strlen (arg);
29197c478bd9Sstevel@tonic-gate 
29207c478bd9Sstevel@tonic-gate   /* Reset MB_CMDLINE.  */
29217c478bd9Sstevel@tonic-gate   mb_cmdline = (char *) MB_CMDLINE_BUF;
29227c478bd9Sstevel@tonic-gate   if (len + 1 > MB_CMDLINE_BUFLEN)
29237c478bd9Sstevel@tonic-gate     {
29247c478bd9Sstevel@tonic-gate       errnum = ERR_WONT_FIT;
29257c478bd9Sstevel@tonic-gate       return 1;
29267c478bd9Sstevel@tonic-gate     }
29277c478bd9Sstevel@tonic-gate 
29287c478bd9Sstevel@tonic-gate   /* Copy the command-line to MB_CMDLINE.  */
29297c478bd9Sstevel@tonic-gate   grub_memmove (mb_cmdline, arg, len + 1);
29307c478bd9Sstevel@tonic-gate   kernel_type = load_image (arg, mb_cmdline, suggested_type, load_flags);
29317c478bd9Sstevel@tonic-gate   if (kernel_type == KERNEL_TYPE_NONE)
29327c478bd9Sstevel@tonic-gate     return 1;
29337c478bd9Sstevel@tonic-gate 
2934b1b8ab34Slling   mb_cmdline += grub_strlen(mb_cmdline) + 1;
29357c478bd9Sstevel@tonic-gate   return 0;
29367c478bd9Sstevel@tonic-gate }
29377c478bd9Sstevel@tonic-gate 
29387c478bd9Sstevel@tonic-gate static struct builtin builtin_kernel =
29397c478bd9Sstevel@tonic-gate {
29407c478bd9Sstevel@tonic-gate   "kernel",
29417c478bd9Sstevel@tonic-gate   kernel_func,
29427c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
29437c478bd9Sstevel@tonic-gate   "kernel [--no-mem-option] [--type=TYPE] FILE [ARG ...]",
29447c478bd9Sstevel@tonic-gate   "Attempt to load the primary boot image from FILE. The rest of the"
29457c478bd9Sstevel@tonic-gate   " line is passed verbatim as the \"kernel command line\".  Any modules"
29467c478bd9Sstevel@tonic-gate   " must be reloaded after using this command. The option --type is used"
29477c478bd9Sstevel@tonic-gate   " to suggest what type of kernel to be loaded. TYPE must be either of"
29487c478bd9Sstevel@tonic-gate   " \"netbsd\", \"freebsd\", \"openbsd\", \"linux\", \"biglinux\" and"
29497c478bd9Sstevel@tonic-gate   " \"multiboot\". The option --no-mem-option tells GRUB not to pass a"
29507c478bd9Sstevel@tonic-gate   " Linux's mem option automatically."
29517c478bd9Sstevel@tonic-gate };
29527c478bd9Sstevel@tonic-gate 
2953342440ecSPrasad Singamsetty int
2954342440ecSPrasad Singamsetty min_mem64_func(char *arg, int flags)
2955342440ecSPrasad Singamsetty {
2956342440ecSPrasad Singamsetty 	if (!safe_parse_maxint(&arg, &min_mem64))
2957342440ecSPrasad Singamsetty 		return (1);
2958342440ecSPrasad Singamsetty }
2959342440ecSPrasad Singamsetty 
2960342440ecSPrasad Singamsetty static struct builtin builtin_min_mem64 =
2961342440ecSPrasad Singamsetty {
2962342440ecSPrasad Singamsetty 	"min_mem64",
2963342440ecSPrasad Singamsetty 	min_mem64_func,
2964342440ecSPrasad Singamsetty 	BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_SCRIPT | BUILTIN_HELP_LIST,
2965342440ecSPrasad Singamsetty 	"min_mem64 <memory in MB>",
2966342440ecSPrasad Singamsetty 	"Sets minimum memory (in MB) required for $ISADIR to expand to amd64, "
2967342440ecSPrasad Singamsetty 	"even on 64-bit capable hardware."
2968342440ecSPrasad Singamsetty };
2969342440ecSPrasad Singamsetty 
2970342440ecSPrasad Singamsetty int
2971342440ecSPrasad Singamsetty check_min_mem64()
2972342440ecSPrasad Singamsetty {
2973342440ecSPrasad Singamsetty 	if (min_mem64 == 0)
2974342440ecSPrasad Singamsetty 		return (1);
2975342440ecSPrasad Singamsetty 
2976342440ecSPrasad Singamsetty 	if ((mbi.mem_upper / 10240) * 11 >= min_mem64)
2977342440ecSPrasad Singamsetty 		return (1);
2978342440ecSPrasad Singamsetty 
2979342440ecSPrasad Singamsetty 	return (0);
2980342440ecSPrasad Singamsetty }
2981ae115bc7Smrj 
2982ae115bc7Smrj static int detect_target_operating_mode();
2983ae115bc7Smrj 
2984ae115bc7Smrj int
2985ae115bc7Smrj amd64_config_cpu(void)
2986ae115bc7Smrj {
2987ae115bc7Smrj         struct amd64_cpuid_regs __vcr, *vcr = &__vcr;
2988ae115bc7Smrj         uint32_t maxeax;
2989ae115bc7Smrj         uint32_t max_maxeax = 0x100;
2990ae115bc7Smrj         char vendor[13];
2991ae115bc7Smrj         int isamd64 = 0;
2992ae115bc7Smrj         uint32_t stdfeatures = 0, xtdfeatures = 0;
2993ae115bc7Smrj         uint64_t efer;
2994ae115bc7Smrj 
2995ae115bc7Smrj         /*
2996ae115bc7Smrj          * This check may seem silly, but if the C preprocesor symbol __amd64
2997ae115bc7Smrj          * is #defined during compilation, something that may outwardly seem
2998ae115bc7Smrj          * like a good idea, uts/common/sys/isa_defs.h will #define _LP64,
2999ae115bc7Smrj          * which will cause uts/common/sys/int_types.h to typedef uint64_t as
3000ae115bc7Smrj          * an unsigned long - which is only 4 bytes in size when using a 32-bit
3001ae115bc7Smrj          * compiler.
3002ae115bc7Smrj          *
3003ae115bc7Smrj          * If that happens, all the page table translation routines will fail
3004ae115bc7Smrj          * horribly, so check the size of uint64_t just to insure some degree
3005ae115bc7Smrj          * of sanity in future operations.
3006ae115bc7Smrj          */
3007ae115bc7Smrj         /*LINTED [sizeof result is invarient]*/
3008ae115bc7Smrj         if (sizeof (uint64_t) != 8)
3009ae115bc7Smrj                 prom_panic("grub compiled improperly, unable to boot "
3010ae115bc7Smrj                     "64-bit AMD64 executables");
3011ae115bc7Smrj 
3012ae115bc7Smrj         /*
3013ae115bc7Smrj          * If the CPU doesn't support the CPUID instruction, it's definitely
3014ae115bc7Smrj          * not an AMD64.
3015ae115bc7Smrj          */
3016ae115bc7Smrj         if (amd64_cpuid_supported() == 0)
3017ae115bc7Smrj                 return (0);
3018ae115bc7Smrj 
3019ae115bc7Smrj         amd64_cpuid_insn(0, vcr);
3020ae115bc7Smrj 
3021ae115bc7Smrj         maxeax = vcr->r_eax;
3022ae115bc7Smrj         {
3023ae115bc7Smrj                 /*LINTED [vendor string from cpuid data]*/
3024ae115bc7Smrj                 uint32_t *iptr = (uint32_t *)vendor;
3025ae115bc7Smrj 
3026ae115bc7Smrj                 *iptr++ = vcr->r_ebx;
3027ae115bc7Smrj                 *iptr++ = vcr->r_edx;
3028ae115bc7Smrj                 *iptr++ = vcr->r_ecx;
3029ae115bc7Smrj 
3030ae115bc7Smrj                 vendor[12] = '\0';
3031ae115bc7Smrj         }
3032ae115bc7Smrj 
3033ae115bc7Smrj         if (maxeax > max_maxeax) {
3034ae115bc7Smrj                 grub_printf("cpu: warning, maxeax was 0x%x -> 0x%x\n",
3035ae115bc7Smrj                     maxeax, max_maxeax);
3036ae115bc7Smrj                 maxeax = max_maxeax;
3037ae115bc7Smrj         }
3038ae115bc7Smrj 
3039ae115bc7Smrj         if (maxeax < 1)
3040ae115bc7Smrj                 return (0);     /* no additional functions, not an AMD64 */
3041ae115bc7Smrj         else {
3042ae115bc7Smrj                 uint_t family, model, step;
3043ae115bc7Smrj 
3044ae115bc7Smrj                 amd64_cpuid_insn(1, vcr);
3045ae115bc7Smrj 
3046ae115bc7Smrj                 /*
3047ae115bc7Smrj                  * All AMD64/IA32e processors technically SHOULD report
3048ae115bc7Smrj                  * themselves as being in family 0xf, but for some reason
3049ae115bc7Smrj                  * Simics doesn't, and this may change in the future, so
3050ae115bc7Smrj                  * don't error out if it's not true.
3051ae115bc7Smrj                  */
3052ae115bc7Smrj                 if ((family = BITX(vcr->r_eax, 11, 8)) == 0xf)
3053ae115bc7Smrj                         family += BITX(vcr->r_eax, 27, 20);
3054ae115bc7Smrj 
3055ae115bc7Smrj                 if ((model = BITX(vcr->r_eax, 7, 4)) == 0xf)
3056ae115bc7Smrj                         model += BITX(vcr->r_eax, 19, 16) << 4;
3057ae115bc7Smrj                 step = BITX(vcr->r_eax, 3, 0);
3058ae115bc7Smrj 
3059ae115bc7Smrj                 grub_printf("cpu: '%s' family %d model %d step %d\n",
3060ae115bc7Smrj                     vendor, family, model, step);
3061ae115bc7Smrj                 stdfeatures = vcr->r_edx;
3062ae115bc7Smrj         }
3063ae115bc7Smrj 
3064ae115bc7Smrj         amd64_cpuid_insn(0x80000000, vcr);
3065ae115bc7Smrj 
3066ae115bc7Smrj         if (vcr->r_eax & 0x80000000) {
3067ae115bc7Smrj                 uint32_t xmaxeax = vcr->r_eax;
3068ae115bc7Smrj                 const uint32_t max_xmaxeax = 0x80000100;
3069ae115bc7Smrj 
3070ae115bc7Smrj                 if (xmaxeax > max_xmaxeax) {
3071ae115bc7Smrj                         grub_printf("amd64: warning, xmaxeax was "
3072ae115bc7Smrj 			    "0x%x -> 0x%x\n", xmaxeax, max_xmaxeax);
3073ae115bc7Smrj                         xmaxeax = max_xmaxeax;
3074ae115bc7Smrj                 }
3075ae115bc7Smrj 
3076ae115bc7Smrj                 if (xmaxeax >= 0x80000001) {
3077ae115bc7Smrj                         amd64_cpuid_insn(0x80000001, vcr);
3078ae115bc7Smrj                         xtdfeatures = vcr->r_edx;
3079ae115bc7Smrj                 }
3080ae115bc7Smrj         }
3081ae115bc7Smrj 
3082ae115bc7Smrj         if (BITX(xtdfeatures, 29, 29))          /* long mode */
3083ae115bc7Smrj                 isamd64++;
3084ae115bc7Smrj         else
3085ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support long mode\n");
3086ae115bc7Smrj 
3087ae115bc7Smrj         if (!BITX(stdfeatures, 0, 0)) {
3088ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support FPU\n");
3089ae115bc7Smrj                 isamd64--;
3090ae115bc7Smrj         }
3091ae115bc7Smrj 
3092ae115bc7Smrj         if (!BITX(stdfeatures, 4, 4)) {
3093ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support TSC\n");
3094ae115bc7Smrj                 isamd64--;
3095ae115bc7Smrj         }
3096ae115bc7Smrj 
3097ae115bc7Smrj         if (!BITX(stdfeatures, 5, 5)) {
3098ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support MSRs\n");
3099ae115bc7Smrj                 isamd64--;
3100ae115bc7Smrj         }
3101ae115bc7Smrj 
3102ae115bc7Smrj         if (!BITX(stdfeatures, 6, 6)) {
3103ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support PAE\n");
3104ae115bc7Smrj                 isamd64--;
3105ae115bc7Smrj         }
3106ae115bc7Smrj 
3107ae115bc7Smrj         if (!BITX(stdfeatures, 8, 8)) {
3108ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support CX8\n");
3109ae115bc7Smrj                 isamd64--;
3110ae115bc7Smrj         }
3111ae115bc7Smrj 
3112ae115bc7Smrj         if (!BITX(stdfeatures, 13, 13)) {
3113ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support PGE\n");
3114ae115bc7Smrj                 isamd64--;
3115ae115bc7Smrj         }
3116ae115bc7Smrj 
3117ae115bc7Smrj         if (!BITX(stdfeatures, 19, 19)) {
3118ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support CLFSH\n");
3119ae115bc7Smrj                 isamd64--;
3120ae115bc7Smrj         }
3121ae115bc7Smrj 
3122ae115bc7Smrj         if (!BITX(stdfeatures, 23, 23)) {
3123ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support MMX\n");
3124ae115bc7Smrj                 isamd64--;
3125ae115bc7Smrj         }
3126ae115bc7Smrj 
3127ae115bc7Smrj         if (!BITX(stdfeatures, 24, 24)) {
3128ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support FXSR\n");
3129ae115bc7Smrj                 isamd64--;
3130ae115bc7Smrj         }
3131ae115bc7Smrj 
3132ae115bc7Smrj         if (!BITX(stdfeatures, 25, 25)) {
3133ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support SSE\n");
3134ae115bc7Smrj                 isamd64--;
3135ae115bc7Smrj         }
3136ae115bc7Smrj 
3137ae115bc7Smrj         if (!BITX(stdfeatures, 26, 26)) {
3138ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support SSE2\n");
3139ae115bc7Smrj                 isamd64--;
3140ae115bc7Smrj         }
3141ae115bc7Smrj 
3142ae115bc7Smrj         if (isamd64 < 1) {
3143ae115bc7Smrj                 grub_printf("amd64: CPU does not support amd64 executables.\n");
3144ae115bc7Smrj                 return (0);
3145ae115bc7Smrj         }
3146ae115bc7Smrj 
3147ae115bc7Smrj         amd64_rdmsr(MSR_AMD_EFER, &efer);
3148ae115bc7Smrj         if (efer & AMD_EFER_SCE)
3149ae115bc7Smrj                 grub_printf("amd64: EFER_SCE (syscall/sysret) already "
3150ae115bc7Smrj 		    "enabled\n");
3151ae115bc7Smrj         if (efer & AMD_EFER_NXE)
3152ae115bc7Smrj                 grub_printf("amd64: EFER_NXE (no-exec prot) already enabled\n");
3153ae115bc7Smrj         if (efer & AMD_EFER_LME)
3154ae115bc7Smrj                 grub_printf("amd64: EFER_LME (long mode) already enabled\n");
3155ae115bc7Smrj 
3156ae115bc7Smrj         return (detect_target_operating_mode());
3157ae115bc7Smrj }
3158ae115bc7Smrj 
3159ae115bc7Smrj static int
3160ae115bc7Smrj detect_target_operating_mode()
3161ae115bc7Smrj {
3162ae115bc7Smrj         int ret, ah;
3163ae115bc7Smrj 
3164ae115bc7Smrj 	ah = get_target_operating_mode();
3165ae115bc7Smrj 
3166ae115bc7Smrj         ah = ah >> 8;
3167ae115bc7Smrj 
3168ae115bc7Smrj 	/* XXX still need to pass back the return from the call  */
3169ae115bc7Smrj 	ret = 0;
3170ae115bc7Smrj 
3171ae115bc7Smrj         if (ah == 0x86 && (ret & CB) != 0) {
3172ae115bc7Smrj                 grub_printf("[BIOS 'Detect Target Operating Mode' "
3173ae115bc7Smrj                     "callback unsupported on this platform]\n");
3174ae115bc7Smrj                 return (1);     /* unsupported, ignore */
3175ae115bc7Smrj         }
3176ae115bc7Smrj 
3177ae115bc7Smrj         if (ah == 0x0 && (ret & CB) == 0) {
3178ae115bc7Smrj                 grub_printf("[BIOS accepted mixed-mode target setting!]\n");
3179ae115bc7Smrj                 return (1);     /* told the bios what we're up to */
3180ae115bc7Smrj         }
3181ae115bc7Smrj 
3182ae115bc7Smrj         if (ah == 0 && ret & CB) {
3183ae115bc7Smrj                 grub_printf("fatal: BIOS reports this machine CANNOT run in "
3184ae115bc7Smrj 		    "mixed 32/64-bit mode!\n");
3185ae115bc7Smrj                 return (0);
3186ae115bc7Smrj         }
3187ae115bc7Smrj 
3188ae115bc7Smrj         grub_printf("warning: BIOS Detect Target Operating Mode callback "
3189ae115bc7Smrj             "confused.\n         %%ax >> 8 = 0x%x, carry = %d\n", ah,
3190ae115bc7Smrj             ret & CB ? 1 : 0);
3191ae115bc7Smrj 
3192ae115bc7Smrj         return (1);
3193ae115bc7Smrj }
3194ae115bc7Smrj 
3195ae115bc7Smrj 
3196ae115bc7Smrj int
3197ae115bc7Smrj isamd64()
3198ae115bc7Smrj {
3199ae115bc7Smrj 	static int ret = -1;
3200ae115bc7Smrj 
3201ae115bc7Smrj 	if (ret == -1)
3202ae115bc7Smrj 		ret = amd64_config_cpu();
3203ae115bc7Smrj 
3204ae115bc7Smrj 	return (ret);
3205ae115bc7Smrj }
3206ae115bc7Smrj 
3207b1b8ab34Slling static void
3208b1b8ab34Slling expand_arch (char *arg, char *newarg)
3209ae115bc7Smrj {
3210ae115bc7Smrj   char *index;
3211ae115bc7Smrj 
3212ae115bc7Smrj   newarg[0] = '\0';
3213ae115bc7Smrj 
3214ae115bc7Smrj   while ((index = strstr(arg, "$ISADIR")) != NULL) {
3215ae115bc7Smrj 
3216ae115bc7Smrj     index[0] = '\0';
3217ae115bc7Smrj     strncat(newarg, arg, MAX_CMDLINE);
3218ae115bc7Smrj     index[0] = '$';
3219ae115bc7Smrj 
3220342440ecSPrasad Singamsetty     if (isamd64() && check_min_mem64())
3221ae115bc7Smrj       strncat(newarg, "amd64", MAX_CMDLINE);
3222ae115bc7Smrj 
3223ae115bc7Smrj     arg = index + 7;
3224ae115bc7Smrj   }
3225ae115bc7Smrj 
3226ae115bc7Smrj   strncat(newarg, arg, MAX_CMDLINE);
3227b1b8ab34Slling   return;
3228ae115bc7Smrj }
3229ae115bc7Smrj 
3230ae115bc7Smrj /* kernel$ */
3231ae115bc7Smrj static int
3232ae115bc7Smrj kernel_dollar_func (char *arg, int flags)
3233ae115bc7Smrj {
3234b1b8ab34Slling   char newarg[MAX_CMDLINE];	/* everything boils down to MAX_CMDLINE */
3235b1b8ab34Slling 
3236b1b8ab34Slling   grub_printf("loading '%s' ...\n", arg);
3237b1b8ab34Slling   expand_arch(arg, newarg);
3238b1b8ab34Slling 
3239b1b8ab34Slling   if (kernel_func(newarg, flags))
3240b1b8ab34Slling 	return (1);
3241b1b8ab34Slling 
3242b1b8ab34Slling   mb_cmdline = (char *)MB_CMDLINE_BUF;
3243ffb5616eSLin Ling   if (expand_dollar_bootfs(newarg, mb_cmdline)) {
3244ffb5616eSLin Ling 	grub_printf("cannot expand $ZFS-BOOTFS for dataset %s\n",
3245ffb5616eSLin Ling 	    current_bootfs);
3246b1b8ab34Slling 	return (1);
3247ffb5616eSLin Ling   }
3248b1b8ab34Slling 
3249b1b8ab34Slling   grub_printf("'%s' is loaded\n", mb_cmdline);
3250b1b8ab34Slling   mb_cmdline += grub_strlen(mb_cmdline) + 1;
3251b1b8ab34Slling 
3252b1b8ab34Slling   return (0);
3253ae115bc7Smrj }
3254ae115bc7Smrj 
3255ae115bc7Smrj static struct builtin builtin_kernel_dollar =
3256ae115bc7Smrj {
3257ae115bc7Smrj   "kernel$",
3258ae115bc7Smrj   kernel_dollar_func,
3259ae115bc7Smrj   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
3260ae115bc7Smrj   "kernel$ [--no-mem-option] [--type=TYPE] FILE [ARG ...]",
3261ae115bc7Smrj   " Just like kernel, but with $ISADIR expansion."
3262ae115bc7Smrj };
3263ae115bc7Smrj 
32647c478bd9Sstevel@tonic-gate 
32657c478bd9Sstevel@tonic-gate /* lock */
32667c478bd9Sstevel@tonic-gate static int
32677c478bd9Sstevel@tonic-gate lock_func (char *arg, int flags)
32687c478bd9Sstevel@tonic-gate {
32697c478bd9Sstevel@tonic-gate   if (! auth && password)
32707c478bd9Sstevel@tonic-gate     {
32717c478bd9Sstevel@tonic-gate       errnum = ERR_PRIVILEGED;
32727c478bd9Sstevel@tonic-gate       return 1;
32737c478bd9Sstevel@tonic-gate     }
32747c478bd9Sstevel@tonic-gate 
32757c478bd9Sstevel@tonic-gate   return 0;
32767c478bd9Sstevel@tonic-gate }
32777c478bd9Sstevel@tonic-gate 
32787c478bd9Sstevel@tonic-gate static struct builtin builtin_lock =
32797c478bd9Sstevel@tonic-gate {
32807c478bd9Sstevel@tonic-gate   "lock",
32817c478bd9Sstevel@tonic-gate   lock_func,
32827c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
32837c478bd9Sstevel@tonic-gate   "lock",
32847c478bd9Sstevel@tonic-gate   "Break a command execution unless the user is authenticated."
32857c478bd9Sstevel@tonic-gate };
32867c478bd9Sstevel@tonic-gate 
32877c478bd9Sstevel@tonic-gate 
32887c478bd9Sstevel@tonic-gate /* makeactive */
32897c478bd9Sstevel@tonic-gate static int
32907c478bd9Sstevel@tonic-gate makeactive_func (char *arg, int flags)
32917c478bd9Sstevel@tonic-gate {
32927c478bd9Sstevel@tonic-gate   if (! make_saved_active ())
32937c478bd9Sstevel@tonic-gate     return 1;
32947c478bd9Sstevel@tonic-gate 
32957c478bd9Sstevel@tonic-gate   return 0;
32967c478bd9Sstevel@tonic-gate }
32977c478bd9Sstevel@tonic-gate 
32987c478bd9Sstevel@tonic-gate static struct builtin builtin_makeactive =
32997c478bd9Sstevel@tonic-gate {
33007c478bd9Sstevel@tonic-gate   "makeactive",
33017c478bd9Sstevel@tonic-gate   makeactive_func,
33027c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
33037c478bd9Sstevel@tonic-gate   "makeactive",
33047c478bd9Sstevel@tonic-gate   "Set the active partition on the root disk to GRUB's root device."
33057c478bd9Sstevel@tonic-gate   " This command is limited to _primary_ PC partitions on a hard disk."
33067c478bd9Sstevel@tonic-gate };
33077c478bd9Sstevel@tonic-gate 
33087c478bd9Sstevel@tonic-gate 
33097c478bd9Sstevel@tonic-gate /* map */
33107c478bd9Sstevel@tonic-gate /* Map FROM_DRIVE to TO_DRIVE.  */
33117c478bd9Sstevel@tonic-gate static int
33127c478bd9Sstevel@tonic-gate map_func (char *arg, int flags)
33137c478bd9Sstevel@tonic-gate {
33147c478bd9Sstevel@tonic-gate   char *to_drive;
33157c478bd9Sstevel@tonic-gate   char *from_drive;
33167c478bd9Sstevel@tonic-gate   unsigned long to, from;
33177c478bd9Sstevel@tonic-gate   int i;
33187c478bd9Sstevel@tonic-gate 
33197c478bd9Sstevel@tonic-gate   to_drive = arg;
33207c478bd9Sstevel@tonic-gate   from_drive = skip_to (0, arg);
33217c478bd9Sstevel@tonic-gate 
33227c478bd9Sstevel@tonic-gate   /* Get the drive number for TO_DRIVE.  */
33237c478bd9Sstevel@tonic-gate   set_device (to_drive);
33247c478bd9Sstevel@tonic-gate   if (errnum)
33257c478bd9Sstevel@tonic-gate     return 1;
33267c478bd9Sstevel@tonic-gate   to = current_drive;
33277c478bd9Sstevel@tonic-gate 
33287c478bd9Sstevel@tonic-gate   /* Get the drive number for FROM_DRIVE.  */
33297c478bd9Sstevel@tonic-gate   set_device (from_drive);
33307c478bd9Sstevel@tonic-gate   if (errnum)
33317c478bd9Sstevel@tonic-gate     return 1;
33327c478bd9Sstevel@tonic-gate   from = current_drive;
33337c478bd9Sstevel@tonic-gate 
33347c478bd9Sstevel@tonic-gate   /* Search for an empty slot in BIOS_DRIVE_MAP.  */
33357c478bd9Sstevel@tonic-gate   for (i = 0; i < DRIVE_MAP_SIZE; i++)
33367c478bd9Sstevel@tonic-gate     {
33377c478bd9Sstevel@tonic-gate       /* Perhaps the user wants to override the map.  */
33387c478bd9Sstevel@tonic-gate       if ((bios_drive_map[i] & 0xff) == from)
33397c478bd9Sstevel@tonic-gate 	break;
33407c478bd9Sstevel@tonic-gate 
33417c478bd9Sstevel@tonic-gate       if (! bios_drive_map[i])
33427c478bd9Sstevel@tonic-gate 	break;
33437c478bd9Sstevel@tonic-gate     }
33447c478bd9Sstevel@tonic-gate 
33457c478bd9Sstevel@tonic-gate   if (i == DRIVE_MAP_SIZE)
33467c478bd9Sstevel@tonic-gate     {
33477c478bd9Sstevel@tonic-gate       errnum = ERR_WONT_FIT;
33487c478bd9Sstevel@tonic-gate       return 1;
33497c478bd9Sstevel@tonic-gate     }
33507c478bd9Sstevel@tonic-gate 
33517c478bd9Sstevel@tonic-gate   if (to == from)
33527c478bd9Sstevel@tonic-gate     /* If TO is equal to FROM, delete the entry.  */
33537c478bd9Sstevel@tonic-gate     grub_memmove ((char *) &bios_drive_map[i], (char *) &bios_drive_map[i + 1],
33547c478bd9Sstevel@tonic-gate 		  sizeof (unsigned short) * (DRIVE_MAP_SIZE - i));
33557c478bd9Sstevel@tonic-gate   else
33567c478bd9Sstevel@tonic-gate     bios_drive_map[i] = from | (to << 8);
33577c478bd9Sstevel@tonic-gate 
33587c478bd9Sstevel@tonic-gate   return 0;
33597c478bd9Sstevel@tonic-gate }
33607c478bd9Sstevel@tonic-gate 
33617c478bd9Sstevel@tonic-gate static struct builtin builtin_map =
33627c478bd9Sstevel@tonic-gate {
33637c478bd9Sstevel@tonic-gate   "map",
33647c478bd9Sstevel@tonic-gate   map_func,
33657c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
33667c478bd9Sstevel@tonic-gate   "map TO_DRIVE FROM_DRIVE",
33677c478bd9Sstevel@tonic-gate   "Map the drive FROM_DRIVE to the drive TO_DRIVE. This is necessary"
33687c478bd9Sstevel@tonic-gate   " when you chain-load some operating systems, such as DOS, if such an"
33697c478bd9Sstevel@tonic-gate   " OS resides at a non-first drive."
33707c478bd9Sstevel@tonic-gate };
33717c478bd9Sstevel@tonic-gate 
33727c478bd9Sstevel@tonic-gate 
33737c478bd9Sstevel@tonic-gate #ifdef USE_MD5_PASSWORDS
33747c478bd9Sstevel@tonic-gate /* md5crypt */
33757c478bd9Sstevel@tonic-gate static int
33767c478bd9Sstevel@tonic-gate md5crypt_func (char *arg, int flags)
33777c478bd9Sstevel@tonic-gate {
33787c478bd9Sstevel@tonic-gate   char crypted[36];
33797c478bd9Sstevel@tonic-gate   char key[32];
33807c478bd9Sstevel@tonic-gate   unsigned int seed;
33817c478bd9Sstevel@tonic-gate   int i;
33827c478bd9Sstevel@tonic-gate   const char *const seedchars =
33837c478bd9Sstevel@tonic-gate     "./0123456789ABCDEFGHIJKLMNOPQRST"
33847c478bd9Sstevel@tonic-gate     "UVWXYZabcdefghijklmnopqrstuvwxyz";
33857c478bd9Sstevel@tonic-gate 
33867c478bd9Sstevel@tonic-gate   /* First create a salt.  */
33877c478bd9Sstevel@tonic-gate 
33887c478bd9Sstevel@tonic-gate   /* The magical prefix.  */
33897c478bd9Sstevel@tonic-gate   grub_memset (crypted, 0, sizeof (crypted));
33907c478bd9Sstevel@tonic-gate   grub_memmove (crypted, "$1$", 3);
33917c478bd9Sstevel@tonic-gate 
33927c478bd9Sstevel@tonic-gate   /* Create the length of a salt.  */
33937c478bd9Sstevel@tonic-gate   seed = currticks ();
33947c478bd9Sstevel@tonic-gate 
33957c478bd9Sstevel@tonic-gate   /* Generate a salt.  */
33967c478bd9Sstevel@tonic-gate   for (i = 0; i < 8 && seed; i++)
33977c478bd9Sstevel@tonic-gate     {
33987c478bd9Sstevel@tonic-gate       /* FIXME: This should be more random.  */
33997c478bd9Sstevel@tonic-gate       crypted[3 + i] = seedchars[seed & 0x3f];
34007c478bd9Sstevel@tonic-gate       seed >>= 6;
34017c478bd9Sstevel@tonic-gate     }
34027c478bd9Sstevel@tonic-gate 
34037c478bd9Sstevel@tonic-gate   /* A salt must be terminated with `$', if it is less than 8 chars.  */
34047c478bd9Sstevel@tonic-gate   crypted[3 + i] = '$';
34057c478bd9Sstevel@tonic-gate 
34067c478bd9Sstevel@tonic-gate #ifdef DEBUG_MD5CRYPT
34077c478bd9Sstevel@tonic-gate   grub_printf ("salt = %s\n", crypted);
34087c478bd9Sstevel@tonic-gate #endif
34097c478bd9Sstevel@tonic-gate 
34107c478bd9Sstevel@tonic-gate   /* Get a password.  */
34117c478bd9Sstevel@tonic-gate   grub_memset (key, 0, sizeof (key));
34127c478bd9Sstevel@tonic-gate   get_cmdline ("Password: ", key, sizeof (key) - 1, '*', 0);
34137c478bd9Sstevel@tonic-gate 
34147c478bd9Sstevel@tonic-gate   /* Crypt the key.  */
34157c478bd9Sstevel@tonic-gate   make_md5_password (key, crypted);
34167c478bd9Sstevel@tonic-gate 
34177c478bd9Sstevel@tonic-gate   grub_printf ("Encrypted: %s\n", crypted);
34187c478bd9Sstevel@tonic-gate   return 0;
34197c478bd9Sstevel@tonic-gate }
34207c478bd9Sstevel@tonic-gate 
34217c478bd9Sstevel@tonic-gate static struct builtin builtin_md5crypt =
34227c478bd9Sstevel@tonic-gate {
34237c478bd9Sstevel@tonic-gate   "md5crypt",
34247c478bd9Sstevel@tonic-gate   md5crypt_func,
34257c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
34267c478bd9Sstevel@tonic-gate   "md5crypt",
34277c478bd9Sstevel@tonic-gate   "Generate a password in MD5 format."
34287c478bd9Sstevel@tonic-gate };
34297c478bd9Sstevel@tonic-gate #endif /* USE_MD5_PASSWORDS */
34307c478bd9Sstevel@tonic-gate 
34317c478bd9Sstevel@tonic-gate 
34327c478bd9Sstevel@tonic-gate /* module */
34337c478bd9Sstevel@tonic-gate static int
34347c478bd9Sstevel@tonic-gate module_func (char *arg, int flags)
34357c478bd9Sstevel@tonic-gate {
34367c478bd9Sstevel@tonic-gate   int len = grub_strlen (arg);
34377c478bd9Sstevel@tonic-gate 
34387c478bd9Sstevel@tonic-gate   switch (kernel_type)
34397c478bd9Sstevel@tonic-gate     {
34407c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_MULTIBOOT:
34417c478bd9Sstevel@tonic-gate       if (mb_cmdline + len + 1 > (char *) MB_CMDLINE_BUF + MB_CMDLINE_BUFLEN)
34427c478bd9Sstevel@tonic-gate 	{
34437c478bd9Sstevel@tonic-gate 	  errnum = ERR_WONT_FIT;
34447c478bd9Sstevel@tonic-gate 	  return 1;
34457c478bd9Sstevel@tonic-gate 	}
34467c478bd9Sstevel@tonic-gate       grub_memmove (mb_cmdline, arg, len + 1);
34477c478bd9Sstevel@tonic-gate       if (! load_module (arg, mb_cmdline))
34487c478bd9Sstevel@tonic-gate 	return 1;
3449b1b8ab34Slling 
3450b1b8ab34Slling       mb_cmdline += grub_strlen(mb_cmdline) + 1;
34517c478bd9Sstevel@tonic-gate       break;
34527c478bd9Sstevel@tonic-gate 
34537c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_LINUX:
34547c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_BIG_LINUX:
34557c478bd9Sstevel@tonic-gate       if (! load_initrd (arg))
34567c478bd9Sstevel@tonic-gate 	return 1;
34577c478bd9Sstevel@tonic-gate       break;
34587c478bd9Sstevel@tonic-gate 
34597c478bd9Sstevel@tonic-gate     default:
34607c478bd9Sstevel@tonic-gate       errnum = ERR_NEED_MB_KERNEL;
34617c478bd9Sstevel@tonic-gate       return 1;
34627c478bd9Sstevel@tonic-gate     }
34637c478bd9Sstevel@tonic-gate 
34647c478bd9Sstevel@tonic-gate   return 0;
34657c478bd9Sstevel@tonic-gate }
34667c478bd9Sstevel@tonic-gate 
34677c478bd9Sstevel@tonic-gate static struct builtin builtin_module =
34687c478bd9Sstevel@tonic-gate {
34697c478bd9Sstevel@tonic-gate   "module",
34707c478bd9Sstevel@tonic-gate   module_func,
34717c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
34727c478bd9Sstevel@tonic-gate   "module FILE [ARG ...]",
34737c478bd9Sstevel@tonic-gate   "Load a boot module FILE for a Multiboot format boot image (no"
34747c478bd9Sstevel@tonic-gate   " interpretation of the file contents is made, so users of this"
34757c478bd9Sstevel@tonic-gate   " command must know what the kernel in question expects). The"
34767c478bd9Sstevel@tonic-gate   " rest of the line is passed as the \"module command line\", like"
34777c478bd9Sstevel@tonic-gate   " the `kernel' command."
34787c478bd9Sstevel@tonic-gate };
34797c478bd9Sstevel@tonic-gate 
3480ae115bc7Smrj /* module$ */
3481ae115bc7Smrj static int
3482ae115bc7Smrj module_dollar_func (char *arg, int flags)
3483ae115bc7Smrj {
3484b1b8ab34Slling   char newarg[MAX_CMDLINE];	/* everything boils down to MAX_CMDLINE */
3485b1b8ab34Slling   char *cmdline_sav;
3486b1b8ab34Slling 
3487b1b8ab34Slling   grub_printf("loading '%s' ...\n", arg);
3488b1b8ab34Slling   expand_arch(arg, newarg);
3489b1b8ab34Slling 
3490b1b8ab34Slling   cmdline_sav = (char *)mb_cmdline;
3491b1b8ab34Slling   if (module_func(newarg, flags))
3492b1b8ab34Slling 	return (1);
3493b1b8ab34Slling 
3494ffb5616eSLin Ling   if (expand_dollar_bootfs(newarg, cmdline_sav)) {
3495ffb5616eSLin Ling 	grub_printf("cannot expand $ZFS-BOOTFS for dataset %s\n",
3496ffb5616eSLin Ling 	    current_bootfs);
3497b1b8ab34Slling 	return (1);
3498ffb5616eSLin Ling   }
3499b1b8ab34Slling 
3500b1b8ab34Slling   grub_printf("'%s' is loaded\n", (char *)cmdline_sav);
3501b1b8ab34Slling   mb_cmdline += grub_strlen(cmdline_sav) + 1;
3502b1b8ab34Slling 
3503b1b8ab34Slling   return (0);
3504ae115bc7Smrj }
3505ae115bc7Smrj 
3506ae115bc7Smrj static struct builtin builtin_module_dollar =
3507ae115bc7Smrj {
3508ae115bc7Smrj   "module$",
3509ae115bc7Smrj   module_dollar_func,
3510ae115bc7Smrj   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
3511ae115bc7Smrj   "module FILE [ARG ...]",
3512ae115bc7Smrj   " Just like module, but with $ISADIR expansion."
3513ae115bc7Smrj };
3514ae115bc7Smrj 
35157c478bd9Sstevel@tonic-gate 
35167c478bd9Sstevel@tonic-gate /* modulenounzip */
35177c478bd9Sstevel@tonic-gate static int
35187c478bd9Sstevel@tonic-gate modulenounzip_func (char *arg, int flags)
35197c478bd9Sstevel@tonic-gate {
35207c478bd9Sstevel@tonic-gate   int ret;
35217c478bd9Sstevel@tonic-gate 
35227c478bd9Sstevel@tonic-gate #ifndef NO_DECOMPRESSION
35237c478bd9Sstevel@tonic-gate   no_decompression = 1;
35247c478bd9Sstevel@tonic-gate #endif
35257c478bd9Sstevel@tonic-gate 
35267c478bd9Sstevel@tonic-gate   ret = module_func (arg, flags);
35277c478bd9Sstevel@tonic-gate 
35287c478bd9Sstevel@tonic-gate #ifndef NO_DECOMPRESSION
35297c478bd9Sstevel@tonic-gate   no_decompression = 0;
35307c478bd9Sstevel@tonic-gate #endif
35317c478bd9Sstevel@tonic-gate 
35327c478bd9Sstevel@tonic-gate   return ret;
35337c478bd9Sstevel@tonic-gate }
35347c478bd9Sstevel@tonic-gate 
35357c478bd9Sstevel@tonic-gate static struct builtin builtin_modulenounzip =
35367c478bd9Sstevel@tonic-gate {
35377c478bd9Sstevel@tonic-gate   "modulenounzip",
35387c478bd9Sstevel@tonic-gate   modulenounzip_func,
35397c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
35407c478bd9Sstevel@tonic-gate   "modulenounzip FILE [ARG ...]",
35417c478bd9Sstevel@tonic-gate   "The same as `module', except that automatic decompression is"
35427c478bd9Sstevel@tonic-gate   " disabled."
35437c478bd9Sstevel@tonic-gate };
35447c478bd9Sstevel@tonic-gate 
35457c478bd9Sstevel@tonic-gate 
35467c478bd9Sstevel@tonic-gate /* pager [on|off] */
35477c478bd9Sstevel@tonic-gate static int
35487c478bd9Sstevel@tonic-gate pager_func (char *arg, int flags)
35497c478bd9Sstevel@tonic-gate {
35507c478bd9Sstevel@tonic-gate   /* If ARG is empty, toggle the flag.  */
35517c478bd9Sstevel@tonic-gate   if (! *arg)
35527c478bd9Sstevel@tonic-gate     use_pager = ! use_pager;
35537c478bd9Sstevel@tonic-gate   else if (grub_memcmp (arg, "on", 2) == 0)
35547c478bd9Sstevel@tonic-gate     use_pager = 1;
35557c478bd9Sstevel@tonic-gate   else if (grub_memcmp (arg, "off", 3) == 0)
35567c478bd9Sstevel@tonic-gate     use_pager = 0;
35577c478bd9Sstevel@tonic-gate   else
35587c478bd9Sstevel@tonic-gate     {
35597c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
35607c478bd9Sstevel@tonic-gate       return 1;
35617c478bd9Sstevel@tonic-gate     }
35627c478bd9Sstevel@tonic-gate 
35637c478bd9Sstevel@tonic-gate   grub_printf (" Internal pager is now %s\n", use_pager ? "on" : "off");
35647c478bd9Sstevel@tonic-gate   return 0;
35657c478bd9Sstevel@tonic-gate }
35667c478bd9Sstevel@tonic-gate 
35677c478bd9Sstevel@tonic-gate static struct builtin builtin_pager =
35687c478bd9Sstevel@tonic-gate {
35697c478bd9Sstevel@tonic-gate   "pager",
35707c478bd9Sstevel@tonic-gate   pager_func,
35717c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
35727c478bd9Sstevel@tonic-gate   "pager [FLAG]",
35737c478bd9Sstevel@tonic-gate   "Toggle pager mode with no argument. If FLAG is given and its value"
35747c478bd9Sstevel@tonic-gate   " is `on', turn on the mode. If FLAG is `off', turn off the mode."
35757c478bd9Sstevel@tonic-gate };
35767c478bd9Sstevel@tonic-gate 
35777c478bd9Sstevel@tonic-gate 
35787c478bd9Sstevel@tonic-gate /* partnew PART TYPE START LEN */
35797c478bd9Sstevel@tonic-gate static int
35807c478bd9Sstevel@tonic-gate partnew_func (char *arg, int flags)
35817c478bd9Sstevel@tonic-gate {
35827c478bd9Sstevel@tonic-gate   int new_type, new_start, new_len;
35837c478bd9Sstevel@tonic-gate   int start_cl, start_ch, start_dh;
35847c478bd9Sstevel@tonic-gate   int end_cl, end_ch, end_dh;
35857c478bd9Sstevel@tonic-gate   int entry;
35867c478bd9Sstevel@tonic-gate   char mbr[512];
35877c478bd9Sstevel@tonic-gate 
35887c478bd9Sstevel@tonic-gate   /* Convert a LBA address to a CHS address in the INT 13 format.  */
35897c478bd9Sstevel@tonic-gate   auto void lba_to_chs (int lba, int *cl, int *ch, int *dh);
35907c478bd9Sstevel@tonic-gate   void lba_to_chs (int lba, int *cl, int *ch, int *dh)
35917c478bd9Sstevel@tonic-gate     {
35927c478bd9Sstevel@tonic-gate       int cylinder, head, sector;
35937c478bd9Sstevel@tonic-gate 
35947c478bd9Sstevel@tonic-gate       sector = lba % buf_geom.sectors + 1;
35957c478bd9Sstevel@tonic-gate       head = (lba / buf_geom.sectors) % buf_geom.heads;
35967c478bd9Sstevel@tonic-gate       cylinder = lba / (buf_geom.sectors * buf_geom.heads);
35977c478bd9Sstevel@tonic-gate 
35987c478bd9Sstevel@tonic-gate       if (cylinder >= buf_geom.cylinders)
35997c478bd9Sstevel@tonic-gate 	cylinder = buf_geom.cylinders - 1;
36007c478bd9Sstevel@tonic-gate 
36017c478bd9Sstevel@tonic-gate       *cl = sector | ((cylinder & 0x300) >> 2);
36027c478bd9Sstevel@tonic-gate       *ch = cylinder & 0xFF;
36037c478bd9Sstevel@tonic-gate       *dh = head;
36047c478bd9Sstevel@tonic-gate     }
36057c478bd9Sstevel@tonic-gate 
36067c478bd9Sstevel@tonic-gate   /* Get the drive and the partition.  */
36077c478bd9Sstevel@tonic-gate   if (! set_device (arg))
36087c478bd9Sstevel@tonic-gate     return 1;
36097c478bd9Sstevel@tonic-gate 
36107c478bd9Sstevel@tonic-gate   /* The drive must be a hard disk.  */
36117c478bd9Sstevel@tonic-gate   if (! (current_drive & 0x80))
36127c478bd9Sstevel@tonic-gate     {
36137c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
36147c478bd9Sstevel@tonic-gate       return 1;
36157c478bd9Sstevel@tonic-gate     }
36167c478bd9Sstevel@tonic-gate 
36177c478bd9Sstevel@tonic-gate   /* The partition must a primary partition.  */
36187c478bd9Sstevel@tonic-gate   if ((current_partition >> 16) > 3
36197c478bd9Sstevel@tonic-gate       || (current_partition & 0xFFFF) != 0xFFFF)
36207c478bd9Sstevel@tonic-gate     {
36217c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
36227c478bd9Sstevel@tonic-gate       return 1;
36237c478bd9Sstevel@tonic-gate     }
36247c478bd9Sstevel@tonic-gate 
36257c478bd9Sstevel@tonic-gate   entry = current_partition >> 16;
36267c478bd9Sstevel@tonic-gate 
36277c478bd9Sstevel@tonic-gate   /* Get the new partition type.  */
36287c478bd9Sstevel@tonic-gate   arg = skip_to (0, arg);
36297c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &new_type))
36307c478bd9Sstevel@tonic-gate     return 1;
36317c478bd9Sstevel@tonic-gate 
36327c478bd9Sstevel@tonic-gate   /* The partition type is unsigned char.  */
36337c478bd9Sstevel@tonic-gate   if (new_type > 0xFF)
36347c478bd9Sstevel@tonic-gate     {
36357c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
36367c478bd9Sstevel@tonic-gate       return 1;
36377c478bd9Sstevel@tonic-gate     }
36387c478bd9Sstevel@tonic-gate 
36397c478bd9Sstevel@tonic-gate   /* Get the new partition start.  */
36407c478bd9Sstevel@tonic-gate   arg = skip_to (0, arg);
36417c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &new_start))
36427c478bd9Sstevel@tonic-gate     return 1;
36437c478bd9Sstevel@tonic-gate 
36447c478bd9Sstevel@tonic-gate   /* Get the new partition length.  */
36457c478bd9Sstevel@tonic-gate   arg = skip_to (0, arg);
36467c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &new_len))
36477c478bd9Sstevel@tonic-gate     return 1;
36487c478bd9Sstevel@tonic-gate 
36497c478bd9Sstevel@tonic-gate   /* Read the MBR.  */
36507c478bd9Sstevel@tonic-gate   if (! rawread (current_drive, 0, 0, SECTOR_SIZE, mbr))
36517c478bd9Sstevel@tonic-gate     return 1;
36527c478bd9Sstevel@tonic-gate 
36537c478bd9Sstevel@tonic-gate   /* Check if the new partition will fit in the disk.  */
36547c478bd9Sstevel@tonic-gate   if (new_start + new_len > buf_geom.total_sectors)
36557c478bd9Sstevel@tonic-gate     {
36567c478bd9Sstevel@tonic-gate       errnum = ERR_GEOM;
36577c478bd9Sstevel@tonic-gate       return 1;
36587c478bd9Sstevel@tonic-gate     }
36597c478bd9Sstevel@tonic-gate 
36607c478bd9Sstevel@tonic-gate   /* Store the partition information in the MBR.  */
36617c478bd9Sstevel@tonic-gate   lba_to_chs (new_start, &start_cl, &start_ch, &start_dh);
36627c478bd9Sstevel@tonic-gate   lba_to_chs (new_start + new_len - 1, &end_cl, &end_ch, &end_dh);
36637c478bd9Sstevel@tonic-gate 
36647c478bd9Sstevel@tonic-gate   PC_SLICE_FLAG (mbr, entry) = 0;
36657c478bd9Sstevel@tonic-gate   PC_SLICE_HEAD (mbr, entry) = start_dh;
36667c478bd9Sstevel@tonic-gate   PC_SLICE_SEC (mbr, entry) = start_cl;
36677c478bd9Sstevel@tonic-gate   PC_SLICE_CYL (mbr, entry) = start_ch;
36687c478bd9Sstevel@tonic-gate   PC_SLICE_TYPE (mbr, entry) = new_type;
36697c478bd9Sstevel@tonic-gate   PC_SLICE_EHEAD (mbr, entry) = end_dh;
36707c478bd9Sstevel@tonic-gate   PC_SLICE_ESEC (mbr, entry) = end_cl;
36717c478bd9Sstevel@tonic-gate   PC_SLICE_ECYL (mbr, entry) = end_ch;
36727c478bd9Sstevel@tonic-gate   PC_SLICE_START (mbr, entry) = new_start;
36737c478bd9Sstevel@tonic-gate   PC_SLICE_LENGTH (mbr, entry) = new_len;
36747c478bd9Sstevel@tonic-gate 
36757c478bd9Sstevel@tonic-gate   /* Make sure that the MBR has a valid signature.  */
36767c478bd9Sstevel@tonic-gate   PC_MBR_SIG (mbr) = PC_MBR_SIGNATURE;
36777c478bd9Sstevel@tonic-gate 
36787c478bd9Sstevel@tonic-gate   /* Write back the MBR to the disk.  */
3679342440ecSPrasad Singamsetty   buf_track = BUF_CACHE_INVALID;
36807c478bd9Sstevel@tonic-gate   if (! rawwrite (current_drive, 0, mbr))
36817c478bd9Sstevel@tonic-gate     return 1;
36827c478bd9Sstevel@tonic-gate 
36837c478bd9Sstevel@tonic-gate   return 0;
36847c478bd9Sstevel@tonic-gate }
36857c478bd9Sstevel@tonic-gate 
36867c478bd9Sstevel@tonic-gate static struct builtin builtin_partnew =
36877c478bd9Sstevel@tonic-gate {
36887c478bd9Sstevel@tonic-gate   "partnew",
36897c478bd9Sstevel@tonic-gate   partnew_func,
36907c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
36917c478bd9Sstevel@tonic-gate   "partnew PART TYPE START LEN",
36927c478bd9Sstevel@tonic-gate   "Create a primary partition at the starting address START with the"
36937c478bd9Sstevel@tonic-gate   " length LEN, with the type TYPE. START and LEN are in sector units."
36947c478bd9Sstevel@tonic-gate };
36957c478bd9Sstevel@tonic-gate 
36967c478bd9Sstevel@tonic-gate 
36977c478bd9Sstevel@tonic-gate /* parttype PART TYPE */
36987c478bd9Sstevel@tonic-gate static int
36997c478bd9Sstevel@tonic-gate parttype_func (char *arg, int flags)
37007c478bd9Sstevel@tonic-gate {
37017c478bd9Sstevel@tonic-gate   int new_type;
37027c478bd9Sstevel@tonic-gate   unsigned long part = 0xFFFFFF;
37037c478bd9Sstevel@tonic-gate   unsigned long start, len, offset, ext_offset;
37047c478bd9Sstevel@tonic-gate   int entry, type;
37057c478bd9Sstevel@tonic-gate   char mbr[512];
37067c478bd9Sstevel@tonic-gate 
37077c478bd9Sstevel@tonic-gate   /* Get the drive and the partition.  */
37087c478bd9Sstevel@tonic-gate   if (! set_device (arg))
37097c478bd9Sstevel@tonic-gate     return 1;
37107c478bd9Sstevel@tonic-gate 
37117c478bd9Sstevel@tonic-gate   /* The drive must be a hard disk.  */
37127c478bd9Sstevel@tonic-gate   if (! (current_drive & 0x80))
37137c478bd9Sstevel@tonic-gate     {
37147c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
37157c478bd9Sstevel@tonic-gate       return 1;
37167c478bd9Sstevel@tonic-gate     }
37177c478bd9Sstevel@tonic-gate 
37187c478bd9Sstevel@tonic-gate   /* The partition must be a PC slice.  */
37197c478bd9Sstevel@tonic-gate   if ((current_partition >> 16) == 0xFF
37207c478bd9Sstevel@tonic-gate       || (current_partition & 0xFFFF) != 0xFFFF)
37217c478bd9Sstevel@tonic-gate     {
37227c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
37237c478bd9Sstevel@tonic-gate       return 1;
37247c478bd9Sstevel@tonic-gate     }
37257c478bd9Sstevel@tonic-gate 
37267c478bd9Sstevel@tonic-gate   /* Get the new partition type.  */
37277c478bd9Sstevel@tonic-gate   arg = skip_to (0, arg);
37287c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &new_type))
37297c478bd9Sstevel@tonic-gate     return 1;
37307c478bd9Sstevel@tonic-gate 
37317c478bd9Sstevel@tonic-gate   /* The partition type is unsigned char.  */
37327c478bd9Sstevel@tonic-gate   if (new_type > 0xFF)
37337c478bd9Sstevel@tonic-gate     {
37347c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
37357c478bd9Sstevel@tonic-gate       return 1;
37367c478bd9Sstevel@tonic-gate     }
37377c478bd9Sstevel@tonic-gate 
37387c478bd9Sstevel@tonic-gate   /* Look for the partition.  */
37397c478bd9Sstevel@tonic-gate   while (next_partition (current_drive, 0xFFFFFF, &part, &type,
37407c478bd9Sstevel@tonic-gate 			 &start, &len, &offset, &entry,
37417c478bd9Sstevel@tonic-gate 			 &ext_offset, mbr))
37427c478bd9Sstevel@tonic-gate     {
37437c478bd9Sstevel@tonic-gate       if (part == current_partition)
37447c478bd9Sstevel@tonic-gate 	{
37457c478bd9Sstevel@tonic-gate 	  /* Found.  */
37467c478bd9Sstevel@tonic-gate 
37477c478bd9Sstevel@tonic-gate 	  /* Set the type to NEW_TYPE.  */
37487c478bd9Sstevel@tonic-gate 	  PC_SLICE_TYPE (mbr, entry) = new_type;
37497c478bd9Sstevel@tonic-gate 
37507c478bd9Sstevel@tonic-gate 	  /* Write back the MBR to the disk.  */
3751342440ecSPrasad Singamsetty 	  buf_track = BUF_CACHE_INVALID;
37527c478bd9Sstevel@tonic-gate 	  if (! rawwrite (current_drive, offset, mbr))
37537c478bd9Sstevel@tonic-gate 	    return 1;
37547c478bd9Sstevel@tonic-gate 
37557c478bd9Sstevel@tonic-gate 	  /* Succeed.  */
37567c478bd9Sstevel@tonic-gate 	  return 0;
37577c478bd9Sstevel@tonic-gate 	}
37587c478bd9Sstevel@tonic-gate     }
37597c478bd9Sstevel@tonic-gate 
37607c478bd9Sstevel@tonic-gate   /* The partition was not found.  ERRNUM was set by next_partition.  */
37617c478bd9Sstevel@tonic-gate   return 1;
37627c478bd9Sstevel@tonic-gate }
37637c478bd9Sstevel@tonic-gate 
37647c478bd9Sstevel@tonic-gate static struct builtin builtin_parttype =
37657c478bd9Sstevel@tonic-gate {
37667c478bd9Sstevel@tonic-gate   "parttype",
37677c478bd9Sstevel@tonic-gate   parttype_func,
37687c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
37697c478bd9Sstevel@tonic-gate   "parttype PART TYPE",
37707c478bd9Sstevel@tonic-gate   "Change the type of the partition PART to TYPE."
37717c478bd9Sstevel@tonic-gate };
37727c478bd9Sstevel@tonic-gate 
37737c478bd9Sstevel@tonic-gate 
37747c478bd9Sstevel@tonic-gate /* password */
37757c478bd9Sstevel@tonic-gate static int
37767c478bd9Sstevel@tonic-gate password_func (char *arg, int flags)
37777c478bd9Sstevel@tonic-gate {
37787c478bd9Sstevel@tonic-gate   int len;
37797c478bd9Sstevel@tonic-gate   password_t type = PASSWORD_PLAIN;
37807c478bd9Sstevel@tonic-gate 
37817c478bd9Sstevel@tonic-gate #ifdef USE_MD5_PASSWORDS
37827c478bd9Sstevel@tonic-gate   if (grub_memcmp (arg, "--md5", 5) == 0)
37837c478bd9Sstevel@tonic-gate     {
37847c478bd9Sstevel@tonic-gate       type = PASSWORD_MD5;
37857c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
37867c478bd9Sstevel@tonic-gate     }
37877c478bd9Sstevel@tonic-gate #endif
37887c478bd9Sstevel@tonic-gate   if (grub_memcmp (arg, "--", 2) == 0)
37897c478bd9Sstevel@tonic-gate     {
37907c478bd9Sstevel@tonic-gate       type = PASSWORD_UNSUPPORTED;
37917c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
37927c478bd9Sstevel@tonic-gate     }
37937c478bd9Sstevel@tonic-gate 
37947c478bd9Sstevel@tonic-gate   if ((flags & (BUILTIN_CMDLINE | BUILTIN_SCRIPT)) != 0)
37957c478bd9Sstevel@tonic-gate     {
37967c478bd9Sstevel@tonic-gate       /* Do password check! */
37977c478bd9Sstevel@tonic-gate       char entered[32];
37987c478bd9Sstevel@tonic-gate 
37997c478bd9Sstevel@tonic-gate       /* Wipe out any previously entered password */
38007c478bd9Sstevel@tonic-gate       entered[0] = 0;
38017c478bd9Sstevel@tonic-gate       get_cmdline ("Password: ", entered, 31, '*', 0);
38027c478bd9Sstevel@tonic-gate 
38037c478bd9Sstevel@tonic-gate       nul_terminate (arg);
38047c478bd9Sstevel@tonic-gate       if (check_password (entered, arg, type) != 0)
38057c478bd9Sstevel@tonic-gate 	{
38067c478bd9Sstevel@tonic-gate 	  errnum = ERR_PRIVILEGED;
38077c478bd9Sstevel@tonic-gate 	  return 1;
38087c478bd9Sstevel@tonic-gate 	}
38097c478bd9Sstevel@tonic-gate     }
38107c478bd9Sstevel@tonic-gate   else
38117c478bd9Sstevel@tonic-gate     {
38127c478bd9Sstevel@tonic-gate       len = grub_strlen (arg);
38137c478bd9Sstevel@tonic-gate 
38147c478bd9Sstevel@tonic-gate       /* PASSWORD NUL NUL ... */
38157c478bd9Sstevel@tonic-gate       if (len + 2 > PASSWORD_BUFLEN)
38167c478bd9Sstevel@tonic-gate 	{
38177c478bd9Sstevel@tonic-gate 	  errnum = ERR_WONT_FIT;
38187c478bd9Sstevel@tonic-gate 	  return 1;
38197c478bd9Sstevel@tonic-gate 	}
38207c478bd9Sstevel@tonic-gate 
38217c478bd9Sstevel@tonic-gate       /* Copy the password and clear the rest of the buffer.  */
38227c478bd9Sstevel@tonic-gate       password = (char *) PASSWORD_BUF;
38237c478bd9Sstevel@tonic-gate       grub_memmove (password, arg, len);
38247c478bd9Sstevel@tonic-gate       grub_memset (password + len, 0, PASSWORD_BUFLEN - len);
38257c478bd9Sstevel@tonic-gate       password_type = type;
38267c478bd9Sstevel@tonic-gate     }
38277c478bd9Sstevel@tonic-gate   return 0;
38287c478bd9Sstevel@tonic-gate }
38297c478bd9Sstevel@tonic-gate 
38307c478bd9Sstevel@tonic-gate static struct builtin builtin_password =
38317c478bd9Sstevel@tonic-gate {
38327c478bd9Sstevel@tonic-gate   "password",
38337c478bd9Sstevel@tonic-gate   password_func,
38347c478bd9Sstevel@tonic-gate   BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_NO_ECHO,
38357c478bd9Sstevel@tonic-gate   "password [--md5] PASSWD [FILE]",
38367c478bd9Sstevel@tonic-gate   "If used in the first section of a menu file, disable all"
38377c478bd9Sstevel@tonic-gate   " interactive editing control (menu entry editor and"
38387c478bd9Sstevel@tonic-gate   " command line). If the password PASSWD is entered, it loads the"
38397c478bd9Sstevel@tonic-gate   " FILE as a new config file and restarts the GRUB Stage 2. If you"
38407c478bd9Sstevel@tonic-gate   " omit the argument FILE, then GRUB just unlocks privileged"
38417c478bd9Sstevel@tonic-gate   " instructions.  You can also use it in the script section, in"
38427c478bd9Sstevel@tonic-gate   " which case it will ask for the password, before continueing."
38437c478bd9Sstevel@tonic-gate   " The option --md5 tells GRUB that PASSWD is encrypted with"
38447c478bd9Sstevel@tonic-gate   " md5crypt."
38457c478bd9Sstevel@tonic-gate };
38467c478bd9Sstevel@tonic-gate 
38477c478bd9Sstevel@tonic-gate 
38487c478bd9Sstevel@tonic-gate /* pause */
38497c478bd9Sstevel@tonic-gate static int
38507c478bd9Sstevel@tonic-gate pause_func (char *arg, int flags)
38517c478bd9Sstevel@tonic-gate {
38527c478bd9Sstevel@tonic-gate   printf("%s\n", arg);
38537c478bd9Sstevel@tonic-gate 
38547c478bd9Sstevel@tonic-gate   /* If ESC is returned, then abort this entry.  */
38557c478bd9Sstevel@tonic-gate   if (ASCII_CHAR (getkey ()) == 27)
38567c478bd9Sstevel@tonic-gate     return 1;
38577c478bd9Sstevel@tonic-gate 
38587c478bd9Sstevel@tonic-gate   return 0;
38597c478bd9Sstevel@tonic-gate }
38607c478bd9Sstevel@tonic-gate 
38617c478bd9Sstevel@tonic-gate static struct builtin builtin_pause =
38627c478bd9Sstevel@tonic-gate {
38637c478bd9Sstevel@tonic-gate   "pause",
38647c478bd9Sstevel@tonic-gate   pause_func,
38657c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_NO_ECHO,
38667c478bd9Sstevel@tonic-gate   "pause [MESSAGE ...]",
38677c478bd9Sstevel@tonic-gate   "Print MESSAGE, then wait until a key is pressed."
38687c478bd9Sstevel@tonic-gate };
38697c478bd9Sstevel@tonic-gate 
38707c478bd9Sstevel@tonic-gate 
38717c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
38727c478bd9Sstevel@tonic-gate /* quit */
38737c478bd9Sstevel@tonic-gate static int
38747c478bd9Sstevel@tonic-gate quit_func (char *arg, int flags)
38757c478bd9Sstevel@tonic-gate {
38767c478bd9Sstevel@tonic-gate   stop ();
38777c478bd9Sstevel@tonic-gate 
38787c478bd9Sstevel@tonic-gate   /* Never reach here.  */
38797c478bd9Sstevel@tonic-gate   return 0;
38807c478bd9Sstevel@tonic-gate }
38817c478bd9Sstevel@tonic-gate 
38827c478bd9Sstevel@tonic-gate static struct builtin builtin_quit =
38837c478bd9Sstevel@tonic-gate {
38847c478bd9Sstevel@tonic-gate   "quit",
38857c478bd9Sstevel@tonic-gate   quit_func,
38867c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
38877c478bd9Sstevel@tonic-gate   "quit",
38887c478bd9Sstevel@tonic-gate   "Exit from the GRUB shell."
38897c478bd9Sstevel@tonic-gate };
38907c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
38917c478bd9Sstevel@tonic-gate 
38927c478bd9Sstevel@tonic-gate 
38937c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
38947c478bd9Sstevel@tonic-gate /* rarp */
38957c478bd9Sstevel@tonic-gate static int
38967c478bd9Sstevel@tonic-gate rarp_func (char *arg, int flags)
38977c478bd9Sstevel@tonic-gate {
38987c478bd9Sstevel@tonic-gate   if (! rarp ())
38997c478bd9Sstevel@tonic-gate     {
39007c478bd9Sstevel@tonic-gate       if (errnum == ERR_NONE)
39017c478bd9Sstevel@tonic-gate 	errnum = ERR_DEV_VALUES;
39027c478bd9Sstevel@tonic-gate 
39037c478bd9Sstevel@tonic-gate       return 1;
39047c478bd9Sstevel@tonic-gate     }
39057c478bd9Sstevel@tonic-gate 
39067c478bd9Sstevel@tonic-gate   /* Notify the configuration.  */
39077c478bd9Sstevel@tonic-gate   print_network_configuration ();
39087c478bd9Sstevel@tonic-gate   return 0;
39097c478bd9Sstevel@tonic-gate }
39107c478bd9Sstevel@tonic-gate 
39117c478bd9Sstevel@tonic-gate static struct builtin builtin_rarp =
39127c478bd9Sstevel@tonic-gate {
39137c478bd9Sstevel@tonic-gate   "rarp",
39147c478bd9Sstevel@tonic-gate   rarp_func,
39157c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
39167c478bd9Sstevel@tonic-gate   "rarp",
39177c478bd9Sstevel@tonic-gate   "Initialize a network device via RARP."
39187c478bd9Sstevel@tonic-gate };
39197c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
39207c478bd9Sstevel@tonic-gate 
39217c478bd9Sstevel@tonic-gate 
39227c478bd9Sstevel@tonic-gate static int
39237c478bd9Sstevel@tonic-gate read_func (char *arg, int flags)
39247c478bd9Sstevel@tonic-gate {
39257c478bd9Sstevel@tonic-gate   int addr;
39267c478bd9Sstevel@tonic-gate 
39277c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &addr))
39287c478bd9Sstevel@tonic-gate     return 1;
39297c478bd9Sstevel@tonic-gate 
39307c478bd9Sstevel@tonic-gate   grub_printf ("Address 0x%x: Value 0x%x\n",
39317c478bd9Sstevel@tonic-gate 	       addr, *((unsigned *) RAW_ADDR (addr)));
39327c478bd9Sstevel@tonic-gate   return 0;
39337c478bd9Sstevel@tonic-gate }
39347c478bd9Sstevel@tonic-gate 
39357c478bd9Sstevel@tonic-gate static struct builtin builtin_read =
39367c478bd9Sstevel@tonic-gate {
39377c478bd9Sstevel@tonic-gate   "read",
39387c478bd9Sstevel@tonic-gate   read_func,
39397c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
39407c478bd9Sstevel@tonic-gate   "read ADDR",
39417c478bd9Sstevel@tonic-gate   "Read a 32-bit value from memory at address ADDR and"
39427c478bd9Sstevel@tonic-gate   " display it in hex format."
39437c478bd9Sstevel@tonic-gate };
39447c478bd9Sstevel@tonic-gate 
39457c478bd9Sstevel@tonic-gate 
39467c478bd9Sstevel@tonic-gate /* reboot */
39477c478bd9Sstevel@tonic-gate static int
39487c478bd9Sstevel@tonic-gate reboot_func (char *arg, int flags)
39497c478bd9Sstevel@tonic-gate {
39507c478bd9Sstevel@tonic-gate   grub_reboot ();
39517c478bd9Sstevel@tonic-gate 
39527c478bd9Sstevel@tonic-gate   /* Never reach here.  */
39537c478bd9Sstevel@tonic-gate   return 1;
39547c478bd9Sstevel@tonic-gate }
39557c478bd9Sstevel@tonic-gate 
39567c478bd9Sstevel@tonic-gate static struct builtin builtin_reboot =
39577c478bd9Sstevel@tonic-gate {
39587c478bd9Sstevel@tonic-gate   "reboot",
39597c478bd9Sstevel@tonic-gate   reboot_func,
39607c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
39617c478bd9Sstevel@tonic-gate   "reboot",
39627c478bd9Sstevel@tonic-gate   "Reboot your system."
39637c478bd9Sstevel@tonic-gate };
39647c478bd9Sstevel@tonic-gate 
39657c478bd9Sstevel@tonic-gate 
39667c478bd9Sstevel@tonic-gate /* Print the root device information.  */
39677c478bd9Sstevel@tonic-gate static void
39687c478bd9Sstevel@tonic-gate print_root_device (void)
39697c478bd9Sstevel@tonic-gate {
39707c478bd9Sstevel@tonic-gate   if (saved_drive == NETWORK_DRIVE)
39717c478bd9Sstevel@tonic-gate     {
39727c478bd9Sstevel@tonic-gate       /* Network drive.  */
39737c478bd9Sstevel@tonic-gate       grub_printf (" (nd):");
39747c478bd9Sstevel@tonic-gate     }
39757c478bd9Sstevel@tonic-gate   else if (saved_drive & 0x80)
39767c478bd9Sstevel@tonic-gate     {
39777c478bd9Sstevel@tonic-gate       /* Hard disk drive.  */
39787c478bd9Sstevel@tonic-gate       grub_printf (" (hd%d", saved_drive - 0x80);
39797c478bd9Sstevel@tonic-gate 
39807c478bd9Sstevel@tonic-gate       if ((saved_partition & 0xFF0000) != 0xFF0000)
39817c478bd9Sstevel@tonic-gate 	grub_printf (",%d", saved_partition >> 16);
39827c478bd9Sstevel@tonic-gate 
39837c478bd9Sstevel@tonic-gate       if ((saved_partition & 0x00FF00) != 0x00FF00)
39847c478bd9Sstevel@tonic-gate 	grub_printf (",%c", ((saved_partition >> 8) & 0xFF) + 'a');
39857c478bd9Sstevel@tonic-gate 
39867c478bd9Sstevel@tonic-gate       grub_printf ("):");
39877c478bd9Sstevel@tonic-gate     }
39887c478bd9Sstevel@tonic-gate   else
39897c478bd9Sstevel@tonic-gate     {
39907c478bd9Sstevel@tonic-gate       /* Floppy disk drive.  */
39917c478bd9Sstevel@tonic-gate       grub_printf (" (fd%d):", saved_drive);
39927c478bd9Sstevel@tonic-gate     }
39937c478bd9Sstevel@tonic-gate 
39947c478bd9Sstevel@tonic-gate   /* Print the filesystem information.  */
39957c478bd9Sstevel@tonic-gate   current_partition = saved_partition;
39967c478bd9Sstevel@tonic-gate   current_drive = saved_drive;
39977c478bd9Sstevel@tonic-gate   print_fsys_type ();
39987c478bd9Sstevel@tonic-gate }
39997c478bd9Sstevel@tonic-gate 
40007c478bd9Sstevel@tonic-gate static int
40017c478bd9Sstevel@tonic-gate real_root_func (char *arg, int attempt_mount)
40027c478bd9Sstevel@tonic-gate {
40037c478bd9Sstevel@tonic-gate   int hdbias = 0;
40047c478bd9Sstevel@tonic-gate   char *biasptr;
40057c478bd9Sstevel@tonic-gate   char *next;
40067c478bd9Sstevel@tonic-gate 
40077c478bd9Sstevel@tonic-gate   /* If ARG is empty, just print the current root device.  */
40087c478bd9Sstevel@tonic-gate   if (! *arg)
40097c478bd9Sstevel@tonic-gate     {
40107c478bd9Sstevel@tonic-gate       print_root_device ();
40117c478bd9Sstevel@tonic-gate       return 0;
40127c478bd9Sstevel@tonic-gate     }
40137c478bd9Sstevel@tonic-gate 
40147c478bd9Sstevel@tonic-gate   /* Call set_device to get the drive and the partition in ARG.  */
40157c478bd9Sstevel@tonic-gate   next = set_device (arg);
40167c478bd9Sstevel@tonic-gate   if (! next)
40177c478bd9Sstevel@tonic-gate     return 1;
40187c478bd9Sstevel@tonic-gate 
40197c478bd9Sstevel@tonic-gate   /* Ignore ERR_FSYS_MOUNT.  */
40207c478bd9Sstevel@tonic-gate   if (attempt_mount)
40217c478bd9Sstevel@tonic-gate     {
40227c478bd9Sstevel@tonic-gate       if (! open_device () && errnum != ERR_FSYS_MOUNT)
40237c478bd9Sstevel@tonic-gate 	return 1;
40247c478bd9Sstevel@tonic-gate     }
40257c478bd9Sstevel@tonic-gate   else
40267c478bd9Sstevel@tonic-gate     {
40277c478bd9Sstevel@tonic-gate       /* This is necessary, because the location of a partition table
40287c478bd9Sstevel@tonic-gate 	 must be set appropriately.  */
40297c478bd9Sstevel@tonic-gate       if (open_partition ())
40307c478bd9Sstevel@tonic-gate 	{
40317c478bd9Sstevel@tonic-gate 	  set_bootdev (0);
40327c478bd9Sstevel@tonic-gate 	  if (errnum)
40337c478bd9Sstevel@tonic-gate 	    return 1;
40347c478bd9Sstevel@tonic-gate 	}
40357c478bd9Sstevel@tonic-gate     }
40367c478bd9Sstevel@tonic-gate 
40377c478bd9Sstevel@tonic-gate   /* Clear ERRNUM.  */
40387c478bd9Sstevel@tonic-gate   errnum = 0;
40397c478bd9Sstevel@tonic-gate   saved_partition = current_partition;
40407c478bd9Sstevel@tonic-gate   saved_drive = current_drive;
40417c478bd9Sstevel@tonic-gate 
40427c478bd9Sstevel@tonic-gate   if (attempt_mount)
40437c478bd9Sstevel@tonic-gate     {
40447c478bd9Sstevel@tonic-gate       /* BSD and chainloading evil hacks !!  */
40457c478bd9Sstevel@tonic-gate       biasptr = skip_to (0, next);
40467c478bd9Sstevel@tonic-gate       safe_parse_maxint (&biasptr, &hdbias);
40477c478bd9Sstevel@tonic-gate       errnum = 0;
40487c478bd9Sstevel@tonic-gate       bootdev = set_bootdev (hdbias);
40497c478bd9Sstevel@tonic-gate       if (errnum)
40507c478bd9Sstevel@tonic-gate 	return 1;
40517c478bd9Sstevel@tonic-gate 
40527c478bd9Sstevel@tonic-gate       /* Print the type of the filesystem.  */
40537c478bd9Sstevel@tonic-gate       print_fsys_type ();
40547c478bd9Sstevel@tonic-gate     }
40557c478bd9Sstevel@tonic-gate 
40567c478bd9Sstevel@tonic-gate   return 0;
40577c478bd9Sstevel@tonic-gate }
40587c478bd9Sstevel@tonic-gate 
40597c478bd9Sstevel@tonic-gate static int
40607c478bd9Sstevel@tonic-gate root_func (char *arg, int flags)
40617c478bd9Sstevel@tonic-gate {
4062b1b8ab34Slling   is_zfs_mount = 0;
40637c478bd9Sstevel@tonic-gate   return real_root_func (arg, 1);
40647c478bd9Sstevel@tonic-gate }
40657c478bd9Sstevel@tonic-gate 
40667c478bd9Sstevel@tonic-gate static struct builtin builtin_root =
40677c478bd9Sstevel@tonic-gate {
40687c478bd9Sstevel@tonic-gate   "root",
40697c478bd9Sstevel@tonic-gate   root_func,
40707c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
40717c478bd9Sstevel@tonic-gate   "root [DEVICE [HDBIAS]]",
40727c478bd9Sstevel@tonic-gate   "Set the current \"root device\" to the device DEVICE, then"
40737c478bd9Sstevel@tonic-gate   " attempt to mount it to get the partition size (for passing the"
40747c478bd9Sstevel@tonic-gate   " partition descriptor in `ES:ESI', used by some chain-loaded"
40757c478bd9Sstevel@tonic-gate   " bootloaders), the BSD drive-type (for booting BSD kernels using"
40767c478bd9Sstevel@tonic-gate   " their native boot format), and correctly determine "
40777c478bd9Sstevel@tonic-gate   " the PC partition where a BSD sub-partition is located. The"
40787c478bd9Sstevel@tonic-gate   " optional HDBIAS parameter is a number to tell a BSD kernel"
40797c478bd9Sstevel@tonic-gate   " how many BIOS drive numbers are on controllers before the current"
40807c478bd9Sstevel@tonic-gate   " one. For example, if there is an IDE disk and a SCSI disk, and your"
40817c478bd9Sstevel@tonic-gate   " FreeBSD root partition is on the SCSI disk, then use a `1' for HDBIAS."
40827c478bd9Sstevel@tonic-gate };
40837c478bd9Sstevel@tonic-gate 
4084eb2bd662Svikram 
4085eb2bd662Svikram /* findroot */
4086eb2bd662Svikram static int
4087eb2bd662Svikram findroot_func (char *arg, int flags)
4088eb2bd662Svikram {
4089eb2bd662Svikram   int ret;
4090eb2bd662Svikram   char root[32];
4091eb2bd662Svikram 
4092eb2bd662Svikram   if (grub_strlen(arg) >= BOOTSIGN_ARGLEN) {
4093eb2bd662Svikram   	errnum = ERR_BAD_ARGUMENT;
4094eb2bd662Svikram 	return 1;
4095eb2bd662Svikram   }
4096eb2bd662Svikram 
4097eb2bd662Svikram   if (arg[0] == '\0') {
4098eb2bd662Svikram   	errnum = ERR_BAD_ARGUMENT;
4099eb2bd662Svikram 	return 1;
4100eb2bd662Svikram   }
4101eb2bd662Svikram 
4102eb2bd662Svikram   if (grub_strchr(arg, '/')) {
4103eb2bd662Svikram   	errnum = ERR_BAD_ARGUMENT;
4104eb2bd662Svikram 	return 1;
4105eb2bd662Svikram   }
4106eb2bd662Svikram 
4107051aabe6Staylor   find_best_root = 1;
4108051aabe6Staylor   best_drive = 0;
4109051aabe6Staylor   best_part = 0;
4110eb2bd662Svikram   ret = find_common(arg, root, 1, flags);
4111eb2bd662Svikram   if (ret != 0)
4112eb2bd662Svikram 	return (ret);
4113051aabe6Staylor   find_best_root = 0;
4114eb2bd662Svikram 
4115eb2bd662Svikram   return real_root_func (root, 1);
4116eb2bd662Svikram }
4117eb2bd662Svikram 
4118eb2bd662Svikram static struct builtin builtin_findroot =
4119eb2bd662Svikram {
4120eb2bd662Svikram   "findroot",
4121eb2bd662Svikram   findroot_func,
4122eb2bd662Svikram   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
4123963390b4Svikram   "findroot  <SIGNATURE | (SIGNATURE,partition[,slice])>",
4124963390b4Svikram   "Searches across all partitions for the file name SIGNATURE."
4125963390b4Svikram   " GRUB looks only in the directory /boot/grub/bootsign for the"
4126963390b4Svikram   " filename and it stops as soon as it finds the first instance of"
4127963390b4Svikram   " the file - so to be useful the name of the signature file must be"
4128963390b4Svikram   " unique across all partitions. Once the signature file is found,"
4129963390b4Svikram   " GRUB invokes the \"root\" command on that partition."
4130eb2bd662Svikram   " An optional partition and slice may be specified to optimize the search."
4131eb2bd662Svikram };
4132eb2bd662Svikram 
4133b1b8ab34Slling 
4134b1b8ab34Slling /*
4135b1b8ab34Slling  * COMMAND to override the default root filesystem for ZFS
4136b1b8ab34Slling  *	bootfs pool/fs
4137b1b8ab34Slling  */
4138b1b8ab34Slling static int
4139b1b8ab34Slling bootfs_func (char *arg, int flags)
4140b1b8ab34Slling {
4141b1b8ab34Slling 	int hdbias = 0;
4142b1b8ab34Slling 	char *biasptr;
4143b1b8ab34Slling 	char *next;
4144b1b8ab34Slling 
4145b1b8ab34Slling 	if (! *arg) {
4146b1b8ab34Slling 	    if (current_bootfs[0] != '\0')
4147b1b8ab34Slling 		grub_printf ("The zfs boot filesystem is set to '%s'.\n",
4148b1b8ab34Slling 				current_bootfs);
4149b1b8ab34Slling 	    else if (current_rootpool[0] != 0 && current_bootfs_obj != 0)
4150b1b8ab34Slling 		grub_printf("The zfs boot filesystem is <default: %s/%u>.",
4151b1b8ab34Slling 				current_rootpool, current_bootfs_obj);
4152b1b8ab34Slling 	    else
415311a41203Slling 		grub_printf ("The zfs boot filesystem will be derived from "
415411a41203Slling 			"the default bootfs pool property.\n");
4155b1b8ab34Slling 
4156b1b8ab34Slling 	    return (1);
4157b1b8ab34Slling 	}
4158b1b8ab34Slling 
4159b1b8ab34Slling 	/* Verify the zfs filesystem name */
4160b1b8ab34Slling 	if (arg[0] == '/' || arg[0] == '\0') {
4161b1b8ab34Slling 		errnum = ERR_BAD_ARGUMENT;
4162b1b8ab34Slling 		return 0;
4163b1b8ab34Slling 	}
4164b35c6776Staylor 	if (current_rootpool[0] != 0 && grub_strncmp(arg,
4165b35c6776Staylor 	    current_rootpool, strlen(current_rootpool))) {
4166b35c6776Staylor 		errnum = ERR_BAD_ARGUMENT;
4167b35c6776Staylor 		return 0;
4168b35c6776Staylor 	}
4169b1b8ab34Slling 
4170b1b8ab34Slling 	if (set_bootfs(arg) == 0) {
4171b1b8ab34Slling 		errnum = ERR_BAD_ARGUMENT;
4172b1b8ab34Slling 		return 0;
4173b1b8ab34Slling 	}
4174b1b8ab34Slling 
4175b1b8ab34Slling 	return (1);
4176b1b8ab34Slling }
4177b1b8ab34Slling 
4178b1b8ab34Slling static struct builtin builtin_bootfs =
4179b1b8ab34Slling {
4180b1b8ab34Slling   "bootfs",
4181b1b8ab34Slling   bootfs_func,
4182b1b8ab34Slling   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
4183b1b8ab34Slling   "bootfs [ZFSBOOTFS]",
4184b1b8ab34Slling   "Set the current zfs boot filesystem to ZFSBOOTFS (rootpool/rootfs)."
4185b1b8ab34Slling };
4186b1b8ab34Slling 
41877c478bd9Sstevel@tonic-gate 
41887c478bd9Sstevel@tonic-gate /* rootnoverify */
41897c478bd9Sstevel@tonic-gate static int
41907c478bd9Sstevel@tonic-gate rootnoverify_func (char *arg, int flags)
41917c478bd9Sstevel@tonic-gate {
41927c478bd9Sstevel@tonic-gate   return real_root_func (arg, 0);
41937c478bd9Sstevel@tonic-gate }
41947c478bd9Sstevel@tonic-gate 
41957c478bd9Sstevel@tonic-gate static struct builtin builtin_rootnoverify =
41967c478bd9Sstevel@tonic-gate {
41977c478bd9Sstevel@tonic-gate   "rootnoverify",
41987c478bd9Sstevel@tonic-gate   rootnoverify_func,
41997c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
42007c478bd9Sstevel@tonic-gate   "rootnoverify [DEVICE [HDBIAS]]",
42017c478bd9Sstevel@tonic-gate   "Similar to `root', but don't attempt to mount the partition. This"
42027c478bd9Sstevel@tonic-gate   " is useful for when an OS is outside of the area of the disk that"
42037c478bd9Sstevel@tonic-gate   " GRUB can read, but setting the correct root device is still"
42047c478bd9Sstevel@tonic-gate   " desired. Note that the items mentioned in `root' which"
42057c478bd9Sstevel@tonic-gate   " derived from attempting the mount will NOT work correctly."
42067c478bd9Sstevel@tonic-gate };
42077c478bd9Sstevel@tonic-gate 
42087c478bd9Sstevel@tonic-gate 
42097c478bd9Sstevel@tonic-gate /* savedefault */
42107c478bd9Sstevel@tonic-gate static int
42117c478bd9Sstevel@tonic-gate savedefault_func (char *arg, int flags)
42127c478bd9Sstevel@tonic-gate {
42137c478bd9Sstevel@tonic-gate #if !defined(SUPPORT_DISKLESS) && !defined(GRUB_UTIL)
42147c478bd9Sstevel@tonic-gate   unsigned long tmp_drive = saved_drive;
42157c478bd9Sstevel@tonic-gate   unsigned long tmp_partition = saved_partition;
42167c478bd9Sstevel@tonic-gate   char *default_file = (char *) DEFAULT_FILE_BUF;
42177c478bd9Sstevel@tonic-gate   char buf[10];
42187c478bd9Sstevel@tonic-gate   char sect[SECTOR_SIZE];
42197c478bd9Sstevel@tonic-gate   int entryno;
42207c478bd9Sstevel@tonic-gate   int sector_count = 0;
4221342440ecSPrasad Singamsetty   unsigned int saved_sectors[2];
42227c478bd9Sstevel@tonic-gate   int saved_offsets[2];
42237c478bd9Sstevel@tonic-gate   int saved_lengths[2];
42247c478bd9Sstevel@tonic-gate 
4225b1b8ab34Slling   /* not supported for zfs root */
4226b1b8ab34Slling   if (is_zfs_mount == 1) {
4227b1b8ab34Slling 	return (0); /* no-op */
4228b1b8ab34Slling   }
4229b1b8ab34Slling 
42307c478bd9Sstevel@tonic-gate   /* Save sector information about at most two sectors.  */
42311b8adde7SWilliam Kucharski   auto void disk_read_savesect_func (unsigned int sector, int offset,
42321b8adde7SWilliam Kucharski       int length);
42331b8adde7SWilliam Kucharski   void disk_read_savesect_func (unsigned int sector, int offset, int length)
42347c478bd9Sstevel@tonic-gate     {
42357c478bd9Sstevel@tonic-gate       if (sector_count < 2)
42367c478bd9Sstevel@tonic-gate 	{
42377c478bd9Sstevel@tonic-gate 	  saved_sectors[sector_count] = sector;
42387c478bd9Sstevel@tonic-gate 	  saved_offsets[sector_count] = offset;
42397c478bd9Sstevel@tonic-gate 	  saved_lengths[sector_count] = length;
42407c478bd9Sstevel@tonic-gate 	}
42417c478bd9Sstevel@tonic-gate       sector_count++;
42427c478bd9Sstevel@tonic-gate     }
42437c478bd9Sstevel@tonic-gate 
42447c478bd9Sstevel@tonic-gate   /* This command is only useful when you boot an entry from the menu
42457c478bd9Sstevel@tonic-gate      interface.  */
42467c478bd9Sstevel@tonic-gate   if (! (flags & BUILTIN_SCRIPT))
42477c478bd9Sstevel@tonic-gate     {
42487c478bd9Sstevel@tonic-gate       errnum = ERR_UNRECOGNIZED;
42497c478bd9Sstevel@tonic-gate       return 1;
42507c478bd9Sstevel@tonic-gate     }
42517c478bd9Sstevel@tonic-gate 
42527c478bd9Sstevel@tonic-gate   /* Determine a saved entry number.  */
42537c478bd9Sstevel@tonic-gate   if (*arg)
42547c478bd9Sstevel@tonic-gate     {
42557c478bd9Sstevel@tonic-gate       if (grub_memcmp (arg, "fallback", sizeof ("fallback") - 1) == 0)
42567c478bd9Sstevel@tonic-gate 	{
42577c478bd9Sstevel@tonic-gate 	  int i;
42587c478bd9Sstevel@tonic-gate 	  int index = 0;
42597c478bd9Sstevel@tonic-gate 
42607c478bd9Sstevel@tonic-gate 	  for (i = 0; i < MAX_FALLBACK_ENTRIES; i++)
42617c478bd9Sstevel@tonic-gate 	    {
42627c478bd9Sstevel@tonic-gate 	      if (fallback_entries[i] < 0)
42637c478bd9Sstevel@tonic-gate 		break;
42647c478bd9Sstevel@tonic-gate 	      if (fallback_entries[i] == current_entryno)
42657c478bd9Sstevel@tonic-gate 		{
42667c478bd9Sstevel@tonic-gate 		  index = i + 1;
42677c478bd9Sstevel@tonic-gate 		  break;
42687c478bd9Sstevel@tonic-gate 		}
42697c478bd9Sstevel@tonic-gate 	    }
42707c478bd9Sstevel@tonic-gate 
42717c478bd9Sstevel@tonic-gate 	  if (index >= MAX_FALLBACK_ENTRIES || fallback_entries[index] < 0)
42727c478bd9Sstevel@tonic-gate 	    {
42737c478bd9Sstevel@tonic-gate 	      /* This is the last.  */
42747c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_ARGUMENT;
42757c478bd9Sstevel@tonic-gate 	      return 1;
42767c478bd9Sstevel@tonic-gate 	    }
42777c478bd9Sstevel@tonic-gate 
42787c478bd9Sstevel@tonic-gate 	  entryno = fallback_entries[index];
42797c478bd9Sstevel@tonic-gate 	}
42807c478bd9Sstevel@tonic-gate       else if (! safe_parse_maxint (&arg, &entryno))
42817c478bd9Sstevel@tonic-gate 	return 1;
42827c478bd9Sstevel@tonic-gate     }
42837c478bd9Sstevel@tonic-gate   else
42847c478bd9Sstevel@tonic-gate     entryno = current_entryno;
42857c478bd9Sstevel@tonic-gate 
42867c478bd9Sstevel@tonic-gate   /* Open the default file.  */
42877c478bd9Sstevel@tonic-gate   saved_drive = boot_drive;
42887c478bd9Sstevel@tonic-gate   saved_partition = install_partition;
42897c478bd9Sstevel@tonic-gate   if (grub_open (default_file))
42907c478bd9Sstevel@tonic-gate     {
42917c478bd9Sstevel@tonic-gate       int len;
42927c478bd9Sstevel@tonic-gate 
42937c478bd9Sstevel@tonic-gate       disk_read_hook = disk_read_savesect_func;
42947c478bd9Sstevel@tonic-gate       len = grub_read (buf, sizeof (buf));
42957c478bd9Sstevel@tonic-gate       disk_read_hook = 0;
42967c478bd9Sstevel@tonic-gate       grub_close ();
42977c478bd9Sstevel@tonic-gate 
42987c478bd9Sstevel@tonic-gate       if (len != sizeof (buf))
42997c478bd9Sstevel@tonic-gate 	{
43007c478bd9Sstevel@tonic-gate 	  /* This is too small. Do not modify the file manually, please!  */
43017c478bd9Sstevel@tonic-gate 	  errnum = ERR_READ;
43027c478bd9Sstevel@tonic-gate 	  goto fail;
43037c478bd9Sstevel@tonic-gate 	}
43047c478bd9Sstevel@tonic-gate 
43057c478bd9Sstevel@tonic-gate       if (sector_count > 2)
43067c478bd9Sstevel@tonic-gate 	{
43077c478bd9Sstevel@tonic-gate 	  /* Is this possible?! Too fragmented!  */
43087c478bd9Sstevel@tonic-gate 	  errnum = ERR_FSYS_CORRUPT;
43097c478bd9Sstevel@tonic-gate 	  goto fail;
43107c478bd9Sstevel@tonic-gate 	}
43117c478bd9Sstevel@tonic-gate 
43127c478bd9Sstevel@tonic-gate       /* Set up a string to be written.  */
43137c478bd9Sstevel@tonic-gate       grub_memset (buf, '\n', sizeof (buf));
43147c478bd9Sstevel@tonic-gate       grub_sprintf (buf, "%d", entryno);
43157c478bd9Sstevel@tonic-gate 
43167c478bd9Sstevel@tonic-gate       if (saved_lengths[0] < sizeof (buf))
43177c478bd9Sstevel@tonic-gate 	{
43187c478bd9Sstevel@tonic-gate 	  /* The file is anchored to another file and the first few bytes
43197c478bd9Sstevel@tonic-gate 	     are spanned in two sectors. Uggh...  */
43207c478bd9Sstevel@tonic-gate 	  if (! rawread (current_drive, saved_sectors[0], 0, SECTOR_SIZE,
43217c478bd9Sstevel@tonic-gate 			 sect))
43227c478bd9Sstevel@tonic-gate 	    goto fail;
43237c478bd9Sstevel@tonic-gate 	  grub_memmove (sect + saved_offsets[0], buf, saved_lengths[0]);
43247c478bd9Sstevel@tonic-gate 	  if (! rawwrite (current_drive, saved_sectors[0], sect))
43257c478bd9Sstevel@tonic-gate 	    goto fail;
43267c478bd9Sstevel@tonic-gate 
43277c478bd9Sstevel@tonic-gate 	  if (! rawread (current_drive, saved_sectors[1], 0, SECTOR_SIZE,
43287c478bd9Sstevel@tonic-gate 			 sect))
43297c478bd9Sstevel@tonic-gate 	    goto fail;
43307c478bd9Sstevel@tonic-gate 	  grub_memmove (sect + saved_offsets[1],
43317c478bd9Sstevel@tonic-gate 			buf + saved_lengths[0],
43327c478bd9Sstevel@tonic-gate 			sizeof (buf) - saved_lengths[0]);
43337c478bd9Sstevel@tonic-gate 	  if (! rawwrite (current_drive, saved_sectors[1], sect))
43347c478bd9Sstevel@tonic-gate 	    goto fail;
43357c478bd9Sstevel@tonic-gate 	}
43367c478bd9Sstevel@tonic-gate       else
43377c478bd9Sstevel@tonic-gate 	{
43387c478bd9Sstevel@tonic-gate 	  /* This is a simple case. It fits into a single sector.  */
43397c478bd9Sstevel@tonic-gate 	  if (! rawread (current_drive, saved_sectors[0], 0, SECTOR_SIZE,
43407c478bd9Sstevel@tonic-gate 			 sect))
43417c478bd9Sstevel@tonic-gate 	    goto fail;
43427c478bd9Sstevel@tonic-gate 	  grub_memmove (sect + saved_offsets[0], buf, sizeof (buf));
43437c478bd9Sstevel@tonic-gate 	  if (! rawwrite (current_drive, saved_sectors[0], sect))
43447c478bd9Sstevel@tonic-gate 	    goto fail;
43457c478bd9Sstevel@tonic-gate 	}
43467c478bd9Sstevel@tonic-gate 
43477c478bd9Sstevel@tonic-gate       /* Clear the cache.  */
4348342440ecSPrasad Singamsetty       buf_track = BUF_CACHE_INVALID;
43497c478bd9Sstevel@tonic-gate     }
43507c478bd9Sstevel@tonic-gate 
43517c478bd9Sstevel@tonic-gate  fail:
43527c478bd9Sstevel@tonic-gate   saved_drive = tmp_drive;
43537c478bd9Sstevel@tonic-gate   saved_partition = tmp_partition;
43547c478bd9Sstevel@tonic-gate   return errnum;
43557c478bd9Sstevel@tonic-gate #else /* ! SUPPORT_DISKLESS && ! GRUB_UTIL */
43567c478bd9Sstevel@tonic-gate   errnum = ERR_UNRECOGNIZED;
43577c478bd9Sstevel@tonic-gate   return 1;
43587c478bd9Sstevel@tonic-gate #endif /* ! SUPPORT_DISKLESS && ! GRUB_UTIL */
43597c478bd9Sstevel@tonic-gate }
43607c478bd9Sstevel@tonic-gate 
43617c478bd9Sstevel@tonic-gate static struct builtin builtin_savedefault =
43627c478bd9Sstevel@tonic-gate {
43637c478bd9Sstevel@tonic-gate   "savedefault",
43647c478bd9Sstevel@tonic-gate   savedefault_func,
43657c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
43667c478bd9Sstevel@tonic-gate   "savedefault [NUM | `fallback']",
43677c478bd9Sstevel@tonic-gate   "Save the current entry as the default boot entry if no argument is"
43687c478bd9Sstevel@tonic-gate   " specified. If a number is specified, this number is saved. If"
43697c478bd9Sstevel@tonic-gate   " `fallback' is used, next fallback entry is saved."
43707c478bd9Sstevel@tonic-gate };
43717c478bd9Sstevel@tonic-gate 
43727c478bd9Sstevel@tonic-gate 
43737c478bd9Sstevel@tonic-gate #ifdef SUPPORT_SERIAL
43747c478bd9Sstevel@tonic-gate /* serial */
43757c478bd9Sstevel@tonic-gate static int
43767c478bd9Sstevel@tonic-gate serial_func (char *arg, int flags)
43777c478bd9Sstevel@tonic-gate {
43787c478bd9Sstevel@tonic-gate   unsigned short port = serial_hw_get_port (0);
43797c478bd9Sstevel@tonic-gate   unsigned int speed = 9600;
43807c478bd9Sstevel@tonic-gate   int word_len = UART_8BITS_WORD;
43817c478bd9Sstevel@tonic-gate   int parity = UART_NO_PARITY;
43827c478bd9Sstevel@tonic-gate   int stop_bit_len = UART_1_STOP_BIT;
43837c478bd9Sstevel@tonic-gate 
43847c478bd9Sstevel@tonic-gate   /* Process GNU-style long options.
43857c478bd9Sstevel@tonic-gate      FIXME: We should implement a getopt-like function, to avoid
43867c478bd9Sstevel@tonic-gate      duplications.  */
43877c478bd9Sstevel@tonic-gate   while (1)
43887c478bd9Sstevel@tonic-gate     {
43897c478bd9Sstevel@tonic-gate       if (grub_memcmp (arg, "--unit=", sizeof ("--unit=") - 1) == 0)
43907c478bd9Sstevel@tonic-gate 	{
43917c478bd9Sstevel@tonic-gate 	  char *p = arg + sizeof ("--unit=") - 1;
43927c478bd9Sstevel@tonic-gate 	  int unit;
43937c478bd9Sstevel@tonic-gate 
43947c478bd9Sstevel@tonic-gate 	  if (! safe_parse_maxint (&p, &unit))
43957c478bd9Sstevel@tonic-gate 	    return 1;
43967c478bd9Sstevel@tonic-gate 
43977c478bd9Sstevel@tonic-gate 	  if (unit < 0 || unit > 3)
43987c478bd9Sstevel@tonic-gate 	    {
43997c478bd9Sstevel@tonic-gate 	      errnum = ERR_DEV_VALUES;
44007c478bd9Sstevel@tonic-gate 	      return 1;
44017c478bd9Sstevel@tonic-gate 	    }
44027c478bd9Sstevel@tonic-gate 
44037c478bd9Sstevel@tonic-gate 	  port = serial_hw_get_port (unit);
44047c478bd9Sstevel@tonic-gate 	}
44057c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--speed=", sizeof ("--speed=") - 1) == 0)
44067c478bd9Sstevel@tonic-gate 	{
44077c478bd9Sstevel@tonic-gate 	  char *p = arg + sizeof ("--speed=") - 1;
44087c478bd9Sstevel@tonic-gate 	  int num;
44097c478bd9Sstevel@tonic-gate 
44107c478bd9Sstevel@tonic-gate 	  if (! safe_parse_maxint (&p, &num))
44117c478bd9Sstevel@tonic-gate 	    return 1;
44127c478bd9Sstevel@tonic-gate 
44137c478bd9Sstevel@tonic-gate 	  speed = (unsigned int) num;
44147c478bd9Sstevel@tonic-gate 	}
44157c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--port=", sizeof ("--port=") - 1) == 0)
44167c478bd9Sstevel@tonic-gate 	{
44177c478bd9Sstevel@tonic-gate 	  char *p = arg + sizeof ("--port=") - 1;
44187c478bd9Sstevel@tonic-gate 	  int num;
44197c478bd9Sstevel@tonic-gate 
44207c478bd9Sstevel@tonic-gate 	  if (! safe_parse_maxint (&p, &num))
44217c478bd9Sstevel@tonic-gate 	    return 1;
44227c478bd9Sstevel@tonic-gate 
44237c478bd9Sstevel@tonic-gate 	  port = (unsigned short) num;
44247c478bd9Sstevel@tonic-gate 	}
44257c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--word=", sizeof ("--word=") - 1) == 0)
44267c478bd9Sstevel@tonic-gate 	{
44277c478bd9Sstevel@tonic-gate 	  char *p = arg + sizeof ("--word=") - 1;
44287c478bd9Sstevel@tonic-gate 	  int len;
44297c478bd9Sstevel@tonic-gate 
44307c478bd9Sstevel@tonic-gate 	  if (! safe_parse_maxint (&p, &len))
44317c478bd9Sstevel@tonic-gate 	    return 1;
44327c478bd9Sstevel@tonic-gate 
44337c478bd9Sstevel@tonic-gate 	  switch (len)
44347c478bd9Sstevel@tonic-gate 	    {
44357c478bd9Sstevel@tonic-gate 	    case 5: word_len = UART_5BITS_WORD; break;
44367c478bd9Sstevel@tonic-gate 	    case 6: word_len = UART_6BITS_WORD; break;
44377c478bd9Sstevel@tonic-gate 	    case 7: word_len = UART_7BITS_WORD; break;
44387c478bd9Sstevel@tonic-gate 	    case 8: word_len = UART_8BITS_WORD; break;
44397c478bd9Sstevel@tonic-gate 	    default:
44407c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_ARGUMENT;
44417c478bd9Sstevel@tonic-gate 	      return 1;
44427c478bd9Sstevel@tonic-gate 	    }
44437c478bd9Sstevel@tonic-gate 	}
44447c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--stop=", sizeof ("--stop=") - 1) == 0)
44457c478bd9Sstevel@tonic-gate 	{
44467c478bd9Sstevel@tonic-gate 	  char *p = arg + sizeof ("--stop=") - 1;
44477c478bd9Sstevel@tonic-gate 	  int len;
44487c478bd9Sstevel@tonic-gate 
44497c478bd9Sstevel@tonic-gate 	  if (! safe_parse_maxint (&p, &len))
44507c478bd9Sstevel@tonic-gate 	    return 1;
44517c478bd9Sstevel@tonic-gate 
44527c478bd9Sstevel@tonic-gate 	  switch (len)
44537c478bd9Sstevel@tonic-gate 	    {
44547c478bd9Sstevel@tonic-gate 	    case 1: stop_bit_len = UART_1_STOP_BIT; break;
44557c478bd9Sstevel@tonic-gate 	    case 2: stop_bit_len = UART_2_STOP_BITS; break;
44567c478bd9Sstevel@tonic-gate 	    default:
44577c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_ARGUMENT;
44587c478bd9Sstevel@tonic-gate 	      return 1;
44597c478bd9Sstevel@tonic-gate 	    }
44607c478bd9Sstevel@tonic-gate 	}
44617c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--parity=", sizeof ("--parity=") - 1) == 0)
44627c478bd9Sstevel@tonic-gate 	{
44637c478bd9Sstevel@tonic-gate 	  char *p = arg + sizeof ("--parity=") - 1;
44647c478bd9Sstevel@tonic-gate 
44657c478bd9Sstevel@tonic-gate 	  if (grub_memcmp (p, "no", sizeof ("no") - 1) == 0)
44667c478bd9Sstevel@tonic-gate 	    parity = UART_NO_PARITY;
44677c478bd9Sstevel@tonic-gate 	  else if (grub_memcmp (p, "odd", sizeof ("odd") - 1) == 0)
44687c478bd9Sstevel@tonic-gate 	    parity = UART_ODD_PARITY;
44697c478bd9Sstevel@tonic-gate 	  else if (grub_memcmp (p, "even", sizeof ("even") - 1) == 0)
44707c478bd9Sstevel@tonic-gate 	    parity = UART_EVEN_PARITY;
44717c478bd9Sstevel@tonic-gate 	  else
44727c478bd9Sstevel@tonic-gate 	    {
44737c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_ARGUMENT;
44747c478bd9Sstevel@tonic-gate 	      return 1;
44757c478bd9Sstevel@tonic-gate 	    }
44767c478bd9Sstevel@tonic-gate 	}
44777c478bd9Sstevel@tonic-gate # ifdef GRUB_UTIL
44787c478bd9Sstevel@tonic-gate       /* In the grub shell, don't use any port number but open a tty
44797c478bd9Sstevel@tonic-gate 	 device instead.  */
44807c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--device=", sizeof ("--device=") - 1) == 0)
44817c478bd9Sstevel@tonic-gate 	{
44827c478bd9Sstevel@tonic-gate 	  char *p = arg + sizeof ("--device=") - 1;
44837c478bd9Sstevel@tonic-gate 	  char dev[256];	/* XXX */
44847c478bd9Sstevel@tonic-gate 	  char *q = dev;
44857c478bd9Sstevel@tonic-gate 
44867c478bd9Sstevel@tonic-gate 	  while (*p && ! grub_isspace (*p))
44877c478bd9Sstevel@tonic-gate 	    *q++ = *p++;
44887c478bd9Sstevel@tonic-gate 
44897c478bd9Sstevel@tonic-gate 	  *q = 0;
44907c478bd9Sstevel@tonic-gate 	  serial_set_device (dev);
44917c478bd9Sstevel@tonic-gate 	}
44927c478bd9Sstevel@tonic-gate # endif /* GRUB_UTIL */
44937c478bd9Sstevel@tonic-gate       else
44947c478bd9Sstevel@tonic-gate 	break;
44957c478bd9Sstevel@tonic-gate 
44967c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
44977c478bd9Sstevel@tonic-gate     }
44987c478bd9Sstevel@tonic-gate 
44997c478bd9Sstevel@tonic-gate   /* Initialize the serial unit.  */
45007c478bd9Sstevel@tonic-gate   if (! serial_hw_init (port, speed, word_len, parity, stop_bit_len))
45017c478bd9Sstevel@tonic-gate     {
45027c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
45037c478bd9Sstevel@tonic-gate       return 1;
45047c478bd9Sstevel@tonic-gate     }
45057c478bd9Sstevel@tonic-gate 
45067c478bd9Sstevel@tonic-gate   return 0;
45077c478bd9Sstevel@tonic-gate }
45087c478bd9Sstevel@tonic-gate 
45097c478bd9Sstevel@tonic-gate static struct builtin builtin_serial =
45107c478bd9Sstevel@tonic-gate {
45117c478bd9Sstevel@tonic-gate   "serial",
45127c478bd9Sstevel@tonic-gate   serial_func,
45137c478bd9Sstevel@tonic-gate   BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
45147c478bd9Sstevel@tonic-gate   "serial [--unit=UNIT] [--port=PORT] [--speed=SPEED] [--word=WORD] [--parity=PARITY] [--stop=STOP] [--device=DEV]",
45157c478bd9Sstevel@tonic-gate   "Initialize a serial device. UNIT is a digit that specifies which serial"
45167c478bd9Sstevel@tonic-gate   " device is used (e.g. 0 == COM1). If you need to specify the port number,"
45177c478bd9Sstevel@tonic-gate   " set it by --port. SPEED is the DTE-DTE speed. WORD is the word length,"
45187c478bd9Sstevel@tonic-gate   " PARITY is the type of parity, which is one of `no', `odd' and `even'."
45197c478bd9Sstevel@tonic-gate   " STOP is the length of stop bit(s). The option --device can be used only"
45207c478bd9Sstevel@tonic-gate   " in the grub shell, which specifies the file name of a tty device. The"
45217c478bd9Sstevel@tonic-gate   " default values are COM1, 9600, 8N1."
45227c478bd9Sstevel@tonic-gate };
45237c478bd9Sstevel@tonic-gate #endif /* SUPPORT_SERIAL */
45247c478bd9Sstevel@tonic-gate 
45257c478bd9Sstevel@tonic-gate 
45267c478bd9Sstevel@tonic-gate /* setkey */
45277c478bd9Sstevel@tonic-gate struct keysym
45287c478bd9Sstevel@tonic-gate {
45297c478bd9Sstevel@tonic-gate   char *unshifted_name;			/* the name in unshifted state */
45307c478bd9Sstevel@tonic-gate   char *shifted_name;			/* the name in shifted state */
45317c478bd9Sstevel@tonic-gate   unsigned char unshifted_ascii;	/* the ascii code in unshifted state */
45327c478bd9Sstevel@tonic-gate   unsigned char shifted_ascii;		/* the ascii code in shifted state */
45337c478bd9Sstevel@tonic-gate   unsigned char keycode;		/* keyboard scancode */
45347c478bd9Sstevel@tonic-gate };
45357c478bd9Sstevel@tonic-gate 
45367c478bd9Sstevel@tonic-gate /* The table for key symbols. If the "shifted" member of an entry is
45377c478bd9Sstevel@tonic-gate    NULL, the entry does not have shifted state.  */
45387c478bd9Sstevel@tonic-gate static struct keysym keysym_table[] =
45397c478bd9Sstevel@tonic-gate {
45407c478bd9Sstevel@tonic-gate   {"escape",		0,		0x1b,	0,	0x01},
45417c478bd9Sstevel@tonic-gate   {"1",			"exclam",	'1',	'!',	0x02},
45427c478bd9Sstevel@tonic-gate   {"2",			"at",		'2',	'@',	0x03},
45437c478bd9Sstevel@tonic-gate   {"3",			"numbersign",	'3',	'#',	0x04},
45447c478bd9Sstevel@tonic-gate   {"4",			"dollar",	'4',	'$',	0x05},
45457c478bd9Sstevel@tonic-gate   {"5",			"percent",	'5',	'%',	0x06},
45467c478bd9Sstevel@tonic-gate   {"6",			"caret",	'6',	'^',	0x07},
45477c478bd9Sstevel@tonic-gate   {"7",			"ampersand",	'7',	'&',	0x08},
45487c478bd9Sstevel@tonic-gate   {"8",			"asterisk",	'8',	'*',	0x09},
45497c478bd9Sstevel@tonic-gate   {"9",			"parenleft",	'9',	'(',	0x0a},
45507c478bd9Sstevel@tonic-gate   {"0",			"parenright",	'0',	')',	0x0b},
45517c478bd9Sstevel@tonic-gate   {"minus",		"underscore",	'-',	'_',	0x0c},
45527c478bd9Sstevel@tonic-gate   {"equal",		"plus",		'=',	'+',	0x0d},
45537c478bd9Sstevel@tonic-gate   {"backspace",		0,		'\b',	0,	0x0e},
45547c478bd9Sstevel@tonic-gate   {"tab",		0,		'\t',	0,	0x0f},
45557c478bd9Sstevel@tonic-gate   {"q",			"Q",		'q',	'Q',	0x10},
45567c478bd9Sstevel@tonic-gate   {"w",			"W",		'w',	'W',	0x11},
45577c478bd9Sstevel@tonic-gate   {"e",			"E",		'e',	'E',	0x12},
45587c478bd9Sstevel@tonic-gate   {"r",			"R",		'r',	'R',	0x13},
45597c478bd9Sstevel@tonic-gate   {"t",			"T",		't',	'T',	0x14},
45607c478bd9Sstevel@tonic-gate   {"y",			"Y",		'y',	'Y',	0x15},
45617c478bd9Sstevel@tonic-gate   {"u",			"U",		'u',	'U',	0x16},
45627c478bd9Sstevel@tonic-gate   {"i",			"I",		'i',	'I',	0x17},
45637c478bd9Sstevel@tonic-gate   {"o",			"O",		'o',	'O',	0x18},
45647c478bd9Sstevel@tonic-gate   {"p",			"P",		'p',	'P',	0x19},
45657c478bd9Sstevel@tonic-gate   {"bracketleft",	"braceleft",	'[',	'{',	0x1a},
45667c478bd9Sstevel@tonic-gate   {"bracketright",	"braceright",	']',	'}',	0x1b},
45677c478bd9Sstevel@tonic-gate   {"enter",		0,		'\n',	0,	0x1c},
45687c478bd9Sstevel@tonic-gate   {"control",		0,		0,	0,	0x1d},
45697c478bd9Sstevel@tonic-gate   {"a",			"A",		'a',	'A',	0x1e},
45707c478bd9Sstevel@tonic-gate   {"s",			"S",		's',	'S',	0x1f},
45717c478bd9Sstevel@tonic-gate   {"d",			"D",		'd',	'D',	0x20},
45727c478bd9Sstevel@tonic-gate   {"f",			"F",		'f',	'F',	0x21},
45737c478bd9Sstevel@tonic-gate   {"g",			"G",		'g',	'G',	0x22},
45747c478bd9Sstevel@tonic-gate   {"h",			"H",		'h',	'H',	0x23},
45757c478bd9Sstevel@tonic-gate   {"j",			"J",		'j',	'J',	0x24},
45767c478bd9Sstevel@tonic-gate   {"k",			"K",		'k',	'K',	0x25},
45777c478bd9Sstevel@tonic-gate   {"l",			"L",		'l',	'L',	0x26},
45787c478bd9Sstevel@tonic-gate   {"semicolon",		"colon",	';',	':',	0x27},
45797c478bd9Sstevel@tonic-gate   {"quote",		"doublequote",	'\'',	'"',	0x28},
45807c478bd9Sstevel@tonic-gate   {"backquote",		"tilde",	'`',	'~',	0x29},
45817c478bd9Sstevel@tonic-gate   {"shift",		0,		0,	0,	0x2a},
45827c478bd9Sstevel@tonic-gate   {"backslash",		"bar",		'\\',	'|',	0x2b},
45837c478bd9Sstevel@tonic-gate   {"z",			"Z",		'z',	'Z',	0x2c},
45847c478bd9Sstevel@tonic-gate   {"x",			"X",		'x',	'X',	0x2d},
45857c478bd9Sstevel@tonic-gate   {"c",			"C",		'c',	'C',	0x2e},
45867c478bd9Sstevel@tonic-gate   {"v",			"V",		'v',	'V',	0x2f},
45877c478bd9Sstevel@tonic-gate   {"b",			"B",		'b',	'B',	0x30},
45887c478bd9Sstevel@tonic-gate   {"n",			"N",		'n',	'N',	0x31},
45897c478bd9Sstevel@tonic-gate   {"m",			"M",		'm',	'M',	0x32},
45907c478bd9Sstevel@tonic-gate   {"comma",		"less",		',',	'<',	0x33},
45917c478bd9Sstevel@tonic-gate   {"period",		"greater",	'.',	'>',	0x34},
45927c478bd9Sstevel@tonic-gate   {"slash",		"question",	'/',	'?',	0x35},
45937c478bd9Sstevel@tonic-gate   {"alt",		0,		0,	0,	0x38},
45947c478bd9Sstevel@tonic-gate   {"space",		0,		' ',	0,	0x39},
45957c478bd9Sstevel@tonic-gate   {"capslock",		0,		0,	0,	0x3a},
45967c478bd9Sstevel@tonic-gate   {"F1",		0,		0,	0,	0x3b},
45977c478bd9Sstevel@tonic-gate   {"F2",		0,		0,	0,	0x3c},
45987c478bd9Sstevel@tonic-gate   {"F3",		0,		0,	0,	0x3d},
45997c478bd9Sstevel@tonic-gate   {"F4",		0,		0,	0,	0x3e},
46007c478bd9Sstevel@tonic-gate   {"F5",		0,		0,	0,	0x3f},
46017c478bd9Sstevel@tonic-gate   {"F6",		0,		0,	0,	0x40},
46027c478bd9Sstevel@tonic-gate   {"F7",		0,		0,	0,	0x41},
46037c478bd9Sstevel@tonic-gate   {"F8",		0,		0,	0,	0x42},
46047c478bd9Sstevel@tonic-gate   {"F9",		0,		0,	0,	0x43},
46057c478bd9Sstevel@tonic-gate   {"F10",		0,		0,	0,	0x44},
46067c478bd9Sstevel@tonic-gate   /* Caution: do not add NumLock here! we cannot deal with it properly.  */
46077c478bd9Sstevel@tonic-gate   {"delete",		0,		0x7f,	0,	0x53}
46087c478bd9Sstevel@tonic-gate };
46097c478bd9Sstevel@tonic-gate 
46107c478bd9Sstevel@tonic-gate static int
46117c478bd9Sstevel@tonic-gate setkey_func (char *arg, int flags)
46127c478bd9Sstevel@tonic-gate {
46137c478bd9Sstevel@tonic-gate   char *to_key, *from_key;
46147c478bd9Sstevel@tonic-gate   int to_code, from_code;
46157c478bd9Sstevel@tonic-gate   int map_in_interrupt = 0;
46167c478bd9Sstevel@tonic-gate 
46171b8adde7SWilliam Kucharski   auto int find_key_code (char *key);
46181b8adde7SWilliam Kucharski   auto int find_ascii_code (char *key);
46191b8adde7SWilliam Kucharski 
46201b8adde7SWilliam Kucharski   auto int find_key_code (char *key)
46217c478bd9Sstevel@tonic-gate     {
46227c478bd9Sstevel@tonic-gate       int i;
46237c478bd9Sstevel@tonic-gate 
46247c478bd9Sstevel@tonic-gate       for (i = 0; i < sizeof (keysym_table) / sizeof (keysym_table[0]); i++)
46257c478bd9Sstevel@tonic-gate 	{
46267c478bd9Sstevel@tonic-gate 	  if (keysym_table[i].unshifted_name &&
46277c478bd9Sstevel@tonic-gate 	      grub_strcmp (key, keysym_table[i].unshifted_name) == 0)
46287c478bd9Sstevel@tonic-gate 	    return keysym_table[i].keycode;
46297c478bd9Sstevel@tonic-gate 	  else if (keysym_table[i].shifted_name &&
46307c478bd9Sstevel@tonic-gate 		   grub_strcmp (key, keysym_table[i].shifted_name) == 0)
46317c478bd9Sstevel@tonic-gate 	    return keysym_table[i].keycode;
46327c478bd9Sstevel@tonic-gate 	}
46337c478bd9Sstevel@tonic-gate 
46347c478bd9Sstevel@tonic-gate       return 0;
46357c478bd9Sstevel@tonic-gate     }
46367c478bd9Sstevel@tonic-gate 
46371b8adde7SWilliam Kucharski   auto int find_ascii_code (char *key)
46387c478bd9Sstevel@tonic-gate     {
46397c478bd9Sstevel@tonic-gate       int i;
46407c478bd9Sstevel@tonic-gate 
46417c478bd9Sstevel@tonic-gate       for (i = 0; i < sizeof (keysym_table) / sizeof (keysym_table[0]); i++)
46427c478bd9Sstevel@tonic-gate 	{
46437c478bd9Sstevel@tonic-gate 	  if (keysym_table[i].unshifted_name &&
46447c478bd9Sstevel@tonic-gate 	      grub_strcmp (key, keysym_table[i].unshifted_name) == 0)
46457c478bd9Sstevel@tonic-gate 	    return keysym_table[i].unshifted_ascii;
46467c478bd9Sstevel@tonic-gate 	  else if (keysym_table[i].shifted_name &&
46477c478bd9Sstevel@tonic-gate 		   grub_strcmp (key, keysym_table[i].shifted_name) == 0)
46487c478bd9Sstevel@tonic-gate 	    return keysym_table[i].shifted_ascii;
46497c478bd9Sstevel@tonic-gate 	}
46507c478bd9Sstevel@tonic-gate 
46517c478bd9Sstevel@tonic-gate       return 0;
46527c478bd9Sstevel@tonic-gate     }
46537c478bd9Sstevel@tonic-gate 
46547c478bd9Sstevel@tonic-gate   to_key = arg;
46557c478bd9Sstevel@tonic-gate   from_key = skip_to (0, to_key);
46567c478bd9Sstevel@tonic-gate 
46577c478bd9Sstevel@tonic-gate   if (! *to_key)
46587c478bd9Sstevel@tonic-gate     {
46597c478bd9Sstevel@tonic-gate       /* If the user specifies no argument, reset the key mappings.  */
46607c478bd9Sstevel@tonic-gate       grub_memset (bios_key_map, 0, KEY_MAP_SIZE * sizeof (unsigned short));
46617c478bd9Sstevel@tonic-gate       grub_memset (ascii_key_map, 0, KEY_MAP_SIZE * sizeof (unsigned short));
46627c478bd9Sstevel@tonic-gate 
46637c478bd9Sstevel@tonic-gate       return 0;
46647c478bd9Sstevel@tonic-gate     }
46657c478bd9Sstevel@tonic-gate   else if (! *from_key)
46667c478bd9Sstevel@tonic-gate     {
46677c478bd9Sstevel@tonic-gate       /* The user must specify two arguments or zero argument.  */
46687c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
46697c478bd9Sstevel@tonic-gate       return 1;
46707c478bd9Sstevel@tonic-gate     }
46717c478bd9Sstevel@tonic-gate 
46727c478bd9Sstevel@tonic-gate   nul_terminate (to_key);
46737c478bd9Sstevel@tonic-gate   nul_terminate (from_key);
46747c478bd9Sstevel@tonic-gate 
46757c478bd9Sstevel@tonic-gate   to_code = find_ascii_code (to_key);
46767c478bd9Sstevel@tonic-gate   from_code = find_ascii_code (from_key);
46777c478bd9Sstevel@tonic-gate   if (! to_code || ! from_code)
46787c478bd9Sstevel@tonic-gate     {
46797c478bd9Sstevel@tonic-gate       map_in_interrupt = 1;
46807c478bd9Sstevel@tonic-gate       to_code = find_key_code (to_key);
46817c478bd9Sstevel@tonic-gate       from_code = find_key_code (from_key);
46827c478bd9Sstevel@tonic-gate       if (! to_code || ! from_code)
46837c478bd9Sstevel@tonic-gate 	{
46847c478bd9Sstevel@tonic-gate 	  errnum = ERR_BAD_ARGUMENT;
46857c478bd9Sstevel@tonic-gate 	  return 1;
46867c478bd9Sstevel@tonic-gate 	}
46877c478bd9Sstevel@tonic-gate     }
46887c478bd9Sstevel@tonic-gate 
46897c478bd9Sstevel@tonic-gate   if (map_in_interrupt)
46907c478bd9Sstevel@tonic-gate     {
46917c478bd9Sstevel@tonic-gate       int i;
46927c478bd9Sstevel@tonic-gate 
46937c478bd9Sstevel@tonic-gate       /* Find an empty slot.  */
46947c478bd9Sstevel@tonic-gate       for (i = 0; i < KEY_MAP_SIZE; i++)
46957c478bd9Sstevel@tonic-gate 	{
46967c478bd9Sstevel@tonic-gate 	  if ((bios_key_map[i] & 0xff) == from_code)
46977c478bd9Sstevel@tonic-gate 	    /* Perhaps the user wants to overwrite the map.  */
46987c478bd9Sstevel@tonic-gate 	    break;
46997c478bd9Sstevel@tonic-gate 
47007c478bd9Sstevel@tonic-gate 	  if (! bios_key_map[i])
47017c478bd9Sstevel@tonic-gate 	    break;
47027c478bd9Sstevel@tonic-gate 	}
47037c478bd9Sstevel@tonic-gate 
47047c478bd9Sstevel@tonic-gate       if (i == KEY_MAP_SIZE)
47057c478bd9Sstevel@tonic-gate 	{
47067c478bd9Sstevel@tonic-gate 	  errnum = ERR_WONT_FIT;
47077c478bd9Sstevel@tonic-gate 	  return 1;
47087c478bd9Sstevel@tonic-gate 	}
47097c478bd9Sstevel@tonic-gate 
47107c478bd9Sstevel@tonic-gate       if (to_code == from_code)
47117c478bd9Sstevel@tonic-gate 	/* If TO is equal to FROM, delete the entry.  */
47127c478bd9Sstevel@tonic-gate 	grub_memmove ((char *) &bios_key_map[i],
47137c478bd9Sstevel@tonic-gate 		      (char *) &bios_key_map[i + 1],
47147c478bd9Sstevel@tonic-gate 		      sizeof (unsigned short) * (KEY_MAP_SIZE - i));
47157c478bd9Sstevel@tonic-gate       else
47167c478bd9Sstevel@tonic-gate 	bios_key_map[i] = (to_code << 8) | from_code;
47177c478bd9Sstevel@tonic-gate 
47187c478bd9Sstevel@tonic-gate       /* Ugly but should work.  */
47197c478bd9Sstevel@tonic-gate       unset_int15_handler ();
47207c478bd9Sstevel@tonic-gate       set_int15_handler ();
47217c478bd9Sstevel@tonic-gate     }
47227c478bd9Sstevel@tonic-gate   else
47237c478bd9Sstevel@tonic-gate     {
47247c478bd9Sstevel@tonic-gate       int i;
47257c478bd9Sstevel@tonic-gate 
47267c478bd9Sstevel@tonic-gate       /* Find an empty slot.  */
47277c478bd9Sstevel@tonic-gate       for (i = 0; i < KEY_MAP_SIZE; i++)
47287c478bd9Sstevel@tonic-gate 	{
47297c478bd9Sstevel@tonic-gate 	  if ((ascii_key_map[i] & 0xff) == from_code)
47307c478bd9Sstevel@tonic-gate 	    /* Perhaps the user wants to overwrite the map.  */
47317c478bd9Sstevel@tonic-gate 	    break;
47327c478bd9Sstevel@tonic-gate 
47337c478bd9Sstevel@tonic-gate 	  if (! ascii_key_map[i])
47347c478bd9Sstevel@tonic-gate 	    break;
47357c478bd9Sstevel@tonic-gate 	}
47367c478bd9Sstevel@tonic-gate 
47377c478bd9Sstevel@tonic-gate       if (i == KEY_MAP_SIZE)
47387c478bd9Sstevel@tonic-gate 	{
47397c478bd9Sstevel@tonic-gate 	  errnum = ERR_WONT_FIT;
47407c478bd9Sstevel@tonic-gate 	  return 1;
47417c478bd9Sstevel@tonic-gate 	}
47427c478bd9Sstevel@tonic-gate 
47437c478bd9Sstevel@tonic-gate       if (to_code == from_code)
47447c478bd9Sstevel@tonic-gate 	/* If TO is equal to FROM, delete the entry.  */
47457c478bd9Sstevel@tonic-gate 	grub_memmove ((char *) &ascii_key_map[i],
47467c478bd9Sstevel@tonic-gate 		      (char *) &ascii_key_map[i + 1],
47477c478bd9Sstevel@tonic-gate 		      sizeof (unsigned short) * (KEY_MAP_SIZE - i));
47487c478bd9Sstevel@tonic-gate       else
47497c478bd9Sstevel@tonic-gate 	ascii_key_map[i] = (to_code << 8) | from_code;
47507c478bd9Sstevel@tonic-gate     }
47517c478bd9Sstevel@tonic-gate 
47527c478bd9Sstevel@tonic-gate   return 0;
47537c478bd9Sstevel@tonic-gate }
47547c478bd9Sstevel@tonic-gate 
47557c478bd9Sstevel@tonic-gate static struct builtin builtin_setkey =
47567c478bd9Sstevel@tonic-gate {
47577c478bd9Sstevel@tonic-gate   "setkey",
47587c478bd9Sstevel@tonic-gate   setkey_func,
47597c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
47607c478bd9Sstevel@tonic-gate   "setkey [TO_KEY FROM_KEY]",
47617c478bd9Sstevel@tonic-gate   "Change the keyboard map. The key FROM_KEY is mapped to the key TO_KEY."
47627c478bd9Sstevel@tonic-gate   " A key must be an alphabet, a digit, or one of these: escape, exclam,"
47637c478bd9Sstevel@tonic-gate   " at, numbersign, dollar, percent, caret, ampersand, asterisk, parenleft,"
47647c478bd9Sstevel@tonic-gate   " parenright, minus, underscore, equal, plus, backspace, tab, bracketleft,"
47657c478bd9Sstevel@tonic-gate   " braceleft, bracketright, braceright, enter, control, semicolon, colon,"
47667c478bd9Sstevel@tonic-gate   " quote, doublequote, backquote, tilde, shift, backslash, bar, comma,"
47677c478bd9Sstevel@tonic-gate   " less, period, greater, slash, question, alt, space, capslock, FX (X"
47687c478bd9Sstevel@tonic-gate   " is a digit), and delete. If no argument is specified, reset key"
47697c478bd9Sstevel@tonic-gate   " mappings."
47707c478bd9Sstevel@tonic-gate };
47717c478bd9Sstevel@tonic-gate 
47727c478bd9Sstevel@tonic-gate 
47737c478bd9Sstevel@tonic-gate /* setup */
47747c478bd9Sstevel@tonic-gate static int
47757c478bd9Sstevel@tonic-gate setup_func (char *arg, int flags)
47767c478bd9Sstevel@tonic-gate {
47777c478bd9Sstevel@tonic-gate   /* Point to the string of the installed drive/partition.  */
47787c478bd9Sstevel@tonic-gate   char *install_ptr;
47797c478bd9Sstevel@tonic-gate   /* Point to the string of the drive/parition where the GRUB images
47807c478bd9Sstevel@tonic-gate      reside.  */
47817c478bd9Sstevel@tonic-gate   char *image_ptr;
47827c478bd9Sstevel@tonic-gate   unsigned long installed_drive, installed_partition;
47837c478bd9Sstevel@tonic-gate   unsigned long image_drive, image_partition;
47847c478bd9Sstevel@tonic-gate   unsigned long tmp_drive, tmp_partition;
47857c478bd9Sstevel@tonic-gate   char stage1[64];
47867c478bd9Sstevel@tonic-gate   char stage2[64];
47877c478bd9Sstevel@tonic-gate   char config_filename[64];
47887c478bd9Sstevel@tonic-gate   char real_config_filename[64];
47897c478bd9Sstevel@tonic-gate   char cmd_arg[256];
47907c478bd9Sstevel@tonic-gate   char device[16];
47917c478bd9Sstevel@tonic-gate   char *buffer = (char *) RAW_ADDR (0x100000);
47927c478bd9Sstevel@tonic-gate   int is_force_lba = 0;
47937c478bd9Sstevel@tonic-gate   char *stage2_arg = 0;
47947c478bd9Sstevel@tonic-gate   char *prefix = 0;
47957c478bd9Sstevel@tonic-gate 
47967c478bd9Sstevel@tonic-gate   auto int check_file (char *file);
47977c478bd9Sstevel@tonic-gate   auto void sprint_device (int drive, int partition);
47987c478bd9Sstevel@tonic-gate   auto int embed_stage1_5 (char * stage1_5, int drive, int partition);
47997c478bd9Sstevel@tonic-gate 
48007c478bd9Sstevel@tonic-gate   /* Check if the file FILE exists like Autoconf.  */
48017c478bd9Sstevel@tonic-gate   int check_file (char *file)
48027c478bd9Sstevel@tonic-gate     {
48037c478bd9Sstevel@tonic-gate       int ret;
48047c478bd9Sstevel@tonic-gate 
48057c478bd9Sstevel@tonic-gate       grub_printf (" Checking if \"%s\" exists... ", file);
48067c478bd9Sstevel@tonic-gate       ret = grub_open (file);
48077c478bd9Sstevel@tonic-gate       if (ret)
48087c478bd9Sstevel@tonic-gate 	{
48097c478bd9Sstevel@tonic-gate 	  grub_close ();
48107c478bd9Sstevel@tonic-gate 	  grub_printf ("yes\n");
48117c478bd9Sstevel@tonic-gate 	}
48127c478bd9Sstevel@tonic-gate       else
48137c478bd9Sstevel@tonic-gate 	grub_printf ("no\n");
48147c478bd9Sstevel@tonic-gate 
48157c478bd9Sstevel@tonic-gate       return ret;
48167c478bd9Sstevel@tonic-gate     }
48177c478bd9Sstevel@tonic-gate 
48187c478bd9Sstevel@tonic-gate   /* Construct a device name in DEVICE.  */
48197c478bd9Sstevel@tonic-gate   void sprint_device (int drive, int partition)
48207c478bd9Sstevel@tonic-gate     {
48217c478bd9Sstevel@tonic-gate       grub_sprintf (device, "(%cd%d",
48227c478bd9Sstevel@tonic-gate 		    (drive & 0x80) ? 'h' : 'f',
48237c478bd9Sstevel@tonic-gate 		    drive & ~0x80);
48247c478bd9Sstevel@tonic-gate       if ((partition & 0xFF0000) != 0xFF0000)
48257c478bd9Sstevel@tonic-gate 	{
48267c478bd9Sstevel@tonic-gate 	  char tmp[16];
48277c478bd9Sstevel@tonic-gate 	  grub_sprintf (tmp, ",%d", (partition >> 16) & 0xFF);
48287c478bd9Sstevel@tonic-gate 	  grub_strncat (device, tmp, 256);
48297c478bd9Sstevel@tonic-gate 	}
48307c478bd9Sstevel@tonic-gate       if ((partition & 0x00FF00) != 0x00FF00)
48317c478bd9Sstevel@tonic-gate 	{
48327c478bd9Sstevel@tonic-gate 	  char tmp[16];
48337c478bd9Sstevel@tonic-gate 	  grub_sprintf (tmp, ",%c", 'a' + ((partition >> 8) & 0xFF));
48347c478bd9Sstevel@tonic-gate 	  grub_strncat (device, tmp, 256);
48357c478bd9Sstevel@tonic-gate 	}
48367c478bd9Sstevel@tonic-gate       grub_strncat (device, ")", 256);
48377c478bd9Sstevel@tonic-gate     }
48387c478bd9Sstevel@tonic-gate 
48397c478bd9Sstevel@tonic-gate   int embed_stage1_5 (char *stage1_5, int drive, int partition)
48407c478bd9Sstevel@tonic-gate     {
48417c478bd9Sstevel@tonic-gate       /* We install GRUB into the MBR, so try to embed the
48427c478bd9Sstevel@tonic-gate 	 Stage 1.5 in the sectors right after the MBR.  */
48437c478bd9Sstevel@tonic-gate       sprint_device (drive, partition);
48447c478bd9Sstevel@tonic-gate       grub_sprintf (cmd_arg, "%s %s", stage1_5, device);
48457c478bd9Sstevel@tonic-gate 
48467c478bd9Sstevel@tonic-gate       /* Notify what will be run.  */
48477c478bd9Sstevel@tonic-gate       grub_printf (" Running \"embed %s\"... ", cmd_arg);
48487c478bd9Sstevel@tonic-gate 
48497c478bd9Sstevel@tonic-gate       embed_func (cmd_arg, flags);
48507c478bd9Sstevel@tonic-gate       if (! errnum)
48517c478bd9Sstevel@tonic-gate 	{
48527c478bd9Sstevel@tonic-gate 	  /* Construct the blocklist representation.  */
48537c478bd9Sstevel@tonic-gate 	  grub_sprintf (buffer, "%s%s", device, embed_info);
48547c478bd9Sstevel@tonic-gate 	  grub_printf ("succeeded\n");
48557c478bd9Sstevel@tonic-gate 	  return 1;
48567c478bd9Sstevel@tonic-gate 	}
48577c478bd9Sstevel@tonic-gate       else
48587c478bd9Sstevel@tonic-gate 	{
48597c478bd9Sstevel@tonic-gate 	  grub_printf ("failed (this is not fatal)\n");
48607c478bd9Sstevel@tonic-gate 	  return 0;
48617c478bd9Sstevel@tonic-gate 	}
48627c478bd9Sstevel@tonic-gate     }
48637c478bd9Sstevel@tonic-gate 
48647c478bd9Sstevel@tonic-gate   struct stage1_5_map {
48657c478bd9Sstevel@tonic-gate     char *fsys;
48667c478bd9Sstevel@tonic-gate     char *name;
48677c478bd9Sstevel@tonic-gate   };
48687c478bd9Sstevel@tonic-gate   struct stage1_5_map stage1_5_map[] =
48697c478bd9Sstevel@tonic-gate   {
48707c478bd9Sstevel@tonic-gate     {"ext2fs",   "/e2fs_stage1_5"},
48717c478bd9Sstevel@tonic-gate     {"fat",      "/fat_stage1_5"},
48727c478bd9Sstevel@tonic-gate     {"ufs2",     "/ufs2_stage1_5"},
48737c478bd9Sstevel@tonic-gate     {"ffs",      "/ffs_stage1_5"},
48747c478bd9Sstevel@tonic-gate     {"iso9660",  "/iso9660_stage1_5"},
48757c478bd9Sstevel@tonic-gate     {"jfs",      "/jfs_stage1_5"},
48767c478bd9Sstevel@tonic-gate     {"minix",    "/minix_stage1_5"},
48777c478bd9Sstevel@tonic-gate     {"reiserfs", "/reiserfs_stage1_5"},
48787c478bd9Sstevel@tonic-gate     {"vstafs",   "/vstafs_stage1_5"},
48797c478bd9Sstevel@tonic-gate     {"xfs",      "/xfs_stage1_5"},
48807c478bd9Sstevel@tonic-gate     {"ufs",      "/ufs_stage1_5"}
48817c478bd9Sstevel@tonic-gate   };
48827c478bd9Sstevel@tonic-gate 
48837c478bd9Sstevel@tonic-gate   tmp_drive = saved_drive;
48847c478bd9Sstevel@tonic-gate   tmp_partition = saved_partition;
48857c478bd9Sstevel@tonic-gate 
48867c478bd9Sstevel@tonic-gate   /* Check if the user specifies --force-lba.  */
48877c478bd9Sstevel@tonic-gate   while (1)
48887c478bd9Sstevel@tonic-gate     {
48897c478bd9Sstevel@tonic-gate       if (grub_memcmp ("--force-lba", arg, sizeof ("--force-lba") - 1) == 0)
48907c478bd9Sstevel@tonic-gate 	{
48917c478bd9Sstevel@tonic-gate 	  is_force_lba = 1;
48927c478bd9Sstevel@tonic-gate 	  arg = skip_to (0, arg);
48937c478bd9Sstevel@tonic-gate 	}
48947c478bd9Sstevel@tonic-gate       else if (grub_memcmp ("--prefix=", arg, sizeof ("--prefix=") - 1) == 0)
48957c478bd9Sstevel@tonic-gate 	{
48967c478bd9Sstevel@tonic-gate 	  prefix = arg + sizeof ("--prefix=") - 1;
48977c478bd9Sstevel@tonic-gate 	  arg = skip_to (0, arg);
48987c478bd9Sstevel@tonic-gate 	  nul_terminate (prefix);
48997c478bd9Sstevel@tonic-gate 	}
49007c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
49017c478bd9Sstevel@tonic-gate       else if (grub_memcmp ("--stage2=", arg, sizeof ("--stage2=") - 1) == 0)
49027c478bd9Sstevel@tonic-gate 	{
49037c478bd9Sstevel@tonic-gate 	  stage2_arg = arg;
49047c478bd9Sstevel@tonic-gate 	  arg = skip_to (0, arg);
49057c478bd9Sstevel@tonic-gate 	  nul_terminate (stage2_arg);
49067c478bd9Sstevel@tonic-gate 	}
49077c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
49087c478bd9Sstevel@tonic-gate       else
49097c478bd9Sstevel@tonic-gate 	break;
49107c478bd9Sstevel@tonic-gate     }
49117c478bd9Sstevel@tonic-gate 
49127c478bd9Sstevel@tonic-gate   install_ptr = arg;
49137c478bd9Sstevel@tonic-gate   image_ptr = skip_to (0, install_ptr);
49147c478bd9Sstevel@tonic-gate 
49157c478bd9Sstevel@tonic-gate   /* Make sure that INSTALL_PTR is valid.  */
49167c478bd9Sstevel@tonic-gate   set_device (install_ptr);
49177c478bd9Sstevel@tonic-gate   if (errnum)
49187c478bd9Sstevel@tonic-gate     return 1;
49197c478bd9Sstevel@tonic-gate 
49207c478bd9Sstevel@tonic-gate   installed_drive = current_drive;
49217c478bd9Sstevel@tonic-gate   installed_partition = current_partition;
49227c478bd9Sstevel@tonic-gate 
49237c478bd9Sstevel@tonic-gate   /* Mount the drive pointed by IMAGE_PTR.  */
49247c478bd9Sstevel@tonic-gate   if (*image_ptr)
49257c478bd9Sstevel@tonic-gate     {
49267c478bd9Sstevel@tonic-gate       /* If the drive/partition where the images reside is specified,
49277c478bd9Sstevel@tonic-gate 	 get the drive and the partition.  */
49287c478bd9Sstevel@tonic-gate       set_device (image_ptr);
49297c478bd9Sstevel@tonic-gate       if (errnum)
49307c478bd9Sstevel@tonic-gate 	return 1;
49317c478bd9Sstevel@tonic-gate     }
49327c478bd9Sstevel@tonic-gate   else
49337c478bd9Sstevel@tonic-gate     {
49347c478bd9Sstevel@tonic-gate       /* If omitted, use SAVED_PARTITION and SAVED_DRIVE.  */
49357c478bd9Sstevel@tonic-gate       current_drive = saved_drive;
49367c478bd9Sstevel@tonic-gate       current_partition = saved_partition;
49377c478bd9Sstevel@tonic-gate     }
49387c478bd9Sstevel@tonic-gate 
49397c478bd9Sstevel@tonic-gate   image_drive = saved_drive = current_drive;
49407c478bd9Sstevel@tonic-gate   image_partition = saved_partition = current_partition;
49417c478bd9Sstevel@tonic-gate 
49427c478bd9Sstevel@tonic-gate   /* Open it.  */
49437c478bd9Sstevel@tonic-gate   if (! open_device ())
49447c478bd9Sstevel@tonic-gate     goto fail;
49457c478bd9Sstevel@tonic-gate 
49467c478bd9Sstevel@tonic-gate   /* Check if stage1 exists. If the user doesn't specify the option
49477c478bd9Sstevel@tonic-gate      `--prefix', attempt /boot/grub and /grub.  */
49487c478bd9Sstevel@tonic-gate   /* NOTE: It is dangerous to run this command without `--prefix' in the
49497c478bd9Sstevel@tonic-gate      grub shell, since that affects `--stage2'.  */
49507c478bd9Sstevel@tonic-gate   if (! prefix)
49517c478bd9Sstevel@tonic-gate     {
49527c478bd9Sstevel@tonic-gate       prefix = "/boot/grub";
49537c478bd9Sstevel@tonic-gate       grub_sprintf (stage1, "%s%s", prefix, "/stage1");
49547c478bd9Sstevel@tonic-gate       if (! check_file (stage1))
49557c478bd9Sstevel@tonic-gate 	{
49567c478bd9Sstevel@tonic-gate 	  errnum = ERR_NONE;
49577c478bd9Sstevel@tonic-gate 	  prefix = "/grub";
49587c478bd9Sstevel@tonic-gate 	  grub_sprintf (stage1, "%s%s", prefix, "/stage1");
49597c478bd9Sstevel@tonic-gate 	  if (! check_file (stage1))
49607c478bd9Sstevel@tonic-gate 	    goto fail;
49617c478bd9Sstevel@tonic-gate 	}
49627c478bd9Sstevel@tonic-gate     }
49637c478bd9Sstevel@tonic-gate   else
49647c478bd9Sstevel@tonic-gate     {
49657c478bd9Sstevel@tonic-gate       grub_sprintf (stage1, "%s%s", prefix, "/stage1");
49667c478bd9Sstevel@tonic-gate       if (! check_file (stage1))
49677c478bd9Sstevel@tonic-gate 	goto fail;
49687c478bd9Sstevel@tonic-gate     }
49697c478bd9Sstevel@tonic-gate 
49707c478bd9Sstevel@tonic-gate   /* The prefix was determined.  */
49717c478bd9Sstevel@tonic-gate   grub_sprintf (stage2, "%s%s", prefix, "/stage2");
49727c478bd9Sstevel@tonic-gate   grub_sprintf (config_filename, "%s%s", prefix, "/menu.lst");
49737c478bd9Sstevel@tonic-gate   *real_config_filename = 0;
49747c478bd9Sstevel@tonic-gate 
49757c478bd9Sstevel@tonic-gate   /* Check if stage2 exists.  */
49767c478bd9Sstevel@tonic-gate   if (! check_file (stage2))
49777c478bd9Sstevel@tonic-gate     goto fail;
49787c478bd9Sstevel@tonic-gate 
49797c478bd9Sstevel@tonic-gate   {
49807c478bd9Sstevel@tonic-gate     char *fsys = fsys_table[fsys_type].name;
49817c478bd9Sstevel@tonic-gate     int i;
49827c478bd9Sstevel@tonic-gate     int size = sizeof (stage1_5_map) / sizeof (stage1_5_map[0]);
49837c478bd9Sstevel@tonic-gate 
49847c478bd9Sstevel@tonic-gate     /* Iterate finding the same filesystem name as FSYS.  */
49857c478bd9Sstevel@tonic-gate     for (i = 0; i < size; i++)
49867c478bd9Sstevel@tonic-gate       if (grub_strcmp (fsys, stage1_5_map[i].fsys) == 0)
49877c478bd9Sstevel@tonic-gate 	{
49887c478bd9Sstevel@tonic-gate 	  /* OK, check if the Stage 1.5 exists.  */
49897c478bd9Sstevel@tonic-gate 	  char stage1_5[64];
49907c478bd9Sstevel@tonic-gate 
49917c478bd9Sstevel@tonic-gate 	  grub_sprintf (stage1_5, "%s%s", prefix, stage1_5_map[i].name);
49927c478bd9Sstevel@tonic-gate 	  if (check_file (stage1_5))
49937c478bd9Sstevel@tonic-gate 	    {
49947c478bd9Sstevel@tonic-gate 	      if (embed_stage1_5 (stage1_5,
49957c478bd9Sstevel@tonic-gate 				    installed_drive, installed_partition)
49967c478bd9Sstevel@tonic-gate 		  || embed_stage1_5 (stage1_5,
49977c478bd9Sstevel@tonic-gate 				     image_drive, image_partition))
49987c478bd9Sstevel@tonic-gate 		{
49997c478bd9Sstevel@tonic-gate 		  grub_strcpy (real_config_filename, config_filename);
50007c478bd9Sstevel@tonic-gate 		  sprint_device (image_drive, image_partition);
50017c478bd9Sstevel@tonic-gate 		  grub_sprintf (config_filename, "%s%s", device, stage2);
50027c478bd9Sstevel@tonic-gate 		  grub_strcpy (stage2, buffer);
50037c478bd9Sstevel@tonic-gate 		}
50047c478bd9Sstevel@tonic-gate 	    }
50057c478bd9Sstevel@tonic-gate 	  errnum = 0;
50067c478bd9Sstevel@tonic-gate 	  break;
50077c478bd9Sstevel@tonic-gate 	}
50087c478bd9Sstevel@tonic-gate   }
50097c478bd9Sstevel@tonic-gate 
50107c478bd9Sstevel@tonic-gate   /* Construct a string that is used by the command "install" as its
50117c478bd9Sstevel@tonic-gate      arguments.  */
50127c478bd9Sstevel@tonic-gate   sprint_device (installed_drive, installed_partition);
50137c478bd9Sstevel@tonic-gate 
50147c478bd9Sstevel@tonic-gate #if 1
50157c478bd9Sstevel@tonic-gate   /* Don't embed a drive number unnecessarily.  */
50167c478bd9Sstevel@tonic-gate   grub_sprintf (cmd_arg, "%s%s%s%s %s%s %s p %s %s",
50177c478bd9Sstevel@tonic-gate 		is_force_lba? "--force-lba " : "",
50187c478bd9Sstevel@tonic-gate 		stage2_arg? stage2_arg : "",
50197c478bd9Sstevel@tonic-gate 		stage2_arg? " " : "",
50207c478bd9Sstevel@tonic-gate 		stage1,
50217c478bd9Sstevel@tonic-gate 		(installed_drive != image_drive) ? "d " : "",
50227c478bd9Sstevel@tonic-gate 		device,
50237c478bd9Sstevel@tonic-gate 		stage2,
50247c478bd9Sstevel@tonic-gate 		config_filename,
50257c478bd9Sstevel@tonic-gate 		real_config_filename);
50267c478bd9Sstevel@tonic-gate #else /* NOT USED */
50277c478bd9Sstevel@tonic-gate   /* This code was used, because we belived some BIOSes had a problem
50287c478bd9Sstevel@tonic-gate      that they didn't pass a booting drive correctly. It turned out,
50297c478bd9Sstevel@tonic-gate      however, stage1 could trash a booting drive when checking LBA support,
50307c478bd9Sstevel@tonic-gate      because some BIOSes modified the register %dx in INT 13H, AH=48H.
50317c478bd9Sstevel@tonic-gate      So it becamed unclear whether GRUB should use a pre-defined booting
50327c478bd9Sstevel@tonic-gate      drive or not. If the problem still exists, it would be necessary to
50337c478bd9Sstevel@tonic-gate      switch back to this code.  */
50347c478bd9Sstevel@tonic-gate   grub_sprintf (cmd_arg, "%s%s%s%s d %s %s p %s %s",
50357c478bd9Sstevel@tonic-gate 		is_force_lba? "--force-lba " : "",
50367c478bd9Sstevel@tonic-gate 		stage2_arg? stage2_arg : "",
50377c478bd9Sstevel@tonic-gate 		stage2_arg? " " : "",
50387c478bd9Sstevel@tonic-gate 		stage1,
50397c478bd9Sstevel@tonic-gate 		device,
50407c478bd9Sstevel@tonic-gate 		stage2,
50417c478bd9Sstevel@tonic-gate 		config_filename,
50427c478bd9Sstevel@tonic-gate 		real_config_filename);
50437c478bd9Sstevel@tonic-gate #endif /* NOT USED */
50447c478bd9Sstevel@tonic-gate 
50457c478bd9Sstevel@tonic-gate   /* Notify what will be run.  */
50467c478bd9Sstevel@tonic-gate   grub_printf (" Running \"install %s\"... ", cmd_arg);
50477c478bd9Sstevel@tonic-gate 
50487c478bd9Sstevel@tonic-gate   /* Make sure that SAVED_DRIVE and SAVED_PARTITION are identical
50497c478bd9Sstevel@tonic-gate      with IMAGE_DRIVE and IMAGE_PARTITION, respectively.  */
50507c478bd9Sstevel@tonic-gate   saved_drive = image_drive;
50517c478bd9Sstevel@tonic-gate   saved_partition = image_partition;
50527c478bd9Sstevel@tonic-gate 
50537c478bd9Sstevel@tonic-gate   /* Run the command.  */
50547c478bd9Sstevel@tonic-gate   if (! install_func (cmd_arg, flags))
50557c478bd9Sstevel@tonic-gate     grub_printf ("succeeded\nDone.\n");
50567c478bd9Sstevel@tonic-gate   else
50577c478bd9Sstevel@tonic-gate     grub_printf ("failed\n");
50587c478bd9Sstevel@tonic-gate 
50597c478bd9Sstevel@tonic-gate  fail:
50607c478bd9Sstevel@tonic-gate   saved_drive = tmp_drive;
50617c478bd9Sstevel@tonic-gate   saved_partition = tmp_partition;
50627c478bd9Sstevel@tonic-gate   return errnum;
50637c478bd9Sstevel@tonic-gate }
50647c478bd9Sstevel@tonic-gate 
50657c478bd9Sstevel@tonic-gate static struct builtin builtin_setup =
50667c478bd9Sstevel@tonic-gate {
50677c478bd9Sstevel@tonic-gate   "setup",
50687c478bd9Sstevel@tonic-gate   setup_func,
50697c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
50707c478bd9Sstevel@tonic-gate   "setup [--prefix=DIR] [--stage2=STAGE2_FILE] [--force-lba] INSTALL_DEVICE [IMAGE_DEVICE]",
50717c478bd9Sstevel@tonic-gate   "Set up the installation of GRUB automatically. This command uses"
50727c478bd9Sstevel@tonic-gate   " the more flexible command \"install\" in the backend and installs"
50737c478bd9Sstevel@tonic-gate   " GRUB into the device INSTALL_DEVICE. If IMAGE_DEVICE is specified,"
50747c478bd9Sstevel@tonic-gate   " then find the GRUB images in the device IMAGE_DEVICE, otherwise"
50757c478bd9Sstevel@tonic-gate   " use the current \"root device\", which can be set by the command"
50767c478bd9Sstevel@tonic-gate   " \"root\". If you know that your BIOS should support LBA but GRUB"
50777c478bd9Sstevel@tonic-gate   " doesn't work in LBA mode, specify the option `--force-lba'."
50787c478bd9Sstevel@tonic-gate   " If you install GRUB under the grub shell and you cannot unmount the"
50797c478bd9Sstevel@tonic-gate   " partition where GRUB images reside, specify the option `--stage2'"
50807c478bd9Sstevel@tonic-gate   " to tell GRUB the file name under your OS."
50817c478bd9Sstevel@tonic-gate };
50827c478bd9Sstevel@tonic-gate 
50837c478bd9Sstevel@tonic-gate 
50847c478bd9Sstevel@tonic-gate #if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES) || defined(SUPPORT_GRAPHICS)
50857c478bd9Sstevel@tonic-gate /* terminal */
50867c478bd9Sstevel@tonic-gate static int
50877c478bd9Sstevel@tonic-gate terminal_func (char *arg, int flags)
50887c478bd9Sstevel@tonic-gate {
50897c478bd9Sstevel@tonic-gate   /* The index of the default terminal in TERM_TABLE.  */
50907c478bd9Sstevel@tonic-gate   int default_term = -1;
50917c478bd9Sstevel@tonic-gate   struct term_entry *prev_term = current_term;
50927c478bd9Sstevel@tonic-gate   int to = -1;
50937c478bd9Sstevel@tonic-gate   int lines = 0;
50947c478bd9Sstevel@tonic-gate   int no_message = 0;
50957c478bd9Sstevel@tonic-gate   unsigned long term_flags = 0;
50967c478bd9Sstevel@tonic-gate   /* XXX: Assume less than 32 terminals.  */
50977c478bd9Sstevel@tonic-gate   unsigned long term_bitmap = 0;
50987c478bd9Sstevel@tonic-gate 
50997c478bd9Sstevel@tonic-gate   /* Get GNU-style long options.  */
51007c478bd9Sstevel@tonic-gate   while (1)
51017c478bd9Sstevel@tonic-gate     {
51027c478bd9Sstevel@tonic-gate       if (grub_memcmp (arg, "--dumb", sizeof ("--dumb") - 1) == 0)
51037c478bd9Sstevel@tonic-gate 	term_flags |= TERM_DUMB;
51047c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--no-echo", sizeof ("--no-echo") - 1) == 0)
51057c478bd9Sstevel@tonic-gate 	/* ``--no-echo'' implies ``--no-edit''.  */
51067c478bd9Sstevel@tonic-gate 	term_flags |= (TERM_NO_ECHO | TERM_NO_EDIT);
51077c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--no-edit", sizeof ("--no-edit") - 1) == 0)
51087c478bd9Sstevel@tonic-gate 	term_flags |= TERM_NO_EDIT;
51097c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--timeout=", sizeof ("--timeout=") - 1) == 0)
51107c478bd9Sstevel@tonic-gate 	{
51117c478bd9Sstevel@tonic-gate 	  char *val = arg + sizeof ("--timeout=") - 1;
51127c478bd9Sstevel@tonic-gate 
51137c478bd9Sstevel@tonic-gate 	  if (! safe_parse_maxint (&val, &to))
51147c478bd9Sstevel@tonic-gate 	    return 1;
51157c478bd9Sstevel@tonic-gate 	}
51167c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--lines=", sizeof ("--lines=") - 1) == 0)
51177c478bd9Sstevel@tonic-gate 	{
51187c478bd9Sstevel@tonic-gate 	  char *val = arg + sizeof ("--lines=") - 1;
51197c478bd9Sstevel@tonic-gate 
51207c478bd9Sstevel@tonic-gate 	  if (! safe_parse_maxint (&val, &lines))
51217c478bd9Sstevel@tonic-gate 	    return 1;
51227c478bd9Sstevel@tonic-gate 
51237c478bd9Sstevel@tonic-gate 	  /* Probably less than four is meaningless....  */
51247c478bd9Sstevel@tonic-gate 	  if (lines < 4)
51257c478bd9Sstevel@tonic-gate 	    {
51267c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_ARGUMENT;
51277c478bd9Sstevel@tonic-gate 	      return 1;
51287c478bd9Sstevel@tonic-gate 	    }
51297c478bd9Sstevel@tonic-gate 	}
51307c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--silent", sizeof ("--silent") - 1) == 0)
51317c478bd9Sstevel@tonic-gate 	no_message = 1;
51327c478bd9Sstevel@tonic-gate       else
51337c478bd9Sstevel@tonic-gate 	break;
51347c478bd9Sstevel@tonic-gate 
51357c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
51367c478bd9Sstevel@tonic-gate     }
51377c478bd9Sstevel@tonic-gate 
51387c478bd9Sstevel@tonic-gate   /* If no argument is specified, show current setting.  */
51397c478bd9Sstevel@tonic-gate   if (! *arg)
51407c478bd9Sstevel@tonic-gate     {
51417c478bd9Sstevel@tonic-gate       grub_printf ("%s%s%s%s\n",
51427c478bd9Sstevel@tonic-gate 		   current_term->name,
51437c478bd9Sstevel@tonic-gate 		   current_term->flags & TERM_DUMB ? " (dumb)" : "",
51447c478bd9Sstevel@tonic-gate 		   current_term->flags & TERM_NO_EDIT ? " (no edit)" : "",
51457c478bd9Sstevel@tonic-gate 		   current_term->flags & TERM_NO_ECHO ? " (no echo)" : "");
51467c478bd9Sstevel@tonic-gate       return 0;
51477c478bd9Sstevel@tonic-gate     }
51487c478bd9Sstevel@tonic-gate 
51497c478bd9Sstevel@tonic-gate   while (*arg)
51507c478bd9Sstevel@tonic-gate     {
51517c478bd9Sstevel@tonic-gate       int i;
51527c478bd9Sstevel@tonic-gate       char *next = skip_to (0, arg);
51537c478bd9Sstevel@tonic-gate 
51547c478bd9Sstevel@tonic-gate       nul_terminate (arg);
51557c478bd9Sstevel@tonic-gate 
51567c478bd9Sstevel@tonic-gate       for (i = 0; term_table[i].name; i++)
51577c478bd9Sstevel@tonic-gate 	{
51587c478bd9Sstevel@tonic-gate 	  if (grub_strcmp (arg, term_table[i].name) == 0)
51597c478bd9Sstevel@tonic-gate 	    {
51607c478bd9Sstevel@tonic-gate 	      if (term_table[i].flags & TERM_NEED_INIT)
51617c478bd9Sstevel@tonic-gate 		{
51627c478bd9Sstevel@tonic-gate 		  errnum = ERR_DEV_NEED_INIT;
51637c478bd9Sstevel@tonic-gate 		  return 1;
51647c478bd9Sstevel@tonic-gate 		}
51657c478bd9Sstevel@tonic-gate 
51667c478bd9Sstevel@tonic-gate 	      if (default_term < 0)
51677c478bd9Sstevel@tonic-gate 		default_term = i;
51687c478bd9Sstevel@tonic-gate 
51697c478bd9Sstevel@tonic-gate 	      term_bitmap |= (1 << i);
51707c478bd9Sstevel@tonic-gate 	      break;
51717c478bd9Sstevel@tonic-gate 	    }
51727c478bd9Sstevel@tonic-gate 	}
51737c478bd9Sstevel@tonic-gate 
51747c478bd9Sstevel@tonic-gate       if (! term_table[i].name)
51757c478bd9Sstevel@tonic-gate 	{
51767c478bd9Sstevel@tonic-gate 	  errnum = ERR_BAD_ARGUMENT;
51777c478bd9Sstevel@tonic-gate 	  return 1;
51787c478bd9Sstevel@tonic-gate 	}
51797c478bd9Sstevel@tonic-gate 
51807c478bd9Sstevel@tonic-gate       arg = next;
51817c478bd9Sstevel@tonic-gate     }
51827c478bd9Sstevel@tonic-gate 
51837c478bd9Sstevel@tonic-gate   /* If multiple terminals are specified, wait until the user pushes any
51847c478bd9Sstevel@tonic-gate      key on one of the terminals.  */
51857c478bd9Sstevel@tonic-gate   if (term_bitmap & ~(1 << default_term))
51867c478bd9Sstevel@tonic-gate     {
51877c478bd9Sstevel@tonic-gate       int time1, time2 = -1;
51887c478bd9Sstevel@tonic-gate 
51897c478bd9Sstevel@tonic-gate       /* XXX: Disable the pager.  */
51907c478bd9Sstevel@tonic-gate       count_lines = -1;
51917c478bd9Sstevel@tonic-gate 
51927c478bd9Sstevel@tonic-gate       /* Get current time.  */
51937c478bd9Sstevel@tonic-gate       while ((time1 = getrtsecs ()) == 0xFF)
51947c478bd9Sstevel@tonic-gate 	;
51957c478bd9Sstevel@tonic-gate 
51967c478bd9Sstevel@tonic-gate       /* Wait for a key input.  */
51977c478bd9Sstevel@tonic-gate       while (to)
51987c478bd9Sstevel@tonic-gate 	{
51997c478bd9Sstevel@tonic-gate 	  int i;
52007c478bd9Sstevel@tonic-gate 
52017c478bd9Sstevel@tonic-gate 	  for (i = 0; term_table[i].name; i++)
52027c478bd9Sstevel@tonic-gate 	    {
52037c478bd9Sstevel@tonic-gate 	      if (term_bitmap & (1 << i))
52047c478bd9Sstevel@tonic-gate 		{
52057c478bd9Sstevel@tonic-gate 		  if (term_table[i].checkkey () >= 0)
52067c478bd9Sstevel@tonic-gate 		    {
52077c478bd9Sstevel@tonic-gate 		      (void) term_table[i].getkey ();
52087c478bd9Sstevel@tonic-gate 		      default_term = i;
52097c478bd9Sstevel@tonic-gate 
52107c478bd9Sstevel@tonic-gate 		      goto end;
52117c478bd9Sstevel@tonic-gate 		    }
52127c478bd9Sstevel@tonic-gate 		}
52137c478bd9Sstevel@tonic-gate 	    }
52147c478bd9Sstevel@tonic-gate 
52157c478bd9Sstevel@tonic-gate 	  /* Prompt the user, once per sec.  */
52167c478bd9Sstevel@tonic-gate 	  if ((time1 = getrtsecs ()) != time2 && time1 != 0xFF)
52177c478bd9Sstevel@tonic-gate 	    {
52187c478bd9Sstevel@tonic-gate 	      if (! no_message)
52197c478bd9Sstevel@tonic-gate 		{
52207c478bd9Sstevel@tonic-gate 		  /* Need to set CURRENT_TERM to each of selected
52217c478bd9Sstevel@tonic-gate 		     terminals.  */
52227c478bd9Sstevel@tonic-gate 		  for (i = 0; term_table[i].name; i++)
52237c478bd9Sstevel@tonic-gate 		    if (term_bitmap & (1 << i))
52247c478bd9Sstevel@tonic-gate 		      {
52257c478bd9Sstevel@tonic-gate 			current_term = term_table + i;
52267c478bd9Sstevel@tonic-gate 			grub_printf ("\rPress any key to continue.\n");
52277c478bd9Sstevel@tonic-gate 		      }
52287c478bd9Sstevel@tonic-gate 
52297c478bd9Sstevel@tonic-gate 		  /* Restore CURRENT_TERM.  */
52307c478bd9Sstevel@tonic-gate 		  current_term = prev_term;
52317c478bd9Sstevel@tonic-gate 		}
52327c478bd9Sstevel@tonic-gate 
52337c478bd9Sstevel@tonic-gate 	      time2 = time1;
52347c478bd9Sstevel@tonic-gate 	      if (to > 0)
52357c478bd9Sstevel@tonic-gate 		to--;
52367c478bd9Sstevel@tonic-gate 	    }
52377c478bd9Sstevel@tonic-gate 	}
52387c478bd9Sstevel@tonic-gate     }
52397c478bd9Sstevel@tonic-gate 
52407c478bd9Sstevel@tonic-gate  end:
52417c478bd9Sstevel@tonic-gate   current_term = term_table + default_term;
52427c478bd9Sstevel@tonic-gate   current_term->flags = term_flags;
52437c478bd9Sstevel@tonic-gate 
52447c478bd9Sstevel@tonic-gate   if (lines)
52457c478bd9Sstevel@tonic-gate     max_lines = lines;
52467c478bd9Sstevel@tonic-gate   else
52477c478bd9Sstevel@tonic-gate     max_lines = current_term->max_lines;
52487c478bd9Sstevel@tonic-gate 
52497c478bd9Sstevel@tonic-gate   /* If the interface is currently the command-line,
52507c478bd9Sstevel@tonic-gate      restart it to repaint the screen.  */
52517c478bd9Sstevel@tonic-gate   if ((current_term != prev_term) && (flags & BUILTIN_CMDLINE)){
52527c478bd9Sstevel@tonic-gate     if (prev_term->shutdown)
52537c478bd9Sstevel@tonic-gate       prev_term->shutdown();
52547c478bd9Sstevel@tonic-gate     if (current_term->startup)
52557c478bd9Sstevel@tonic-gate       current_term->startup();
52567c478bd9Sstevel@tonic-gate     grub_longjmp (restart_cmdline_env, 0);
52577c478bd9Sstevel@tonic-gate   }
52587c478bd9Sstevel@tonic-gate 
52597c478bd9Sstevel@tonic-gate   return 0;
52607c478bd9Sstevel@tonic-gate }
52617c478bd9Sstevel@tonic-gate 
52627c478bd9Sstevel@tonic-gate static struct builtin builtin_terminal =
52637c478bd9Sstevel@tonic-gate {
52647c478bd9Sstevel@tonic-gate   "terminal",
52657c478bd9Sstevel@tonic-gate   terminal_func,
52667c478bd9Sstevel@tonic-gate   BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
52677c478bd9Sstevel@tonic-gate   "terminal [--dumb] [--no-echo] [--no-edit] [--timeout=SECS] [--lines=LINES] [--silent] [console] [serial] [hercules] [graphics]",
52687c478bd9Sstevel@tonic-gate   "Select a terminal. When multiple terminals are specified, wait until"
52697c478bd9Sstevel@tonic-gate   " you push any key to continue. If both console and serial are specified,"
52707c478bd9Sstevel@tonic-gate   " the terminal to which you input a key first will be selected. If no"
52717c478bd9Sstevel@tonic-gate   " argument is specified, print current setting. The option --dumb"
52727c478bd9Sstevel@tonic-gate   " specifies that your terminal is dumb, otherwise, vt100-compatibility"
52737c478bd9Sstevel@tonic-gate   " is assumed. If you specify --no-echo, input characters won't be echoed."
52747c478bd9Sstevel@tonic-gate   " If you specify --no-edit, the BASH-like editing feature will be disabled."
52757c478bd9Sstevel@tonic-gate   " If --timeout is present, this command will wait at most for SECS"
52767c478bd9Sstevel@tonic-gate   " seconds. The option --lines specifies the maximum number of lines."
52777c478bd9Sstevel@tonic-gate   " The option --silent is used to suppress messages."
52787c478bd9Sstevel@tonic-gate };
52797c478bd9Sstevel@tonic-gate #endif /* SUPPORT_SERIAL || SUPPORT_HERCULES || SUPPORT_GRAPHICS */
52807c478bd9Sstevel@tonic-gate 
52817c478bd9Sstevel@tonic-gate 
52827c478bd9Sstevel@tonic-gate #ifdef SUPPORT_SERIAL
52837c478bd9Sstevel@tonic-gate static int
52847c478bd9Sstevel@tonic-gate terminfo_func (char *arg, int flags)
52857c478bd9Sstevel@tonic-gate {
52867c478bd9Sstevel@tonic-gate   struct terminfo term;
52877c478bd9Sstevel@tonic-gate 
52887c478bd9Sstevel@tonic-gate   if (*arg)
52897c478bd9Sstevel@tonic-gate     {
52907c478bd9Sstevel@tonic-gate       struct
52917c478bd9Sstevel@tonic-gate       {
52927c478bd9Sstevel@tonic-gate 	const char *name;
52937c478bd9Sstevel@tonic-gate 	char *var;
52947c478bd9Sstevel@tonic-gate       }
52957c478bd9Sstevel@tonic-gate       options[] =
52967c478bd9Sstevel@tonic-gate 	{
52977c478bd9Sstevel@tonic-gate 	  {"--name=", term.name},
52987c478bd9Sstevel@tonic-gate 	  {"--cursor-address=", term.cursor_address},
52997c478bd9Sstevel@tonic-gate 	  {"--clear-screen=", term.clear_screen},
53007c478bd9Sstevel@tonic-gate 	  {"--enter-standout-mode=", term.enter_standout_mode},
53017c478bd9Sstevel@tonic-gate 	  {"--exit-standout-mode=", term.exit_standout_mode}
53027c478bd9Sstevel@tonic-gate 	};
53037c478bd9Sstevel@tonic-gate 
53047c478bd9Sstevel@tonic-gate       grub_memset (&term, 0, sizeof (term));
53057c478bd9Sstevel@tonic-gate 
53067c478bd9Sstevel@tonic-gate       while (*arg)
53077c478bd9Sstevel@tonic-gate 	{
53087c478bd9Sstevel@tonic-gate 	  int i;
53097c478bd9Sstevel@tonic-gate 	  char *next = skip_to (0, arg);
53107c478bd9Sstevel@tonic-gate 
53117c478bd9Sstevel@tonic-gate 	  nul_terminate (arg);
53127c478bd9Sstevel@tonic-gate 
53137c478bd9Sstevel@tonic-gate 	  for (i = 0; i < sizeof (options) / sizeof (options[0]); i++)
53147c478bd9Sstevel@tonic-gate 	    {
53157c478bd9Sstevel@tonic-gate 	      const char *name = options[i].name;
53167c478bd9Sstevel@tonic-gate 	      int len = grub_strlen (name);
53177c478bd9Sstevel@tonic-gate 
53187c478bd9Sstevel@tonic-gate 	      if (! grub_memcmp (arg, name, len))
53197c478bd9Sstevel@tonic-gate 		{
53207c478bd9Sstevel@tonic-gate 		  grub_strcpy (options[i].var, ti_unescape_string (arg + len));
53217c478bd9Sstevel@tonic-gate 		  break;
53227c478bd9Sstevel@tonic-gate 		}
53237c478bd9Sstevel@tonic-gate 	    }
53247c478bd9Sstevel@tonic-gate 
53257c478bd9Sstevel@tonic-gate 	  if (i == sizeof (options) / sizeof (options[0]))
53267c478bd9Sstevel@tonic-gate 	    {
53277c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_ARGUMENT;
53287c478bd9Sstevel@tonic-gate 	      return errnum;
53297c478bd9Sstevel@tonic-gate 	    }
53307c478bd9Sstevel@tonic-gate 
53317c478bd9Sstevel@tonic-gate 	  arg = next;
53327c478bd9Sstevel@tonic-gate 	}
53337c478bd9Sstevel@tonic-gate 
53347c478bd9Sstevel@tonic-gate       if (term.name[0] == 0 || term.cursor_address[0] == 0)
53357c478bd9Sstevel@tonic-gate 	{
53367c478bd9Sstevel@tonic-gate 	  errnum = ERR_BAD_ARGUMENT;
53377c478bd9Sstevel@tonic-gate 	  return errnum;
53387c478bd9Sstevel@tonic-gate 	}
53397c478bd9Sstevel@tonic-gate 
53407c478bd9Sstevel@tonic-gate       ti_set_term (&term);
53417c478bd9Sstevel@tonic-gate     }
53427c478bd9Sstevel@tonic-gate   else
53437c478bd9Sstevel@tonic-gate     {
53447c478bd9Sstevel@tonic-gate       /* No option specifies printing out current settings.  */
53457c478bd9Sstevel@tonic-gate       ti_get_term (&term);
53467c478bd9Sstevel@tonic-gate 
53477c478bd9Sstevel@tonic-gate       grub_printf ("name=%s\n",
53487c478bd9Sstevel@tonic-gate 		   ti_escape_string (term.name));
53497c478bd9Sstevel@tonic-gate       grub_printf ("cursor_address=%s\n",
53507c478bd9Sstevel@tonic-gate 		   ti_escape_string (term.cursor_address));
53517c478bd9Sstevel@tonic-gate       grub_printf ("clear_screen=%s\n",
53527c478bd9Sstevel@tonic-gate 		   ti_escape_string (term.clear_screen));
53537c478bd9Sstevel@tonic-gate       grub_printf ("enter_standout_mode=%s\n",
53547c478bd9Sstevel@tonic-gate 		   ti_escape_string (term.enter_standout_mode));
53557c478bd9Sstevel@tonic-gate       grub_printf ("exit_standout_mode=%s\n",
53567c478bd9Sstevel@tonic-gate 		   ti_escape_string (term.exit_standout_mode));
53577c478bd9Sstevel@tonic-gate     }
53587c478bd9Sstevel@tonic-gate 
53597c478bd9Sstevel@tonic-gate   return 0;
53607c478bd9Sstevel@tonic-gate }
53617c478bd9Sstevel@tonic-gate 
53627c478bd9Sstevel@tonic-gate static struct builtin builtin_terminfo =
53637c478bd9Sstevel@tonic-gate {
53647c478bd9Sstevel@tonic-gate   "terminfo",
53657c478bd9Sstevel@tonic-gate   terminfo_func,
53667c478bd9Sstevel@tonic-gate   BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
53677c478bd9Sstevel@tonic-gate   "terminfo [--name=NAME --cursor-address=SEQ [--clear-screen=SEQ]"
53687c478bd9Sstevel@tonic-gate   " [--enter-standout-mode=SEQ] [--exit-standout-mode=SEQ]]",
53697c478bd9Sstevel@tonic-gate 
53707c478bd9Sstevel@tonic-gate   "Define the capabilities of your terminal. Use this command to"
53717c478bd9Sstevel@tonic-gate   " define escape sequences, if it is not vt100-compatible."
53727c478bd9Sstevel@tonic-gate   " You may use \\e for ESC and ^X for a control character."
53737c478bd9Sstevel@tonic-gate   " If no option is specified, the current settings are printed."
53747c478bd9Sstevel@tonic-gate };
53757c478bd9Sstevel@tonic-gate #endif /* SUPPORT_SERIAL */
53767c478bd9Sstevel@tonic-gate 
53777c478bd9Sstevel@tonic-gate 
53787c478bd9Sstevel@tonic-gate /* testload */
53797c478bd9Sstevel@tonic-gate static int
53807c478bd9Sstevel@tonic-gate testload_func (char *arg, int flags)
53817c478bd9Sstevel@tonic-gate {
53827c478bd9Sstevel@tonic-gate   int i;
53837c478bd9Sstevel@tonic-gate 
53847c478bd9Sstevel@tonic-gate   kernel_type = KERNEL_TYPE_NONE;
53857c478bd9Sstevel@tonic-gate 
53867c478bd9Sstevel@tonic-gate   if (! grub_open (arg))
53877c478bd9Sstevel@tonic-gate     return 1;
53887c478bd9Sstevel@tonic-gate 
53897c478bd9Sstevel@tonic-gate   disk_read_hook = disk_read_print_func;
53907c478bd9Sstevel@tonic-gate 
53917c478bd9Sstevel@tonic-gate   /* Perform filesystem test on the specified file.  */
53927c478bd9Sstevel@tonic-gate   /* Read whole file first. */
53937c478bd9Sstevel@tonic-gate   grub_printf ("Whole file: ");
53947c478bd9Sstevel@tonic-gate 
53957c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x100000), -1);
53967c478bd9Sstevel@tonic-gate 
53977c478bd9Sstevel@tonic-gate   /* Now compare two sections of the file read differently.  */
53987c478bd9Sstevel@tonic-gate 
53997c478bd9Sstevel@tonic-gate   for (i = 0; i < 0x10ac0; i++)
54007c478bd9Sstevel@tonic-gate     {
54017c478bd9Sstevel@tonic-gate       *((unsigned char *) RAW_ADDR (0x200000 + i)) = 0;
54027c478bd9Sstevel@tonic-gate       *((unsigned char *) RAW_ADDR (0x300000 + i)) = 1;
54037c478bd9Sstevel@tonic-gate     }
54047c478bd9Sstevel@tonic-gate 
54057c478bd9Sstevel@tonic-gate   /* First partial read.  */
54067c478bd9Sstevel@tonic-gate   grub_printf ("\nPartial read 1: ");
54077c478bd9Sstevel@tonic-gate 
54087c478bd9Sstevel@tonic-gate   grub_seek (0);
54097c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x200000), 0x7);
54107c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x200007), 0x100);
54117c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x200107), 0x10);
54127c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x200117), 0x999);
54137c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x200ab0), 0x10);
54147c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x200ac0), 0x10000);
54157c478bd9Sstevel@tonic-gate 
54167c478bd9Sstevel@tonic-gate   /* Second partial read.  */
54177c478bd9Sstevel@tonic-gate   grub_printf ("\nPartial read 2: ");
54187c478bd9Sstevel@tonic-gate 
54197c478bd9Sstevel@tonic-gate   grub_seek (0);
54207c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x300000), 0x10000);
54217c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x310000), 0x10);
54227c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x310010), 0x7);
54237c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x310017), 0x10);
54247c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x310027), 0x999);
54257c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x3109c0), 0x100);
54267c478bd9Sstevel@tonic-gate 
54277c478bd9Sstevel@tonic-gate   grub_printf ("\nHeader1 = 0x%x, next = 0x%x, next = 0x%x, next = 0x%x\n",
54287c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x200000)),
54297c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x200004)),
54307c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x200008)),
54317c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x20000c)));
54327c478bd9Sstevel@tonic-gate 
54337c478bd9Sstevel@tonic-gate   grub_printf ("Header2 = 0x%x, next = 0x%x, next = 0x%x, next = 0x%x\n",
54347c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x300000)),
54357c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x300004)),
54367c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x300008)),
54377c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x30000c)));
54387c478bd9Sstevel@tonic-gate 
54397c478bd9Sstevel@tonic-gate   for (i = 0; i < 0x10ac0; i++)
54407c478bd9Sstevel@tonic-gate     if (*((unsigned char *) RAW_ADDR (0x200000 + i))
54417c478bd9Sstevel@tonic-gate 	!= *((unsigned char *) RAW_ADDR (0x300000 + i)))
54427c478bd9Sstevel@tonic-gate       break;
54437c478bd9Sstevel@tonic-gate 
54447c478bd9Sstevel@tonic-gate   grub_printf ("Max is 0x10ac0: i=0x%x, filepos=0x%x\n", i, filepos);
54457c478bd9Sstevel@tonic-gate   disk_read_hook = 0;
54467c478bd9Sstevel@tonic-gate   grub_close ();
54477c478bd9Sstevel@tonic-gate   return 0;
54487c478bd9Sstevel@tonic-gate }
54497c478bd9Sstevel@tonic-gate 
54507c478bd9Sstevel@tonic-gate static struct builtin builtin_testload =
54517c478bd9Sstevel@tonic-gate {
54527c478bd9Sstevel@tonic-gate   "testload",
54537c478bd9Sstevel@tonic-gate   testload_func,
54547c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
54557c478bd9Sstevel@tonic-gate   "testload FILE",
54567c478bd9Sstevel@tonic-gate   "Read the entire contents of FILE in several different ways and"
54577c478bd9Sstevel@tonic-gate   " compares them, to test the filesystem code. The output is somewhat"
54587c478bd9Sstevel@tonic-gate   " cryptic, but if no errors are reported and the final `i=X,"
54597c478bd9Sstevel@tonic-gate   " filepos=Y' reading has X and Y equal, then it is definitely"
54607c478bd9Sstevel@tonic-gate   " consistent, and very likely works correctly subject to a"
54617c478bd9Sstevel@tonic-gate   " consistent offset error. If this test succeeds, then a good next"
54627c478bd9Sstevel@tonic-gate   " step is to try loading a kernel."
54637c478bd9Sstevel@tonic-gate };
54647c478bd9Sstevel@tonic-gate 
54657c478bd9Sstevel@tonic-gate 
54667c478bd9Sstevel@tonic-gate /* testvbe MODE */
54677c478bd9Sstevel@tonic-gate static int
54687c478bd9Sstevel@tonic-gate testvbe_func (char *arg, int flags)
54697c478bd9Sstevel@tonic-gate {
54707c478bd9Sstevel@tonic-gate   int mode_number;
54717c478bd9Sstevel@tonic-gate   struct vbe_controller controller;
54727c478bd9Sstevel@tonic-gate   struct vbe_mode mode;
54737c478bd9Sstevel@tonic-gate 
54747c478bd9Sstevel@tonic-gate   if (! *arg)
54757c478bd9Sstevel@tonic-gate     {
54767c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
54777c478bd9Sstevel@tonic-gate       return 1;
54787c478bd9Sstevel@tonic-gate     }
54797c478bd9Sstevel@tonic-gate 
54807c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &mode_number))
54817c478bd9Sstevel@tonic-gate     return 1;
54827c478bd9Sstevel@tonic-gate 
54837c478bd9Sstevel@tonic-gate   /* Preset `VBE2'.  */
54847c478bd9Sstevel@tonic-gate   grub_memmove (controller.signature, "VBE2", 4);
54857c478bd9Sstevel@tonic-gate 
54867c478bd9Sstevel@tonic-gate   /* Detect VBE BIOS.  */
54877c478bd9Sstevel@tonic-gate   if (get_vbe_controller_info (&controller) != 0x004F)
54887c478bd9Sstevel@tonic-gate     {
54897c478bd9Sstevel@tonic-gate       grub_printf (" VBE BIOS is not present.\n");
54907c478bd9Sstevel@tonic-gate       return 0;
54917c478bd9Sstevel@tonic-gate     }
54927c478bd9Sstevel@tonic-gate 
54937c478bd9Sstevel@tonic-gate   if (controller.version < 0x0200)
54947c478bd9Sstevel@tonic-gate     {
54957c478bd9Sstevel@tonic-gate       grub_printf (" VBE version %d.%d is not supported.\n",
54967c478bd9Sstevel@tonic-gate 		   (int) (controller.version >> 8),
54977c478bd9Sstevel@tonic-gate 		   (int) (controller.version & 0xFF));
54987c478bd9Sstevel@tonic-gate       return 0;
54997c478bd9Sstevel@tonic-gate     }
55007c478bd9Sstevel@tonic-gate 
55017c478bd9Sstevel@tonic-gate   if (get_vbe_mode_info (mode_number, &mode) != 0x004F
55027c478bd9Sstevel@tonic-gate       || (mode.mode_attributes & 0x0091) != 0x0091)
55037c478bd9Sstevel@tonic-gate     {
55047c478bd9Sstevel@tonic-gate       grub_printf (" Mode 0x%x is not supported.\n", mode_number);
55057c478bd9Sstevel@tonic-gate       return 0;
55067c478bd9Sstevel@tonic-gate     }
55077c478bd9Sstevel@tonic-gate 
55087c478bd9Sstevel@tonic-gate   /* Now trip to the graphics mode.  */
55097c478bd9Sstevel@tonic-gate   if (set_vbe_mode (mode_number | (1 << 14)) != 0x004F)
55107c478bd9Sstevel@tonic-gate     {
55117c478bd9Sstevel@tonic-gate       grub_printf (" Switching to Mode 0x%x failed.\n", mode_number);
55127c478bd9Sstevel@tonic-gate       return 0;
55137c478bd9Sstevel@tonic-gate     }
55147c478bd9Sstevel@tonic-gate 
55157c478bd9Sstevel@tonic-gate   /* Draw something on the screen...  */
55167c478bd9Sstevel@tonic-gate   {
55177c478bd9Sstevel@tonic-gate     unsigned char *base_buf = (unsigned char *) mode.phys_base;
55187c478bd9Sstevel@tonic-gate     int scanline = controller.version >= 0x0300
55197c478bd9Sstevel@tonic-gate       ? mode.linear_bytes_per_scanline : mode.bytes_per_scanline;
55207c478bd9Sstevel@tonic-gate     /* FIXME: this assumes that any depth is a modulo of 8.  */
55217c478bd9Sstevel@tonic-gate     int bpp = mode.bits_per_pixel / 8;
55227c478bd9Sstevel@tonic-gate     int width = mode.x_resolution;
55237c478bd9Sstevel@tonic-gate     int height = mode.y_resolution;
55247c478bd9Sstevel@tonic-gate     int x, y;
55257c478bd9Sstevel@tonic-gate     unsigned color = 0;
55267c478bd9Sstevel@tonic-gate 
55277c478bd9Sstevel@tonic-gate     /* Iterate drawing on the screen, until the user hits any key.  */
55287c478bd9Sstevel@tonic-gate     while (checkkey () == -1)
55297c478bd9Sstevel@tonic-gate       {
55307c478bd9Sstevel@tonic-gate 	for (y = 0; y < height; y++)
55317c478bd9Sstevel@tonic-gate 	  {
55327c478bd9Sstevel@tonic-gate 	    unsigned char *line_buf = base_buf + scanline * y;
55337c478bd9Sstevel@tonic-gate 
55347c478bd9Sstevel@tonic-gate 	    for (x = 0; x < width; x++)
55357c478bd9Sstevel@tonic-gate 	      {
55367c478bd9Sstevel@tonic-gate 		unsigned char *buf = line_buf + bpp * x;
55377c478bd9Sstevel@tonic-gate 		int i;
55387c478bd9Sstevel@tonic-gate 
55397c478bd9Sstevel@tonic-gate 		for (i = 0; i < bpp; i++, buf++)
55407c478bd9Sstevel@tonic-gate 		  *buf = (color >> (i * 8)) & 0xff;
55417c478bd9Sstevel@tonic-gate 	      }
55427c478bd9Sstevel@tonic-gate 
55437c478bd9Sstevel@tonic-gate 	    color++;
55447c478bd9Sstevel@tonic-gate 	  }
55457c478bd9Sstevel@tonic-gate       }
55467c478bd9Sstevel@tonic-gate 
55477c478bd9Sstevel@tonic-gate     /* Discard the input.  */
55487c478bd9Sstevel@tonic-gate     getkey ();
55497c478bd9Sstevel@tonic-gate   }
55507c478bd9Sstevel@tonic-gate 
55517c478bd9Sstevel@tonic-gate   /* Back to the default text mode.  */
55527c478bd9Sstevel@tonic-gate   if (set_vbe_mode (0x03) != 0x004F)
55537c478bd9Sstevel@tonic-gate     {
55547c478bd9Sstevel@tonic-gate       /* Why?!  */
55557c478bd9Sstevel@tonic-gate       grub_reboot ();
55567c478bd9Sstevel@tonic-gate     }
55577c478bd9Sstevel@tonic-gate 
55587c478bd9Sstevel@tonic-gate   return 0;
55597c478bd9Sstevel@tonic-gate }
55607c478bd9Sstevel@tonic-gate 
55617c478bd9Sstevel@tonic-gate static struct builtin builtin_testvbe =
55627c478bd9Sstevel@tonic-gate {
55637c478bd9Sstevel@tonic-gate   "testvbe",
55647c478bd9Sstevel@tonic-gate   testvbe_func,
55657c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
55667c478bd9Sstevel@tonic-gate   "testvbe MODE",
55677c478bd9Sstevel@tonic-gate   "Test the VBE mode MODE. Hit any key to return."
55687c478bd9Sstevel@tonic-gate };
55697c478bd9Sstevel@tonic-gate 
55707c478bd9Sstevel@tonic-gate 
55717c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
55727c478bd9Sstevel@tonic-gate /* tftpserver */
55737c478bd9Sstevel@tonic-gate static int
55747c478bd9Sstevel@tonic-gate tftpserver_func (char *arg, int flags)
55757c478bd9Sstevel@tonic-gate {
55767c478bd9Sstevel@tonic-gate   if (! *arg || ! ifconfig (0, 0, 0, arg))
55777c478bd9Sstevel@tonic-gate     {
55787c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
55797c478bd9Sstevel@tonic-gate       return 1;
55807c478bd9Sstevel@tonic-gate     }
55817c478bd9Sstevel@tonic-gate 
55827c478bd9Sstevel@tonic-gate   print_network_configuration ();
55837c478bd9Sstevel@tonic-gate   return 0;
55847c478bd9Sstevel@tonic-gate }
55857c478bd9Sstevel@tonic-gate 
55867c478bd9Sstevel@tonic-gate static struct builtin builtin_tftpserver =
55877c478bd9Sstevel@tonic-gate {
55887c478bd9Sstevel@tonic-gate   "tftpserver",
55897c478bd9Sstevel@tonic-gate   tftpserver_func,
55907c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
55917c478bd9Sstevel@tonic-gate   "tftpserver IPADDR",
55927c478bd9Sstevel@tonic-gate   "Override the TFTP server address."
55937c478bd9Sstevel@tonic-gate };
55947c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
55957c478bd9Sstevel@tonic-gate 
55967c478bd9Sstevel@tonic-gate 
55977c478bd9Sstevel@tonic-gate /* timeout */
55987c478bd9Sstevel@tonic-gate static int
55997c478bd9Sstevel@tonic-gate timeout_func (char *arg, int flags)
56007c478bd9Sstevel@tonic-gate {
56017c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &grub_timeout))
56027c478bd9Sstevel@tonic-gate     return 1;
56037c478bd9Sstevel@tonic-gate 
56047c478bd9Sstevel@tonic-gate   return 0;
56057c478bd9Sstevel@tonic-gate }
56067c478bd9Sstevel@tonic-gate 
56077c478bd9Sstevel@tonic-gate static struct builtin builtin_timeout =
56087c478bd9Sstevel@tonic-gate {
56097c478bd9Sstevel@tonic-gate   "timeout",
56107c478bd9Sstevel@tonic-gate   timeout_func,
56117c478bd9Sstevel@tonic-gate   BUILTIN_MENU,
56127c478bd9Sstevel@tonic-gate #if 0
56137c478bd9Sstevel@tonic-gate   "timeout SEC",
56147c478bd9Sstevel@tonic-gate   "Set a timeout, in SEC seconds, before automatically booting the"
56157c478bd9Sstevel@tonic-gate   " default entry (normally the first entry defined)."
56167c478bd9Sstevel@tonic-gate #endif
56177c478bd9Sstevel@tonic-gate };
56187c478bd9Sstevel@tonic-gate 
56197c478bd9Sstevel@tonic-gate 
56207c478bd9Sstevel@tonic-gate /* title */
56217c478bd9Sstevel@tonic-gate static int
56227c478bd9Sstevel@tonic-gate title_func (char *arg, int flags)
56237c478bd9Sstevel@tonic-gate {
56247c478bd9Sstevel@tonic-gate   /* This function is not actually used at least currently.  */
56257c478bd9Sstevel@tonic-gate   return 0;
56267c478bd9Sstevel@tonic-gate }
56277c478bd9Sstevel@tonic-gate 
56287c478bd9Sstevel@tonic-gate static struct builtin builtin_title =
56297c478bd9Sstevel@tonic-gate {
56307c478bd9Sstevel@tonic-gate   "title",
56317c478bd9Sstevel@tonic-gate   title_func,
56327c478bd9Sstevel@tonic-gate   BUILTIN_TITLE,
56337c478bd9Sstevel@tonic-gate #if 0
56347c478bd9Sstevel@tonic-gate   "title [NAME ...]",
56357c478bd9Sstevel@tonic-gate   "Start a new boot entry, and set its name to the contents of the"
56367c478bd9Sstevel@tonic-gate   " rest of the line, starting with the first non-space character."
56377c478bd9Sstevel@tonic-gate #endif
56387c478bd9Sstevel@tonic-gate };
56397c478bd9Sstevel@tonic-gate 
56407c478bd9Sstevel@tonic-gate 
56417c478bd9Sstevel@tonic-gate /* unhide */
56427c478bd9Sstevel@tonic-gate static int
56437c478bd9Sstevel@tonic-gate unhide_func (char *arg, int flags)
56447c478bd9Sstevel@tonic-gate {
56457c478bd9Sstevel@tonic-gate   if (! set_device (arg))
56467c478bd9Sstevel@tonic-gate     return 1;
56477c478bd9Sstevel@tonic-gate 
56487c478bd9Sstevel@tonic-gate   if (! set_partition_hidden_flag (0))
56497c478bd9Sstevel@tonic-gate     return 1;
56507c478bd9Sstevel@tonic-gate 
56517c478bd9Sstevel@tonic-gate   return 0;
56527c478bd9Sstevel@tonic-gate }
56537c478bd9Sstevel@tonic-gate 
56547c478bd9Sstevel@tonic-gate static struct builtin builtin_unhide =
56557c478bd9Sstevel@tonic-gate {
56567c478bd9Sstevel@tonic-gate   "unhide",
56577c478bd9Sstevel@tonic-gate   unhide_func,
56587c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
56597c478bd9Sstevel@tonic-gate   "unhide PARTITION",
56607c478bd9Sstevel@tonic-gate   "Unhide PARTITION by clearing the \"hidden\" bit in its"
56617c478bd9Sstevel@tonic-gate   " partition type code."
56627c478bd9Sstevel@tonic-gate };
56637c478bd9Sstevel@tonic-gate 
56647c478bd9Sstevel@tonic-gate 
56657c478bd9Sstevel@tonic-gate /* uppermem */
56667c478bd9Sstevel@tonic-gate static int
56677c478bd9Sstevel@tonic-gate uppermem_func (char *arg, int flags)
56687c478bd9Sstevel@tonic-gate {
56697c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, (int *) &mbi.mem_upper))
56707c478bd9Sstevel@tonic-gate     return 1;
56717c478bd9Sstevel@tonic-gate 
56727c478bd9Sstevel@tonic-gate   mbi.flags &= ~MB_INFO_MEM_MAP;
56737c478bd9Sstevel@tonic-gate   return 0;
56747c478bd9Sstevel@tonic-gate }
56757c478bd9Sstevel@tonic-gate 
56767c478bd9Sstevel@tonic-gate static struct builtin builtin_uppermem =
56777c478bd9Sstevel@tonic-gate {
56787c478bd9Sstevel@tonic-gate   "uppermem",
56797c478bd9Sstevel@tonic-gate   uppermem_func,
56807c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
56817c478bd9Sstevel@tonic-gate   "uppermem KBYTES",
56827c478bd9Sstevel@tonic-gate   "Force GRUB to assume that only KBYTES kilobytes of upper memory are"
56837c478bd9Sstevel@tonic-gate   " installed.  Any system address range maps are discarded."
56847c478bd9Sstevel@tonic-gate };
56857c478bd9Sstevel@tonic-gate 
56867c478bd9Sstevel@tonic-gate 
56877c478bd9Sstevel@tonic-gate /* vbeprobe */
56887c478bd9Sstevel@tonic-gate static int
56897c478bd9Sstevel@tonic-gate vbeprobe_func (char *arg, int flags)
56907c478bd9Sstevel@tonic-gate {
56917c478bd9Sstevel@tonic-gate   struct vbe_controller controller;
56927c478bd9Sstevel@tonic-gate   unsigned short *mode_list;
56937c478bd9Sstevel@tonic-gate   int mode_number = -1;
56947c478bd9Sstevel@tonic-gate 
56957c478bd9Sstevel@tonic-gate   auto unsigned long vbe_far_ptr_to_linear (unsigned long);
56967c478bd9Sstevel@tonic-gate 
56977c478bd9Sstevel@tonic-gate   unsigned long vbe_far_ptr_to_linear (unsigned long ptr)
56987c478bd9Sstevel@tonic-gate     {
56997c478bd9Sstevel@tonic-gate       unsigned short seg = (ptr >> 16);
57007c478bd9Sstevel@tonic-gate       unsigned short off = (ptr & 0xFFFF);
57017c478bd9Sstevel@tonic-gate 
57027c478bd9Sstevel@tonic-gate       return (seg << 4) + off;
57037c478bd9Sstevel@tonic-gate     }
57047c478bd9Sstevel@tonic-gate 
57057c478bd9Sstevel@tonic-gate   if (*arg)
57067c478bd9Sstevel@tonic-gate     {
57077c478bd9Sstevel@tonic-gate       if (! safe_parse_maxint (&arg, &mode_number))
57087c478bd9Sstevel@tonic-gate 	return 1;
57097c478bd9Sstevel@tonic-gate     }
57107c478bd9Sstevel@tonic-gate 
57117c478bd9Sstevel@tonic-gate   /* Set the signature to `VBE2', to obtain VBE 3.0 information.  */
57127c478bd9Sstevel@tonic-gate   grub_memmove (controller.signature, "VBE2", 4);
57137c478bd9Sstevel@tonic-gate 
57147c478bd9Sstevel@tonic-gate   if (get_vbe_controller_info (&controller) != 0x004F)
57157c478bd9Sstevel@tonic-gate     {
57167c478bd9Sstevel@tonic-gate       grub_printf (" VBE BIOS is not present.\n");
57177c478bd9Sstevel@tonic-gate       return 0;
57187c478bd9Sstevel@tonic-gate     }
57197c478bd9Sstevel@tonic-gate 
57207c478bd9Sstevel@tonic-gate   /* Check the version.  */
57217c478bd9Sstevel@tonic-gate   if (controller.version < 0x0200)
57227c478bd9Sstevel@tonic-gate     {
57237c478bd9Sstevel@tonic-gate       grub_printf (" VBE version %d.%d is not supported.\n",
57247c478bd9Sstevel@tonic-gate 		   (int) (controller.version >> 8),
57257c478bd9Sstevel@tonic-gate 		   (int) (controller.version & 0xFF));
57267c478bd9Sstevel@tonic-gate       return 0;
57277c478bd9Sstevel@tonic-gate     }
57287c478bd9Sstevel@tonic-gate 
57297c478bd9Sstevel@tonic-gate   /* Print some information.  */
57307c478bd9Sstevel@tonic-gate   grub_printf (" VBE version %d.%d\n",
57317c478bd9Sstevel@tonic-gate 	       (int) (controller.version >> 8),
57327c478bd9Sstevel@tonic-gate 	       (int) (controller.version & 0xFF));
57337c478bd9Sstevel@tonic-gate 
57347c478bd9Sstevel@tonic-gate   /* Iterate probing modes.  */
57357c478bd9Sstevel@tonic-gate   for (mode_list
57367c478bd9Sstevel@tonic-gate 	 = (unsigned short *) vbe_far_ptr_to_linear (controller.video_mode);
57377c478bd9Sstevel@tonic-gate        *mode_list != 0xFFFF;
57387c478bd9Sstevel@tonic-gate        mode_list++)
57397c478bd9Sstevel@tonic-gate     {
57407c478bd9Sstevel@tonic-gate       struct vbe_mode mode;
57417c478bd9Sstevel@tonic-gate 
57427c478bd9Sstevel@tonic-gate       if (get_vbe_mode_info (*mode_list, &mode) != 0x004F)
57437c478bd9Sstevel@tonic-gate 	continue;
57447c478bd9Sstevel@tonic-gate 
57457c478bd9Sstevel@tonic-gate       /* Skip this, if this is not supported or linear frame buffer
57467c478bd9Sstevel@tonic-gate 	 mode is not support.  */
57477c478bd9Sstevel@tonic-gate       if ((mode.mode_attributes & 0x0081) != 0x0081)
57487c478bd9Sstevel@tonic-gate 	continue;
57497c478bd9Sstevel@tonic-gate 
57507c478bd9Sstevel@tonic-gate       if (mode_number == -1 || mode_number == *mode_list)
57517c478bd9Sstevel@tonic-gate 	{
57527c478bd9Sstevel@tonic-gate 	  char *model;
57537c478bd9Sstevel@tonic-gate 	  switch (mode.memory_model)
57547c478bd9Sstevel@tonic-gate 	    {
57557c478bd9Sstevel@tonic-gate 	    case 0x00: model = "Text"; break;
57567c478bd9Sstevel@tonic-gate 	    case 0x01: model = "CGA graphics"; break;
57577c478bd9Sstevel@tonic-gate 	    case 0x02: model = "Hercules graphics"; break;
57587c478bd9Sstevel@tonic-gate 	    case 0x03: model = "Planar"; break;
57597c478bd9Sstevel@tonic-gate 	    case 0x04: model = "Packed pixel"; break;
57607c478bd9Sstevel@tonic-gate 	    case 0x05: model = "Non-chain 4, 256 color"; break;
57617c478bd9Sstevel@tonic-gate 	    case 0x06: model = "Direct Color"; break;
57627c478bd9Sstevel@tonic-gate 	    case 0x07: model = "YUV"; break;
57637c478bd9Sstevel@tonic-gate 	    default: model = "Unknown"; break;
57647c478bd9Sstevel@tonic-gate 	    }
57657c478bd9Sstevel@tonic-gate 
57667c478bd9Sstevel@tonic-gate 	  grub_printf ("  0x%x: %s, %ux%ux%u\n",
57677c478bd9Sstevel@tonic-gate 		       (unsigned) *mode_list,
57687c478bd9Sstevel@tonic-gate 		       model,
57697c478bd9Sstevel@tonic-gate 		       (unsigned) mode.x_resolution,
57707c478bd9Sstevel@tonic-gate 		       (unsigned) mode.y_resolution,
57717c478bd9Sstevel@tonic-gate 		       (unsigned) mode.bits_per_pixel);
57727c478bd9Sstevel@tonic-gate 
57737c478bd9Sstevel@tonic-gate 	  if (mode_number != -1)
57747c478bd9Sstevel@tonic-gate 	    break;
57757c478bd9Sstevel@tonic-gate 	}
57767c478bd9Sstevel@tonic-gate     }
57777c478bd9Sstevel@tonic-gate 
57787c478bd9Sstevel@tonic-gate   if (mode_number != -1 && mode_number != *mode_list)
57797c478bd9Sstevel@tonic-gate     grub_printf ("  Mode 0x%x is not found or supported.\n", mode_number);
57807c478bd9Sstevel@tonic-gate 
57817c478bd9Sstevel@tonic-gate   return 0;
57827c478bd9Sstevel@tonic-gate }
57837c478bd9Sstevel@tonic-gate 
57847c478bd9Sstevel@tonic-gate static struct builtin builtin_vbeprobe =
57857c478bd9Sstevel@tonic-gate {
57867c478bd9Sstevel@tonic-gate   "vbeprobe",
57877c478bd9Sstevel@tonic-gate   vbeprobe_func,
57887c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
57897c478bd9Sstevel@tonic-gate   "vbeprobe [MODE]",
57907c478bd9Sstevel@tonic-gate   "Probe VBE information. If the mode number MODE is specified, show only"
57917c478bd9Sstevel@tonic-gate   " the information about only the mode."
57927c478bd9Sstevel@tonic-gate };
57937c478bd9Sstevel@tonic-gate 
57947c478bd9Sstevel@tonic-gate 
57957c478bd9Sstevel@tonic-gate /* The table of builtin commands. Sorted in dictionary order.  */
57967c478bd9Sstevel@tonic-gate struct builtin *builtin_table[] =
57977c478bd9Sstevel@tonic-gate {
57987c478bd9Sstevel@tonic-gate #ifdef SUPPORT_GRAPHICS
57997c478bd9Sstevel@tonic-gate   &builtin_background,
58007c478bd9Sstevel@tonic-gate #endif
58017c478bd9Sstevel@tonic-gate   &builtin_blocklist,
58027c478bd9Sstevel@tonic-gate   &builtin_boot,
5803b1b8ab34Slling   &builtin_bootfs,
58047c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
58057c478bd9Sstevel@tonic-gate   &builtin_bootp,
58067c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
58077c478bd9Sstevel@tonic-gate   &builtin_cat,
58087c478bd9Sstevel@tonic-gate   &builtin_chainloader,
58097c478bd9Sstevel@tonic-gate   &builtin_clear,
58107c478bd9Sstevel@tonic-gate   &builtin_cmp,
58117c478bd9Sstevel@tonic-gate   &builtin_color,
58127c478bd9Sstevel@tonic-gate   &builtin_configfile,
58137c478bd9Sstevel@tonic-gate   &builtin_debug,
58147c478bd9Sstevel@tonic-gate   &builtin_default,
58157c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
58167c478bd9Sstevel@tonic-gate   &builtin_device,
58177c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
58187c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
58197c478bd9Sstevel@tonic-gate   &builtin_dhcp,
58207c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
58217c478bd9Sstevel@tonic-gate   &builtin_displayapm,
58227c478bd9Sstevel@tonic-gate   &builtin_displaymem,
58237c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
58247c478bd9Sstevel@tonic-gate   &builtin_dump,
58257c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
58267c478bd9Sstevel@tonic-gate   &builtin_embed,
58277c478bd9Sstevel@tonic-gate   &builtin_fallback,
58287c478bd9Sstevel@tonic-gate   &builtin_find,
5829eb2bd662Svikram   &builtin_findroot,
58307c478bd9Sstevel@tonic-gate #ifdef SUPPORT_GRAPHICS
58317c478bd9Sstevel@tonic-gate   &builtin_foreground,
58327c478bd9Sstevel@tonic-gate #endif
58337c478bd9Sstevel@tonic-gate   &builtin_fstest,
58347c478bd9Sstevel@tonic-gate   &builtin_geometry,
58357c478bd9Sstevel@tonic-gate   &builtin_halt,
58367c478bd9Sstevel@tonic-gate   &builtin_help,
58377c478bd9Sstevel@tonic-gate   &builtin_hiddenmenu,
58387c478bd9Sstevel@tonic-gate   &builtin_hide,
58397c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
58407c478bd9Sstevel@tonic-gate   &builtin_ifconfig,
58417c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
58427c478bd9Sstevel@tonic-gate   &builtin_impsprobe,
58437c478bd9Sstevel@tonic-gate   &builtin_initrd,
58447c478bd9Sstevel@tonic-gate   &builtin_install,
58457c478bd9Sstevel@tonic-gate   &builtin_ioprobe,
58467c478bd9Sstevel@tonic-gate   &builtin_kernel,
5847ae115bc7Smrj   &builtin_kernel_dollar,
58487c478bd9Sstevel@tonic-gate   &builtin_lock,
58497c478bd9Sstevel@tonic-gate   &builtin_makeactive,
58507c478bd9Sstevel@tonic-gate   &builtin_map,
58517c478bd9Sstevel@tonic-gate #ifdef USE_MD5_PASSWORDS
58527c478bd9Sstevel@tonic-gate   &builtin_md5crypt,
58537c478bd9Sstevel@tonic-gate #endif /* USE_MD5_PASSWORDS */
5854342440ecSPrasad Singamsetty   &builtin_min_mem64,
58557c478bd9Sstevel@tonic-gate   &builtin_module,
5856ae115bc7Smrj   &builtin_module_dollar,
58577c478bd9Sstevel@tonic-gate   &builtin_modulenounzip,
58587c478bd9Sstevel@tonic-gate   &builtin_pager,
58597c478bd9Sstevel@tonic-gate   &builtin_partnew,
58607c478bd9Sstevel@tonic-gate   &builtin_parttype,
58617c478bd9Sstevel@tonic-gate   &builtin_password,
58627c478bd9Sstevel@tonic-gate   &builtin_pause,
58637c478bd9Sstevel@tonic-gate #if defined(RPC_DEBUG) && defined(SUPPORT_NETBOOT)
58647c478bd9Sstevel@tonic-gate   &builtin_portmap,
58657c478bd9Sstevel@tonic-gate #endif /* RPC_DEBUG && SUPPORT_NETBOOT */
58667c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
58677c478bd9Sstevel@tonic-gate   &builtin_quit,
58687c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
58697c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
58707c478bd9Sstevel@tonic-gate   &builtin_rarp,
58717c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
58727c478bd9Sstevel@tonic-gate   &builtin_read,
58737c478bd9Sstevel@tonic-gate   &builtin_reboot,
58747c478bd9Sstevel@tonic-gate   &builtin_root,
58757c478bd9Sstevel@tonic-gate   &builtin_rootnoverify,
58767c478bd9Sstevel@tonic-gate   &builtin_savedefault,
58777c478bd9Sstevel@tonic-gate #ifdef SUPPORT_SERIAL
58787c478bd9Sstevel@tonic-gate   &builtin_serial,
58797c478bd9Sstevel@tonic-gate #endif /* SUPPORT_SERIAL */
58807c478bd9Sstevel@tonic-gate   &builtin_setkey,
58817c478bd9Sstevel@tonic-gate   &builtin_setup,
58827c478bd9Sstevel@tonic-gate #ifdef SUPPORT_GRAPHICS
58837c478bd9Sstevel@tonic-gate   &builtin_splashimage,
58847c478bd9Sstevel@tonic-gate #endif /* SUPPORT_GRAPHICS */
58857c478bd9Sstevel@tonic-gate #if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES) || defined(SUPPORT_GRAPHICS)
58867c478bd9Sstevel@tonic-gate   &builtin_terminal,
58877c478bd9Sstevel@tonic-gate #endif /* SUPPORT_SERIAL || SUPPORT_HERCULES || SUPPORT_GRAPHICS */
58887c478bd9Sstevel@tonic-gate #ifdef SUPPORT_SERIAL
58897c478bd9Sstevel@tonic-gate   &builtin_terminfo,
58907c478bd9Sstevel@tonic-gate #endif /* SUPPORT_SERIAL */
58917c478bd9Sstevel@tonic-gate   &builtin_testload,
58927c478bd9Sstevel@tonic-gate   &builtin_testvbe,
58937c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
58947c478bd9Sstevel@tonic-gate   &builtin_tftpserver,
58957c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
58967c478bd9Sstevel@tonic-gate   &builtin_timeout,
58977c478bd9Sstevel@tonic-gate   &builtin_title,
58987c478bd9Sstevel@tonic-gate   &builtin_unhide,
58997c478bd9Sstevel@tonic-gate   &builtin_uppermem,
59007c478bd9Sstevel@tonic-gate   &builtin_vbeprobe,
59011fac5a60Ssetje   &builtin_verbose,
59027c478bd9Sstevel@tonic-gate   0
59037c478bd9Sstevel@tonic-gate };
5904