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 
10587c478bd9Sstevel@tonic-gate     strcpy(splashimage, arg);
10597c478bd9Sstevel@tonic-gate 
1060*41c4174fSWilliam Kucharski     if (!graphics_set_splash(splashimage))
1061*41c4174fSWilliam Kucharski 	return 1;
1062*41c4174fSWilliam Kucharski 
10637c478bd9Sstevel@tonic-gate     /* get rid of TERM_NEED_INIT from the graphics terminal. */
10647c478bd9Sstevel@tonic-gate     for (i = 0; term_table[i].name; i++) {
10657c478bd9Sstevel@tonic-gate 	if (grub_strcmp (term_table[i].name, "graphics") == 0) {
10667c478bd9Sstevel@tonic-gate 	    term_table[i].flags &= ~TERM_NEED_INIT;
10677c478bd9Sstevel@tonic-gate 	    break;
10687c478bd9Sstevel@tonic-gate 	}
10697c478bd9Sstevel@tonic-gate     }
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate     if (flags == BUILTIN_CMDLINE && graphics_inited) {
10721fac5a60Ssetje 	/*
10731fac5a60Ssetje 	 * calling graphics_end() here flickers the screen black. OTOH not
10741fac5a60Ssetje 	 * calling it gets us odd plane interlacing / early palette switching ?
10751fac5a60Ssetje 	 * ideally one should figure out how to double buffer and switch...
10761fac5a60Ssetje 	 */
10777c478bd9Sstevel@tonic-gate 	graphics_end();
10787c478bd9Sstevel@tonic-gate 	graphics_init();
10797c478bd9Sstevel@tonic-gate 	graphics_cls();
10807c478bd9Sstevel@tonic-gate     }
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate     /* FIXME: should we be explicitly switching the terminal as a
10837c478bd9Sstevel@tonic-gate      * side effect here? */
10847c478bd9Sstevel@tonic-gate     terminal_func("graphics", flags);
10857c478bd9Sstevel@tonic-gate 
10861fac5a60Ssetje     reset_term = 0;
10871fac5a60Ssetje 
10887c478bd9Sstevel@tonic-gate     return 0;
10897c478bd9Sstevel@tonic-gate }
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate static struct builtin builtin_splashimage =
10927c478bd9Sstevel@tonic-gate {
10937c478bd9Sstevel@tonic-gate   "splashimage",
10947c478bd9Sstevel@tonic-gate   splashimage_func,
10951fac5a60Ssetje   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_SCRIPT | BUILTIN_HELP_LIST,
10967c478bd9Sstevel@tonic-gate   "splashimage FILE",
10977c478bd9Sstevel@tonic-gate   "Load FILE as the background image when in graphics mode."
10987c478bd9Sstevel@tonic-gate };
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 
11017c478bd9Sstevel@tonic-gate /* foreground */
11027c478bd9Sstevel@tonic-gate static int
11037c478bd9Sstevel@tonic-gate foreground_func(char *arg, int flags)
11047c478bd9Sstevel@tonic-gate {
11057c478bd9Sstevel@tonic-gate     if (grub_strlen(arg) == 6) {
11067c478bd9Sstevel@tonic-gate 	int r = ((hex(arg[0]) << 4) | hex(arg[1])) >> 2;
11077c478bd9Sstevel@tonic-gate 	int g = ((hex(arg[2]) << 4) | hex(arg[3])) >> 2;
11087c478bd9Sstevel@tonic-gate 	int b = ((hex(arg[4]) << 4) | hex(arg[5])) >> 2;
11097c478bd9Sstevel@tonic-gate 
11107c478bd9Sstevel@tonic-gate 	foreground = (r << 16) | (g << 8) | b;
11117c478bd9Sstevel@tonic-gate 	if (graphics_inited)
11127c478bd9Sstevel@tonic-gate 	    graphics_set_palette(15, r, g, b);
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate 	return (0);
11157c478bd9Sstevel@tonic-gate     }
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate     return (1);
11187c478bd9Sstevel@tonic-gate }
11197c478bd9Sstevel@tonic-gate 
11207c478bd9Sstevel@tonic-gate static struct builtin builtin_foreground =
11217c478bd9Sstevel@tonic-gate {
11227c478bd9Sstevel@tonic-gate   "foreground",
11237c478bd9Sstevel@tonic-gate   foreground_func,
112467ce1dadSJan Setje-Eilers   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST | BUILTIN_SCRIPT,
11257c478bd9Sstevel@tonic-gate   "foreground RRGGBB",
11267c478bd9Sstevel@tonic-gate   "Sets the foreground color when in graphics mode."
11277c478bd9Sstevel@tonic-gate   "RR is red, GG is green, and BB blue. Numbers must be in hexadecimal."
11287c478bd9Sstevel@tonic-gate };
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate 
11317c478bd9Sstevel@tonic-gate /* background */
11327c478bd9Sstevel@tonic-gate static int
11337c478bd9Sstevel@tonic-gate background_func(char *arg, int flags)
11347c478bd9Sstevel@tonic-gate {
11357c478bd9Sstevel@tonic-gate     if (grub_strlen(arg) == 6) {
11367c478bd9Sstevel@tonic-gate 	int r = ((hex(arg[0]) << 4) | hex(arg[1])) >> 2;
11377c478bd9Sstevel@tonic-gate 	int g = ((hex(arg[2]) << 4) | hex(arg[3])) >> 2;
11387c478bd9Sstevel@tonic-gate 	int b = ((hex(arg[4]) << 4) | hex(arg[5])) >> 2;
11397c478bd9Sstevel@tonic-gate 
11407c478bd9Sstevel@tonic-gate 	background = (r << 16) | (g << 8) | b;
11417c478bd9Sstevel@tonic-gate 	if (graphics_inited)
11427c478bd9Sstevel@tonic-gate 	    graphics_set_palette(0, r, g, b);
11437c478bd9Sstevel@tonic-gate 	return (0);
11447c478bd9Sstevel@tonic-gate     }
11457c478bd9Sstevel@tonic-gate 
11467c478bd9Sstevel@tonic-gate     return (1);
11477c478bd9Sstevel@tonic-gate }
11487c478bd9Sstevel@tonic-gate 
11497c478bd9Sstevel@tonic-gate static struct builtin builtin_background =
11507c478bd9Sstevel@tonic-gate {
11517c478bd9Sstevel@tonic-gate   "background",
11527c478bd9Sstevel@tonic-gate   background_func,
115367ce1dadSJan Setje-Eilers   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST | BUILTIN_SCRIPT,
11547c478bd9Sstevel@tonic-gate   "background RRGGBB",
11557c478bd9Sstevel@tonic-gate   "Sets the background color when in graphics mode."
11567c478bd9Sstevel@tonic-gate   "RR is red, GG is green, and BB blue. Numbers must be in hexadecimal."
11577c478bd9Sstevel@tonic-gate };
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate #endif /* SUPPORT_GRAPHICS */
11607c478bd9Sstevel@tonic-gate 
11617c478bd9Sstevel@tonic-gate 
11627c478bd9Sstevel@tonic-gate /* clear */
11637c478bd9Sstevel@tonic-gate static int
11647c478bd9Sstevel@tonic-gate clear_func()
11657c478bd9Sstevel@tonic-gate {
11667c478bd9Sstevel@tonic-gate   if (current_term->cls)
11677c478bd9Sstevel@tonic-gate     current_term->cls();
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate   return 0;
11707c478bd9Sstevel@tonic-gate }
11717c478bd9Sstevel@tonic-gate 
11727c478bd9Sstevel@tonic-gate static struct builtin builtin_clear =
11737c478bd9Sstevel@tonic-gate {
11747c478bd9Sstevel@tonic-gate   "clear",
11757c478bd9Sstevel@tonic-gate   clear_func,
11767c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
11777c478bd9Sstevel@tonic-gate   "clear",
11787c478bd9Sstevel@tonic-gate   "Clear the screen"
11797c478bd9Sstevel@tonic-gate };
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate /* displayapm */
11827c478bd9Sstevel@tonic-gate static int
11837c478bd9Sstevel@tonic-gate displayapm_func (char *arg, int flags)
11847c478bd9Sstevel@tonic-gate {
11857c478bd9Sstevel@tonic-gate   if (mbi.flags & MB_INFO_APM_TABLE)
11867c478bd9Sstevel@tonic-gate     {
11877c478bd9Sstevel@tonic-gate       grub_printf ("APM BIOS information:\n"
11887c478bd9Sstevel@tonic-gate 		   " Version:          0x%x\n"
11897c478bd9Sstevel@tonic-gate 		   " 32-bit CS:        0x%x\n"
11907c478bd9Sstevel@tonic-gate 		   " Offset:           0x%x\n"
11917c478bd9Sstevel@tonic-gate 		   " 16-bit CS:        0x%x\n"
11927c478bd9Sstevel@tonic-gate 		   " 16-bit DS:        0x%x\n"
11937c478bd9Sstevel@tonic-gate 		   " 32-bit CS length: 0x%x\n"
11947c478bd9Sstevel@tonic-gate 		   " 16-bit CS length: 0x%x\n"
11957c478bd9Sstevel@tonic-gate 		   " 16-bit DS length: 0x%x\n",
11967c478bd9Sstevel@tonic-gate 		   (unsigned) apm_bios_info.version,
11977c478bd9Sstevel@tonic-gate 		   (unsigned) apm_bios_info.cseg,
11987c478bd9Sstevel@tonic-gate 		   apm_bios_info.offset,
11997c478bd9Sstevel@tonic-gate 		   (unsigned) apm_bios_info.cseg_16,
12007c478bd9Sstevel@tonic-gate 		   (unsigned) apm_bios_info.dseg_16,
12017c478bd9Sstevel@tonic-gate 		   (unsigned) apm_bios_info.cseg_len,
12027c478bd9Sstevel@tonic-gate 		   (unsigned) apm_bios_info.cseg_16_len,
12037c478bd9Sstevel@tonic-gate 		   (unsigned) apm_bios_info.dseg_16_len);
12047c478bd9Sstevel@tonic-gate     }
12057c478bd9Sstevel@tonic-gate   else
12067c478bd9Sstevel@tonic-gate     {
12077c478bd9Sstevel@tonic-gate       grub_printf ("No APM BIOS found or probe failed\n");
12087c478bd9Sstevel@tonic-gate     }
12097c478bd9Sstevel@tonic-gate 
12107c478bd9Sstevel@tonic-gate   return 0;
12117c478bd9Sstevel@tonic-gate }
12127c478bd9Sstevel@tonic-gate 
12137c478bd9Sstevel@tonic-gate static struct builtin builtin_displayapm =
12147c478bd9Sstevel@tonic-gate {
12157c478bd9Sstevel@tonic-gate   "displayapm",
12167c478bd9Sstevel@tonic-gate   displayapm_func,
12177c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
12187c478bd9Sstevel@tonic-gate   "displayapm",
12197c478bd9Sstevel@tonic-gate   "Display APM BIOS information."
12207c478bd9Sstevel@tonic-gate };
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate 
12237c478bd9Sstevel@tonic-gate /* displaymem */
12247c478bd9Sstevel@tonic-gate static int
12257c478bd9Sstevel@tonic-gate displaymem_func (char *arg, int flags)
12267c478bd9Sstevel@tonic-gate {
12277c478bd9Sstevel@tonic-gate   if (get_eisamemsize () != -1)
12287c478bd9Sstevel@tonic-gate     grub_printf (" EISA Memory BIOS Interface is present\n");
12297c478bd9Sstevel@tonic-gate   if (get_mmap_entry ((void *) SCRATCHADDR, 0) != 0
12307c478bd9Sstevel@tonic-gate       || *((int *) SCRATCHADDR) != 0)
12317c478bd9Sstevel@tonic-gate     grub_printf (" Address Map BIOS Interface is present\n");
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate   grub_printf (" Lower memory: %uK, "
12347c478bd9Sstevel@tonic-gate 	       "Upper memory (to first chipset hole): %uK\n",
12357c478bd9Sstevel@tonic-gate 	       mbi.mem_lower, mbi.mem_upper);
12367c478bd9Sstevel@tonic-gate 
1237342440ecSPrasad Singamsetty   if (min_mem64 != 0)
1238342440ecSPrasad Singamsetty   	grub_printf (" Memory limit for 64-bit ISADIR expansion: %uMB\n",
1239342440ecSPrasad Singamsetty 	    min_mem64);
1240342440ecSPrasad Singamsetty 
12417c478bd9Sstevel@tonic-gate   if (mbi.flags & MB_INFO_MEM_MAP)
12427c478bd9Sstevel@tonic-gate     {
12437c478bd9Sstevel@tonic-gate       struct AddrRangeDesc *map = (struct AddrRangeDesc *) mbi.mmap_addr;
12447c478bd9Sstevel@tonic-gate       int end_addr = mbi.mmap_addr + mbi.mmap_length;
12457c478bd9Sstevel@tonic-gate 
12467c478bd9Sstevel@tonic-gate       grub_printf (" [Address Range Descriptor entries "
12477c478bd9Sstevel@tonic-gate 		   "immediately follow (values are 64-bit)]\n");
12487c478bd9Sstevel@tonic-gate       while (end_addr > (int) map)
12497c478bd9Sstevel@tonic-gate 	{
12507c478bd9Sstevel@tonic-gate 	  char *str;
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate 	  if (map->Type == MB_ARD_MEMORY)
12537c478bd9Sstevel@tonic-gate 	    str = "Usable RAM";
12547c478bd9Sstevel@tonic-gate 	  else
12557c478bd9Sstevel@tonic-gate 	    str = "Reserved";
12567c478bd9Sstevel@tonic-gate 	  grub_printf ("   %s:  Base Address:  0x%x X 4GB + 0x%x,\n"
1257342440ecSPrasad Singamsetty 		"      Length:   0x%x X 4GB + 0x%x bytes\n",
1258342440ecSPrasad Singamsetty 		str,
1259342440ecSPrasad Singamsetty 		(unsigned long) (map->BaseAddr >> 32),
1260342440ecSPrasad Singamsetty 		(unsigned long) (map->BaseAddr & 0xFFFFFFFF),
1261342440ecSPrasad Singamsetty 		(unsigned long) (map->Length >> 32),
1262342440ecSPrasad Singamsetty 		(unsigned long) (map->Length & 0xFFFFFFFF));
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate 	  map = ((struct AddrRangeDesc *) (((int) map) + 4 + map->size));
12657c478bd9Sstevel@tonic-gate 	}
12667c478bd9Sstevel@tonic-gate     }
12677c478bd9Sstevel@tonic-gate 
12687c478bd9Sstevel@tonic-gate   return 0;
12697c478bd9Sstevel@tonic-gate }
12707c478bd9Sstevel@tonic-gate 
12717c478bd9Sstevel@tonic-gate static struct builtin builtin_displaymem =
12727c478bd9Sstevel@tonic-gate {
12737c478bd9Sstevel@tonic-gate   "displaymem",
12747c478bd9Sstevel@tonic-gate   displaymem_func,
12757c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
12767c478bd9Sstevel@tonic-gate   "displaymem",
12777c478bd9Sstevel@tonic-gate   "Display what GRUB thinks the system address space map of the"
12787c478bd9Sstevel@tonic-gate   " machine is, including all regions of physical RAM installed."
12797c478bd9Sstevel@tonic-gate };
12807c478bd9Sstevel@tonic-gate 
12817c478bd9Sstevel@tonic-gate 
12827c478bd9Sstevel@tonic-gate /* dump FROM TO */
12837c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
12847c478bd9Sstevel@tonic-gate static int
12857c478bd9Sstevel@tonic-gate dump_func (char *arg, int flags)
12867c478bd9Sstevel@tonic-gate {
12877c478bd9Sstevel@tonic-gate   char *from, *to;
12887c478bd9Sstevel@tonic-gate   FILE *fp;
12897c478bd9Sstevel@tonic-gate   char c;
12907c478bd9Sstevel@tonic-gate 
12917c478bd9Sstevel@tonic-gate   from = arg;
12927c478bd9Sstevel@tonic-gate   to = skip_to (0, arg);
12937c478bd9Sstevel@tonic-gate   if (! *from || ! *to)
12947c478bd9Sstevel@tonic-gate     {
12957c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
12967c478bd9Sstevel@tonic-gate       return 1;
12977c478bd9Sstevel@tonic-gate     }
12987c478bd9Sstevel@tonic-gate 
12997c478bd9Sstevel@tonic-gate   nul_terminate (from);
13007c478bd9Sstevel@tonic-gate   nul_terminate (to);
13017c478bd9Sstevel@tonic-gate 
13027c478bd9Sstevel@tonic-gate   if (! grub_open (from))
13037c478bd9Sstevel@tonic-gate     return 1;
13047c478bd9Sstevel@tonic-gate 
13057c478bd9Sstevel@tonic-gate   fp = fopen (to, "w");
13067c478bd9Sstevel@tonic-gate   if (! fp)
13077c478bd9Sstevel@tonic-gate     {
13087c478bd9Sstevel@tonic-gate       errnum = ERR_WRITE;
13097c478bd9Sstevel@tonic-gate       return 1;
13107c478bd9Sstevel@tonic-gate     }
13117c478bd9Sstevel@tonic-gate 
13127c478bd9Sstevel@tonic-gate   while (grub_read (&c, 1))
13137c478bd9Sstevel@tonic-gate     if (fputc (c, fp) == EOF)
13147c478bd9Sstevel@tonic-gate       {
13157c478bd9Sstevel@tonic-gate 	errnum = ERR_WRITE;
13167c478bd9Sstevel@tonic-gate 	fclose (fp);
13177c478bd9Sstevel@tonic-gate 	return 1;
13187c478bd9Sstevel@tonic-gate       }
13197c478bd9Sstevel@tonic-gate 
13207c478bd9Sstevel@tonic-gate   if (fclose (fp) == EOF)
13217c478bd9Sstevel@tonic-gate     {
13227c478bd9Sstevel@tonic-gate       errnum = ERR_WRITE;
13237c478bd9Sstevel@tonic-gate       return 1;
13247c478bd9Sstevel@tonic-gate     }
13257c478bd9Sstevel@tonic-gate 
13267c478bd9Sstevel@tonic-gate   grub_close ();
13277c478bd9Sstevel@tonic-gate   return 0;
13287c478bd9Sstevel@tonic-gate }
13297c478bd9Sstevel@tonic-gate 
13307c478bd9Sstevel@tonic-gate static struct builtin builtin_dump =
13317c478bd9Sstevel@tonic-gate   {
13327c478bd9Sstevel@tonic-gate     "dump",
13337c478bd9Sstevel@tonic-gate     dump_func,
13347c478bd9Sstevel@tonic-gate     BUILTIN_CMDLINE,
13357c478bd9Sstevel@tonic-gate     "dump FROM TO",
13367c478bd9Sstevel@tonic-gate     "Dump the contents of the file FROM to the file TO. FROM must be"
13377c478bd9Sstevel@tonic-gate     " a GRUB file and TO must be an OS file."
13387c478bd9Sstevel@tonic-gate   };
13397c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
13407c478bd9Sstevel@tonic-gate 
13417c478bd9Sstevel@tonic-gate 
13427c478bd9Sstevel@tonic-gate static char embed_info[32];
13437c478bd9Sstevel@tonic-gate /* embed */
13447c478bd9Sstevel@tonic-gate /* Embed a Stage 1.5 in the first cylinder after MBR or in the
13457c478bd9Sstevel@tonic-gate    bootloader block in a FFS.  */
13467c478bd9Sstevel@tonic-gate static int
13477c478bd9Sstevel@tonic-gate embed_func (char *arg, int flags)
13487c478bd9Sstevel@tonic-gate {
13497c478bd9Sstevel@tonic-gate   char *stage1_5;
13507c478bd9Sstevel@tonic-gate   char *device;
13517c478bd9Sstevel@tonic-gate   char *stage1_5_buffer = (char *) RAW_ADDR (0x100000);
13527c478bd9Sstevel@tonic-gate   int len, size;
13537c478bd9Sstevel@tonic-gate   int sector;
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate   stage1_5 = arg;
13567c478bd9Sstevel@tonic-gate   device = skip_to (0, stage1_5);
13577c478bd9Sstevel@tonic-gate 
13587c478bd9Sstevel@tonic-gate   /* Open a Stage 1.5.  */
13597c478bd9Sstevel@tonic-gate   if (! grub_open (stage1_5))
13607c478bd9Sstevel@tonic-gate     return 1;
13617c478bd9Sstevel@tonic-gate 
13627c478bd9Sstevel@tonic-gate   /* Read the whole of the Stage 1.5.  */
13637c478bd9Sstevel@tonic-gate   len = grub_read (stage1_5_buffer, -1);
13647c478bd9Sstevel@tonic-gate   grub_close ();
13657c478bd9Sstevel@tonic-gate 
13667c478bd9Sstevel@tonic-gate   if (errnum)
13677c478bd9Sstevel@tonic-gate     return 1;
13687c478bd9Sstevel@tonic-gate 
13697c478bd9Sstevel@tonic-gate   size = (len + SECTOR_SIZE - 1) / SECTOR_SIZE;
13707c478bd9Sstevel@tonic-gate 
13717c478bd9Sstevel@tonic-gate   /* Get the device where the Stage 1.5 will be embedded.  */
13727c478bd9Sstevel@tonic-gate   set_device (device);
13737c478bd9Sstevel@tonic-gate   if (errnum)
13747c478bd9Sstevel@tonic-gate     return 1;
13757c478bd9Sstevel@tonic-gate 
13767c478bd9Sstevel@tonic-gate   if (current_partition == 0xFFFFFF)
13777c478bd9Sstevel@tonic-gate     {
13787c478bd9Sstevel@tonic-gate       /* Embed it after the MBR.  */
13797c478bd9Sstevel@tonic-gate 
13807c478bd9Sstevel@tonic-gate       char mbr[SECTOR_SIZE];
13817c478bd9Sstevel@tonic-gate       char ezbios_check[2*SECTOR_SIZE];
13827c478bd9Sstevel@tonic-gate       int i;
13837c478bd9Sstevel@tonic-gate 
13847c478bd9Sstevel@tonic-gate       /* Open the partition.  */
13857c478bd9Sstevel@tonic-gate       if (! open_partition ())
13867c478bd9Sstevel@tonic-gate 	return 1;
13877c478bd9Sstevel@tonic-gate 
13887c478bd9Sstevel@tonic-gate       /* No floppy has MBR.  */
13897c478bd9Sstevel@tonic-gate       if (! (current_drive & 0x80))
13907c478bd9Sstevel@tonic-gate 	{
13917c478bd9Sstevel@tonic-gate 	  errnum = ERR_DEV_VALUES;
13927c478bd9Sstevel@tonic-gate 	  return 1;
13937c478bd9Sstevel@tonic-gate 	}
13947c478bd9Sstevel@tonic-gate 
13957c478bd9Sstevel@tonic-gate       /* Read the MBR of CURRENT_DRIVE.  */
13967c478bd9Sstevel@tonic-gate       if (! rawread (current_drive, PC_MBR_SECTOR, 0, SECTOR_SIZE, mbr))
13977c478bd9Sstevel@tonic-gate 	return 1;
13987c478bd9Sstevel@tonic-gate 
13997c478bd9Sstevel@tonic-gate       /* Sanity check.  */
14007c478bd9Sstevel@tonic-gate       if (! PC_MBR_CHECK_SIG (mbr))
14017c478bd9Sstevel@tonic-gate 	{
14027c478bd9Sstevel@tonic-gate 	  errnum = ERR_BAD_PART_TABLE;
14037c478bd9Sstevel@tonic-gate 	  return 1;
14047c478bd9Sstevel@tonic-gate 	}
14057c478bd9Sstevel@tonic-gate 
14067c478bd9Sstevel@tonic-gate       /* Check if the disk can store the Stage 1.5.  */
14077c478bd9Sstevel@tonic-gate       for (i = 0; i < 4; i++)
14087c478bd9Sstevel@tonic-gate 	if (PC_SLICE_TYPE (mbr, i) && PC_SLICE_START (mbr, i) - 1 < size)
14097c478bd9Sstevel@tonic-gate 	  {
14107c478bd9Sstevel@tonic-gate 	    errnum = ERR_NO_DISK_SPACE;
14117c478bd9Sstevel@tonic-gate 	    return 1;
14127c478bd9Sstevel@tonic-gate 	  }
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate       /* Check for EZ-BIOS signature. It should be in the third
14157c478bd9Sstevel@tonic-gate        * sector, but due to remapping it can appear in the second, so
14167c478bd9Sstevel@tonic-gate        * load and check both.
14177c478bd9Sstevel@tonic-gate        */
14187c478bd9Sstevel@tonic-gate       if (! rawread (current_drive, 1, 0, 2 * SECTOR_SIZE, ezbios_check))
14197c478bd9Sstevel@tonic-gate 	return 1;
14207c478bd9Sstevel@tonic-gate 
14217c478bd9Sstevel@tonic-gate       if (! memcmp (ezbios_check + 3, "AERMH", 5)
14227c478bd9Sstevel@tonic-gate 	  || ! memcmp (ezbios_check + 512 + 3, "AERMH", 5))
14237c478bd9Sstevel@tonic-gate 	{
14247c478bd9Sstevel@tonic-gate 	  /* The space after the MBR is used by EZ-BIOS which we must
14257c478bd9Sstevel@tonic-gate 	   * not overwrite.
14267c478bd9Sstevel@tonic-gate 	   */
14277c478bd9Sstevel@tonic-gate 	  errnum = ERR_NO_DISK_SPACE;
14287c478bd9Sstevel@tonic-gate 	  return 1;
14297c478bd9Sstevel@tonic-gate 	}
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate       sector = 1;
14327c478bd9Sstevel@tonic-gate     }
14337c478bd9Sstevel@tonic-gate   else
14347c478bd9Sstevel@tonic-gate     {
14357c478bd9Sstevel@tonic-gate       /* Embed it in the bootloader block in the filesystem.  */
14367c478bd9Sstevel@tonic-gate       int start_sector;
14377c478bd9Sstevel@tonic-gate 
14387c478bd9Sstevel@tonic-gate       /* Open the partition.  */
14397c478bd9Sstevel@tonic-gate       if (! open_device ())
14407c478bd9Sstevel@tonic-gate 	return 1;
14417c478bd9Sstevel@tonic-gate 
14427c478bd9Sstevel@tonic-gate       /* Check if the current slice supports embedding.  */
14437c478bd9Sstevel@tonic-gate       if (fsys_table[fsys_type].embed_func == 0
14447c478bd9Sstevel@tonic-gate 	  || ! fsys_table[fsys_type].embed_func (&start_sector, size))
14457c478bd9Sstevel@tonic-gate 	{
14467c478bd9Sstevel@tonic-gate 	  errnum = ERR_DEV_VALUES;
14477c478bd9Sstevel@tonic-gate 	  return 1;
14487c478bd9Sstevel@tonic-gate 	}
14497c478bd9Sstevel@tonic-gate 
14507c478bd9Sstevel@tonic-gate       sector = part_start + start_sector;
14517c478bd9Sstevel@tonic-gate     }
14527c478bd9Sstevel@tonic-gate 
14537c478bd9Sstevel@tonic-gate   /* Clear the cache.  */
1454342440ecSPrasad Singamsetty   buf_track = BUF_CACHE_INVALID;
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate   /* Now perform the embedding.  */
14577c478bd9Sstevel@tonic-gate   if (! devwrite (sector - part_start, size, stage1_5_buffer))
14587c478bd9Sstevel@tonic-gate     return 1;
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate   grub_printf (" %d sectors are embedded.\n", size);
14617c478bd9Sstevel@tonic-gate   grub_sprintf (embed_info, "%d+%d", sector - part_start, size);
14627c478bd9Sstevel@tonic-gate   return 0;
14637c478bd9Sstevel@tonic-gate }
14647c478bd9Sstevel@tonic-gate 
14657c478bd9Sstevel@tonic-gate static struct builtin builtin_embed =
14667c478bd9Sstevel@tonic-gate {
14677c478bd9Sstevel@tonic-gate   "embed",
14687c478bd9Sstevel@tonic-gate   embed_func,
14697c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
14707c478bd9Sstevel@tonic-gate   "embed STAGE1_5 DEVICE",
14717c478bd9Sstevel@tonic-gate   "Embed the Stage 1.5 STAGE1_5 in the sectors after MBR if DEVICE"
14727c478bd9Sstevel@tonic-gate   " is a drive, or in the \"bootloader\" area if DEVICE is a FFS partition."
14737c478bd9Sstevel@tonic-gate   " Print the number of sectors which STAGE1_5 occupies if successful."
14747c478bd9Sstevel@tonic-gate };
14757c478bd9Sstevel@tonic-gate 
14767c478bd9Sstevel@tonic-gate 
14777c478bd9Sstevel@tonic-gate /* fallback */
14787c478bd9Sstevel@tonic-gate static int
14797c478bd9Sstevel@tonic-gate fallback_func (char *arg, int flags)
14807c478bd9Sstevel@tonic-gate {
14817c478bd9Sstevel@tonic-gate   int i = 0;
14827c478bd9Sstevel@tonic-gate 
14837c478bd9Sstevel@tonic-gate   while (*arg)
14847c478bd9Sstevel@tonic-gate     {
14857c478bd9Sstevel@tonic-gate       int entry;
14867c478bd9Sstevel@tonic-gate       int j;
14877c478bd9Sstevel@tonic-gate 
14887c478bd9Sstevel@tonic-gate       if (! safe_parse_maxint (&arg, &entry))
14897c478bd9Sstevel@tonic-gate 	return 1;
14907c478bd9Sstevel@tonic-gate 
14917c478bd9Sstevel@tonic-gate       /* Remove duplications to prevent infinite looping.  */
14927c478bd9Sstevel@tonic-gate       for (j = 0; j < i; j++)
14937c478bd9Sstevel@tonic-gate 	if (entry == fallback_entries[j])
14947c478bd9Sstevel@tonic-gate 	  break;
14957c478bd9Sstevel@tonic-gate       if (j != i)
14967c478bd9Sstevel@tonic-gate 	continue;
14977c478bd9Sstevel@tonic-gate 
14987c478bd9Sstevel@tonic-gate       fallback_entries[i++] = entry;
14997c478bd9Sstevel@tonic-gate       if (i == MAX_FALLBACK_ENTRIES)
15007c478bd9Sstevel@tonic-gate 	break;
15017c478bd9Sstevel@tonic-gate 
15027c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
15037c478bd9Sstevel@tonic-gate     }
15047c478bd9Sstevel@tonic-gate 
15057c478bd9Sstevel@tonic-gate   if (i < MAX_FALLBACK_ENTRIES)
15067c478bd9Sstevel@tonic-gate     fallback_entries[i] = -1;
15077c478bd9Sstevel@tonic-gate 
15087c478bd9Sstevel@tonic-gate   fallback_entryno = (i == 0) ? -1 : 0;
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate   return 0;
15117c478bd9Sstevel@tonic-gate }
15127c478bd9Sstevel@tonic-gate 
15137c478bd9Sstevel@tonic-gate static struct builtin builtin_fallback =
15147c478bd9Sstevel@tonic-gate {
15157c478bd9Sstevel@tonic-gate   "fallback",
15167c478bd9Sstevel@tonic-gate   fallback_func,
15177c478bd9Sstevel@tonic-gate   BUILTIN_MENU,
15187c478bd9Sstevel@tonic-gate #if 0
15197c478bd9Sstevel@tonic-gate   "fallback NUM...",
15207c478bd9Sstevel@tonic-gate   "Go into unattended boot mode: if the default boot entry has any"
15217c478bd9Sstevel@tonic-gate   " errors, instead of waiting for the user to do anything, it"
15227c478bd9Sstevel@tonic-gate   " immediately starts over using the NUM entry (same numbering as the"
15237c478bd9Sstevel@tonic-gate   " `default' command). This obviously won't help if the machine"
15247c478bd9Sstevel@tonic-gate   " was rebooted by a kernel that GRUB loaded."
15257c478bd9Sstevel@tonic-gate #endif
15267c478bd9Sstevel@tonic-gate };
15277c478bd9Sstevel@tonic-gate 
15287c478bd9Sstevel@tonic-gate 
1529051aabe6Staylor 
1530051aabe6Staylor void
1531051aabe6Staylor set_root (char *root, unsigned long drive, unsigned long part)
1532051aabe6Staylor {
1533051aabe6Staylor   int bsd_part = (part >> 8) & 0xFF;
1534051aabe6Staylor   int pc_slice = part >> 16;
1535051aabe6Staylor 
1536051aabe6Staylor   if (bsd_part == 0xFF) {
1537051aabe6Staylor     grub_sprintf (root, "(hd%d,%d)\n", drive - 0x80, pc_slice);
1538051aabe6Staylor   } else {
1539051aabe6Staylor     grub_sprintf (root, "(hd%d,%d,%c)\n",
1540051aabe6Staylor 		 drive - 0x80, pc_slice, bsd_part + 'a');
1541051aabe6Staylor   }
1542051aabe6Staylor }
1543051aabe6Staylor 
15447c478bd9Sstevel@tonic-gate static int
1545eb2bd662Svikram find_common (char *arg, char *root, int for_root, int flags)
15467c478bd9Sstevel@tonic-gate {
1547eb2bd662Svikram   char *filename = NULL;
1548eb2bd662Svikram   static char argpart[32];
1549eb2bd662Svikram   static char device[32];
1550eb2bd662Svikram   char *tmp_argpart = NULL;
15517c478bd9Sstevel@tonic-gate   unsigned long drive;
15527c478bd9Sstevel@tonic-gate   unsigned long tmp_drive = saved_drive;
15537c478bd9Sstevel@tonic-gate   unsigned long tmp_partition = saved_partition;
15547c478bd9Sstevel@tonic-gate   int got_file = 0;
1555eb2bd662Svikram   static char bootsign[BOOTSIGN_LEN];
1556eb2bd662Svikram 
1557eb2bd662Svikram   /*
1558eb2bd662Svikram    * If argument has partition information (findroot command only), then
1559eb2bd662Svikram    * it can't be a floppy
1560eb2bd662Svikram    */
1561eb2bd662Svikram   if (for_root && arg[0] == '(') {
1562eb2bd662Svikram 	tmp_argpart = grub_strchr(arg + 1, ',');
1563eb2bd662Svikram         if (tmp_argpart == NULL)
1564eb2bd662Svikram 		goto out;
1565eb2bd662Svikram 	grub_strcpy(argpart, tmp_argpart);
1566eb2bd662Svikram 	*tmp_argpart = '\0';
1567eb2bd662Svikram 	arg++;
1568eb2bd662Svikram         grub_sprintf(bootsign, "%s/%s", BOOTSIGN_DIR, arg);
1569eb2bd662Svikram 	filename = bootsign;
1570eb2bd662Svikram 	goto harddisk;
1571eb2bd662Svikram   } else if (for_root) {
1572eb2bd662Svikram 	/* Boot signature without partition/slice information */
1573eb2bd662Svikram         grub_sprintf(bootsign, "%s/%s", BOOTSIGN_DIR, arg);
1574eb2bd662Svikram 	filename = bootsign;
1575eb2bd662Svikram   } else {
1576eb2bd662Svikram 	/* plain vanilla find cmd */
1577eb2bd662Svikram 	filename = arg;
1578eb2bd662Svikram   }
15797c478bd9Sstevel@tonic-gate 
15807c478bd9Sstevel@tonic-gate   /* Floppies.  */
15817c478bd9Sstevel@tonic-gate   for (drive = 0; drive < 8; drive++)
15827c478bd9Sstevel@tonic-gate     {
15837c478bd9Sstevel@tonic-gate       current_drive = drive;
15847c478bd9Sstevel@tonic-gate       current_partition = 0xFFFFFF;
15857c478bd9Sstevel@tonic-gate 
15867c478bd9Sstevel@tonic-gate       if (open_device ())
15877c478bd9Sstevel@tonic-gate 	{
15887c478bd9Sstevel@tonic-gate 	  saved_drive = current_drive;
15897c478bd9Sstevel@tonic-gate 	  saved_partition = current_partition;
15907c478bd9Sstevel@tonic-gate 	  if (grub_open (filename))
15917c478bd9Sstevel@tonic-gate 	    {
15927c478bd9Sstevel@tonic-gate 	      grub_close ();
15937c478bd9Sstevel@tonic-gate 	      got_file = 1;
1594eb2bd662Svikram 	      if (for_root) {
1595eb2bd662Svikram 		 grub_sprintf(root, "(fd%d)", drive);
1596eb2bd662Svikram 		 goto out;
1597eb2bd662Svikram 	      } else
1598eb2bd662Svikram 	         grub_printf (" (fd%d)\n", drive);
15997c478bd9Sstevel@tonic-gate 	    }
16007c478bd9Sstevel@tonic-gate 	}
16017c478bd9Sstevel@tonic-gate 
16027c478bd9Sstevel@tonic-gate       errnum = ERR_NONE;
16037c478bd9Sstevel@tonic-gate     }
16047c478bd9Sstevel@tonic-gate 
1605eb2bd662Svikram harddisk:
16067c478bd9Sstevel@tonic-gate   /* Hard disks.  */
16077c478bd9Sstevel@tonic-gate   for (drive = 0x80; drive < 0x88; drive++)
16087c478bd9Sstevel@tonic-gate     {
16097c478bd9Sstevel@tonic-gate       unsigned long part = 0xFFFFFF;
16107c478bd9Sstevel@tonic-gate       unsigned long start, len, offset, ext_offset;
16117c478bd9Sstevel@tonic-gate       int type, entry;
16127c478bd9Sstevel@tonic-gate       char buf[SECTOR_SIZE];
16137c478bd9Sstevel@tonic-gate 
1614eb2bd662Svikram       if (for_root && tmp_argpart) {
1615051aabe6Staylor 	grub_sprintf(device, "(hd%d%s", drive - 0x80, argpart);
1616eb2bd662Svikram 	set_device(device);
1617eb2bd662Svikram         errnum = ERR_NONE;
1618eb2bd662Svikram 	part = current_partition;
1619eb2bd662Svikram 	if (open_device ()) {
1620eb2bd662Svikram 	   saved_drive = current_drive;
1621eb2bd662Svikram 	   saved_partition = current_partition;
1622eb2bd662Svikram            errnum = ERR_NONE;
1623eb2bd662Svikram 	   if (grub_open (filename)) {
1624eb2bd662Svikram 	      grub_close ();
1625eb2bd662Svikram 	      got_file = 1;
1626051aabe6Staylor 	      if (is_zfs_mount == 0) {
1627051aabe6Staylor 	        set_root(root, current_drive, current_partition);
1628051aabe6Staylor 	        goto out;
1629051aabe6Staylor 	      } else {
1630051aabe6Staylor 		best_drive = current_drive;
1631051aabe6Staylor 		best_part = current_partition;
1632051aabe6Staylor 	      }
1633eb2bd662Svikram            }
1634eb2bd662Svikram 	}
1635eb2bd662Svikram         errnum = ERR_NONE;
1636eb2bd662Svikram 	continue;
1637eb2bd662Svikram       }
16387c478bd9Sstevel@tonic-gate       current_drive = drive;
16397c478bd9Sstevel@tonic-gate       while (next_partition (drive, 0xFFFFFF, &part, &type,
16407c478bd9Sstevel@tonic-gate 			     &start, &len, &offset, &entry,
16417c478bd9Sstevel@tonic-gate 			     &ext_offset, buf))
16427c478bd9Sstevel@tonic-gate 	{
16437c478bd9Sstevel@tonic-gate 	  if (type != PC_SLICE_TYPE_NONE
16447c478bd9Sstevel@tonic-gate 	      && ! IS_PC_SLICE_TYPE_BSD (type)
16457c478bd9Sstevel@tonic-gate 	      && ! IS_PC_SLICE_TYPE_EXTENDED (type))
16467c478bd9Sstevel@tonic-gate 	    {
16477c478bd9Sstevel@tonic-gate 	      current_partition = part;
16487c478bd9Sstevel@tonic-gate 	      if (open_device ())
16497c478bd9Sstevel@tonic-gate 		{
16507c478bd9Sstevel@tonic-gate 		  saved_drive = current_drive;
16517c478bd9Sstevel@tonic-gate 		  saved_partition = current_partition;
16527c478bd9Sstevel@tonic-gate 		  if (grub_open (filename))
16537c478bd9Sstevel@tonic-gate 		    {
1654051aabe6Staylor 		      char tmproot[32];
1655051aabe6Staylor 
16567c478bd9Sstevel@tonic-gate 		      grub_close ();
1657eb2bd662Svikram 		      got_file = 1;
1658051aabe6Staylor 		      set_root(tmproot, drive, part);
1659051aabe6Staylor 		      if (for_root) {
1660051aabe6Staylor 		 	grub_memcpy(root, tmproot, sizeof(tmproot));
1661051aabe6Staylor 			if (is_zfs_mount == 0) {
1662051aabe6Staylor 			      goto out;
1663051aabe6Staylor 			} else {
1664051aabe6Staylor 			      best_drive = current_drive;
1665051aabe6Staylor 			      best_part = current_partition;
1666051aabe6Staylor 			}
1667eb2bd662Svikram 		      } else {
1668051aabe6Staylor 			grub_printf("%s", tmproot);
1669eb2bd662Svikram 		      }
16707c478bd9Sstevel@tonic-gate 		    }
16717c478bd9Sstevel@tonic-gate 		}
16727c478bd9Sstevel@tonic-gate 	    }
16737c478bd9Sstevel@tonic-gate 
16747c478bd9Sstevel@tonic-gate 	  /* We want to ignore any error here.  */
16757c478bd9Sstevel@tonic-gate 	  errnum = ERR_NONE;
16767c478bd9Sstevel@tonic-gate 	}
16777c478bd9Sstevel@tonic-gate 
16787c478bd9Sstevel@tonic-gate       /* next_partition always sets ERRNUM in the last call, so clear
16797c478bd9Sstevel@tonic-gate 	 it.  */
16807c478bd9Sstevel@tonic-gate       errnum = ERR_NONE;
16817c478bd9Sstevel@tonic-gate     }
16827c478bd9Sstevel@tonic-gate 
1683eb2bd662Svikram out:
1684051aabe6Staylor   if (is_zfs_mount && for_root) {
1685051aabe6Staylor         set_root(root, best_drive, best_part);
1686051aabe6Staylor 	buf_drive = -1;
1687051aabe6Staylor   } else {
1688051aabe6Staylor 	saved_drive = tmp_drive;
1689051aabe6Staylor 	saved_partition = tmp_partition;
1690051aabe6Staylor   }
1691eb2bd662Svikram   if (tmp_argpart)
1692eb2bd662Svikram 	*tmp_argpart = ',';
16937c478bd9Sstevel@tonic-gate 
16947c478bd9Sstevel@tonic-gate   if (got_file)
16957c478bd9Sstevel@tonic-gate     {
16967c478bd9Sstevel@tonic-gate       errnum = ERR_NONE;
16977c478bd9Sstevel@tonic-gate       return 0;
16987c478bd9Sstevel@tonic-gate     }
16997c478bd9Sstevel@tonic-gate 
17007c478bd9Sstevel@tonic-gate   errnum = ERR_FILE_NOT_FOUND;
17017c478bd9Sstevel@tonic-gate   return 1;
17027c478bd9Sstevel@tonic-gate }
17037c478bd9Sstevel@tonic-gate 
1704eb2bd662Svikram /* find */
1705eb2bd662Svikram /* Search for the filename ARG in all of partitions.  */
1706eb2bd662Svikram static int
1707eb2bd662Svikram find_func (char *arg, int flags)
1708eb2bd662Svikram {
1709eb2bd662Svikram 	return (find_common(arg, NULL, 0, flags));
1710eb2bd662Svikram }
1711eb2bd662Svikram 
17127c478bd9Sstevel@tonic-gate static struct builtin builtin_find =
17137c478bd9Sstevel@tonic-gate {
17147c478bd9Sstevel@tonic-gate   "find",
17157c478bd9Sstevel@tonic-gate   find_func,
17167c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
17177c478bd9Sstevel@tonic-gate   "find FILENAME",
17187c478bd9Sstevel@tonic-gate   "Search for the filename FILENAME in all of partitions and print the list of"
17197c478bd9Sstevel@tonic-gate   " the devices which contain the file."
17207c478bd9Sstevel@tonic-gate };
17217c478bd9Sstevel@tonic-gate 
17227c478bd9Sstevel@tonic-gate 
17237c478bd9Sstevel@tonic-gate /* fstest */
17247c478bd9Sstevel@tonic-gate static int
17257c478bd9Sstevel@tonic-gate fstest_func (char *arg, int flags)
17267c478bd9Sstevel@tonic-gate {
17277c478bd9Sstevel@tonic-gate   if (disk_read_hook)
17287c478bd9Sstevel@tonic-gate     {
17297c478bd9Sstevel@tonic-gate       disk_read_hook = NULL;
17307c478bd9Sstevel@tonic-gate       printf (" Filesystem tracing is now off\n");
17317c478bd9Sstevel@tonic-gate     }
17327c478bd9Sstevel@tonic-gate   else
17337c478bd9Sstevel@tonic-gate     {
17347c478bd9Sstevel@tonic-gate       disk_read_hook = disk_read_print_func;
17357c478bd9Sstevel@tonic-gate       printf (" Filesystem tracing is now on\n");
17367c478bd9Sstevel@tonic-gate     }
17377c478bd9Sstevel@tonic-gate 
17387c478bd9Sstevel@tonic-gate   return 0;
17397c478bd9Sstevel@tonic-gate }
17407c478bd9Sstevel@tonic-gate 
17417c478bd9Sstevel@tonic-gate static struct builtin builtin_fstest =
17427c478bd9Sstevel@tonic-gate {
17437c478bd9Sstevel@tonic-gate   "fstest",
17447c478bd9Sstevel@tonic-gate   fstest_func,
17457c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
17467c478bd9Sstevel@tonic-gate   "fstest",
17477c478bd9Sstevel@tonic-gate   "Toggle filesystem test mode."
17487c478bd9Sstevel@tonic-gate };
17497c478bd9Sstevel@tonic-gate 
17507c478bd9Sstevel@tonic-gate 
17517c478bd9Sstevel@tonic-gate /* geometry */
17527c478bd9Sstevel@tonic-gate static int
17537c478bd9Sstevel@tonic-gate geometry_func (char *arg, int flags)
17547c478bd9Sstevel@tonic-gate {
17557c478bd9Sstevel@tonic-gate   struct geometry geom;
17567c478bd9Sstevel@tonic-gate   char *msg;
17577c478bd9Sstevel@tonic-gate   char *device = arg;
17587c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
17597c478bd9Sstevel@tonic-gate   char *ptr;
17607c478bd9Sstevel@tonic-gate #endif
17617c478bd9Sstevel@tonic-gate 
17627c478bd9Sstevel@tonic-gate   /* Get the device number.  */
17637c478bd9Sstevel@tonic-gate   set_device (device);
17647c478bd9Sstevel@tonic-gate   if (errnum)
17657c478bd9Sstevel@tonic-gate     return 1;
17667c478bd9Sstevel@tonic-gate 
17677c478bd9Sstevel@tonic-gate   /* Check for the geometry.  */
17687c478bd9Sstevel@tonic-gate   if (get_diskinfo (current_drive, &geom))
17697c478bd9Sstevel@tonic-gate     {
17707c478bd9Sstevel@tonic-gate       errnum = ERR_NO_DISK;
17717c478bd9Sstevel@tonic-gate       return 1;
17727c478bd9Sstevel@tonic-gate     }
17737c478bd9Sstevel@tonic-gate 
17747c478bd9Sstevel@tonic-gate   /* Attempt to read the first sector, because some BIOSes turns out not
17757c478bd9Sstevel@tonic-gate      to support LBA even though they set the bit 0 in the support
17767c478bd9Sstevel@tonic-gate      bitmap, only after reading something actually.  */
17777c478bd9Sstevel@tonic-gate   if (biosdisk (BIOSDISK_READ, current_drive, &geom, 0, 1, SCRATCHSEG))
17787c478bd9Sstevel@tonic-gate     {
17797c478bd9Sstevel@tonic-gate       errnum = ERR_READ;
17807c478bd9Sstevel@tonic-gate       return 1;
17817c478bd9Sstevel@tonic-gate     }
17827c478bd9Sstevel@tonic-gate 
17837c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
17847c478bd9Sstevel@tonic-gate   ptr = skip_to (0, device);
17857c478bd9Sstevel@tonic-gate   if (*ptr)
17867c478bd9Sstevel@tonic-gate     {
17877c478bd9Sstevel@tonic-gate       char *cylinder, *head, *sector, *total_sector;
17887c478bd9Sstevel@tonic-gate       int num_cylinder, num_head, num_sector, num_total_sector;
17897c478bd9Sstevel@tonic-gate 
17907c478bd9Sstevel@tonic-gate       cylinder = ptr;
17917c478bd9Sstevel@tonic-gate       head = skip_to (0, cylinder);
17927c478bd9Sstevel@tonic-gate       sector = skip_to (0, head);
17937c478bd9Sstevel@tonic-gate       total_sector = skip_to (0, sector);
17947c478bd9Sstevel@tonic-gate       if (! safe_parse_maxint (&cylinder, &num_cylinder)
17957c478bd9Sstevel@tonic-gate 	  || ! safe_parse_maxint (&head, &num_head)
17967c478bd9Sstevel@tonic-gate 	  || ! safe_parse_maxint (&sector, &num_sector))
17977c478bd9Sstevel@tonic-gate 	return 1;
17987c478bd9Sstevel@tonic-gate 
17997c478bd9Sstevel@tonic-gate       disks[current_drive].cylinders = num_cylinder;
18007c478bd9Sstevel@tonic-gate       disks[current_drive].heads = num_head;
18017c478bd9Sstevel@tonic-gate       disks[current_drive].sectors = num_sector;
18027c478bd9Sstevel@tonic-gate 
18037c478bd9Sstevel@tonic-gate       if (safe_parse_maxint (&total_sector, &num_total_sector))
18047c478bd9Sstevel@tonic-gate 	disks[current_drive].total_sectors = num_total_sector;
18057c478bd9Sstevel@tonic-gate       else
18067c478bd9Sstevel@tonic-gate 	disks[current_drive].total_sectors
18077c478bd9Sstevel@tonic-gate 	  = num_cylinder * num_head * num_sector;
18087c478bd9Sstevel@tonic-gate       errnum = 0;
18097c478bd9Sstevel@tonic-gate 
18107c478bd9Sstevel@tonic-gate       geom = disks[current_drive];
18117c478bd9Sstevel@tonic-gate       buf_drive = -1;
18127c478bd9Sstevel@tonic-gate     }
18137c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
18147c478bd9Sstevel@tonic-gate 
18157c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
18167c478bd9Sstevel@tonic-gate   msg = device_map[current_drive];
18177c478bd9Sstevel@tonic-gate #else
18187c478bd9Sstevel@tonic-gate   if (geom.flags & BIOSDISK_FLAG_LBA_EXTENSION)
18197c478bd9Sstevel@tonic-gate     msg = "LBA";
18207c478bd9Sstevel@tonic-gate   else
18217c478bd9Sstevel@tonic-gate     msg = "CHS";
18227c478bd9Sstevel@tonic-gate #endif
18237c478bd9Sstevel@tonic-gate 
18247c478bd9Sstevel@tonic-gate   grub_printf ("drive 0x%x: C/H/S = %d/%d/%d, "
1825342440ecSPrasad Singamsetty 	       "The number of sectors = %u, %s\n",
18267c478bd9Sstevel@tonic-gate 	       current_drive,
18277c478bd9Sstevel@tonic-gate 	       geom.cylinders, geom.heads, geom.sectors,
18287c478bd9Sstevel@tonic-gate 	       geom.total_sectors, msg);
18297c478bd9Sstevel@tonic-gate   real_open_partition (1);
18307c478bd9Sstevel@tonic-gate 
18317c478bd9Sstevel@tonic-gate   return 0;
18327c478bd9Sstevel@tonic-gate }
18337c478bd9Sstevel@tonic-gate 
18347c478bd9Sstevel@tonic-gate static struct builtin builtin_geometry =
18357c478bd9Sstevel@tonic-gate {
18367c478bd9Sstevel@tonic-gate   "geometry",
18377c478bd9Sstevel@tonic-gate   geometry_func,
18387c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
18397c478bd9Sstevel@tonic-gate   "geometry DRIVE [CYLINDER HEAD SECTOR [TOTAL_SECTOR]]",
18407c478bd9Sstevel@tonic-gate   "Print the information for a drive DRIVE. In the grub shell, you can"
18417c478bd9Sstevel@tonic-gate   " set the geometry of the drive arbitrarily. The number of the cylinders,"
18427c478bd9Sstevel@tonic-gate   " the one of the heads, the one of the sectors and the one of the total"
18437c478bd9Sstevel@tonic-gate   " sectors are set to CYLINDER, HEAD, SECTOR and TOTAL_SECTOR,"
18447c478bd9Sstevel@tonic-gate   " respectively. If you omit TOTAL_SECTOR, then it will be calculated based"
18457c478bd9Sstevel@tonic-gate   " on the C/H/S values automatically."
18467c478bd9Sstevel@tonic-gate };
18477c478bd9Sstevel@tonic-gate 
18487c478bd9Sstevel@tonic-gate 
18497c478bd9Sstevel@tonic-gate /* halt */
18507c478bd9Sstevel@tonic-gate static int
18517c478bd9Sstevel@tonic-gate halt_func (char *arg, int flags)
18527c478bd9Sstevel@tonic-gate {
18537c478bd9Sstevel@tonic-gate   int no_apm;
18547c478bd9Sstevel@tonic-gate 
18557c478bd9Sstevel@tonic-gate   no_apm = (grub_memcmp (arg, "--no-apm", 8) == 0);
18567c478bd9Sstevel@tonic-gate   grub_halt (no_apm);
18577c478bd9Sstevel@tonic-gate 
18587c478bd9Sstevel@tonic-gate   /* Never reach here.  */
18597c478bd9Sstevel@tonic-gate   return 1;
18607c478bd9Sstevel@tonic-gate }
18617c478bd9Sstevel@tonic-gate 
18627c478bd9Sstevel@tonic-gate static struct builtin builtin_halt =
18637c478bd9Sstevel@tonic-gate {
18647c478bd9Sstevel@tonic-gate   "halt",
18657c478bd9Sstevel@tonic-gate   halt_func,
18667c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
18677c478bd9Sstevel@tonic-gate   "halt [--no-apm]",
18687c478bd9Sstevel@tonic-gate   "Halt your system. If APM is avaiable on it, turn off the power using"
18697c478bd9Sstevel@tonic-gate   " the APM BIOS, unless you specify the option `--no-apm'."
18707c478bd9Sstevel@tonic-gate };
18717c478bd9Sstevel@tonic-gate 
18727c478bd9Sstevel@tonic-gate 
18737c478bd9Sstevel@tonic-gate /* help */
18747c478bd9Sstevel@tonic-gate #define MAX_SHORT_DOC_LEN	39
18757c478bd9Sstevel@tonic-gate #define MAX_LONG_DOC_LEN	66
18767c478bd9Sstevel@tonic-gate 
18777c478bd9Sstevel@tonic-gate static int
18787c478bd9Sstevel@tonic-gate help_func (char *arg, int flags)
18797c478bd9Sstevel@tonic-gate {
18807c478bd9Sstevel@tonic-gate   int all = 0;
18817c478bd9Sstevel@tonic-gate 
18827c478bd9Sstevel@tonic-gate   if (grub_memcmp (arg, "--all", sizeof ("--all") - 1) == 0)
18837c478bd9Sstevel@tonic-gate     {
18847c478bd9Sstevel@tonic-gate       all = 1;
18857c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
18867c478bd9Sstevel@tonic-gate     }
18877c478bd9Sstevel@tonic-gate 
18887c478bd9Sstevel@tonic-gate   if (! *arg)
18897c478bd9Sstevel@tonic-gate     {
18907c478bd9Sstevel@tonic-gate       /* Invoked with no argument. Print the list of the short docs.  */
18917c478bd9Sstevel@tonic-gate       struct builtin **builtin;
18927c478bd9Sstevel@tonic-gate       int left = 1;
18937c478bd9Sstevel@tonic-gate 
18947c478bd9Sstevel@tonic-gate       for (builtin = builtin_table; *builtin != 0; builtin++)
18957c478bd9Sstevel@tonic-gate 	{
18967c478bd9Sstevel@tonic-gate 	  int len;
18977c478bd9Sstevel@tonic-gate 	  int i;
18987c478bd9Sstevel@tonic-gate 
18997c478bd9Sstevel@tonic-gate 	  /* If this cannot be used in the command-line interface,
19007c478bd9Sstevel@tonic-gate 	     skip this.  */
19017c478bd9Sstevel@tonic-gate 	  if (! ((*builtin)->flags & BUILTIN_CMDLINE))
19027c478bd9Sstevel@tonic-gate 	    continue;
19037c478bd9Sstevel@tonic-gate 
19047c478bd9Sstevel@tonic-gate 	  /* If this doesn't need to be listed automatically and "--all"
19057c478bd9Sstevel@tonic-gate 	     is not specified, skip this.  */
19067c478bd9Sstevel@tonic-gate 	  if (! all && ! ((*builtin)->flags & BUILTIN_HELP_LIST))
19077c478bd9Sstevel@tonic-gate 	    continue;
19087c478bd9Sstevel@tonic-gate 
19097c478bd9Sstevel@tonic-gate 	  len = grub_strlen ((*builtin)->short_doc);
19107c478bd9Sstevel@tonic-gate 	  /* If the length of SHORT_DOC is too long, truncate it.  */
19117c478bd9Sstevel@tonic-gate 	  if (len > MAX_SHORT_DOC_LEN - 1)
19127c478bd9Sstevel@tonic-gate 	    len = MAX_SHORT_DOC_LEN - 1;
19137c478bd9Sstevel@tonic-gate 
19147c478bd9Sstevel@tonic-gate 	  for (i = 0; i < len; i++)
19157c478bd9Sstevel@tonic-gate 	    grub_putchar ((*builtin)->short_doc[i]);
19167c478bd9Sstevel@tonic-gate 
19177c478bd9Sstevel@tonic-gate 	  for (; i < MAX_SHORT_DOC_LEN; i++)
19187c478bd9Sstevel@tonic-gate 	    grub_putchar (' ');
19197c478bd9Sstevel@tonic-gate 
19207c478bd9Sstevel@tonic-gate 	  if (! left)
19217c478bd9Sstevel@tonic-gate 	    grub_putchar ('\n');
19227c478bd9Sstevel@tonic-gate 
19237c478bd9Sstevel@tonic-gate 	  left = ! left;
19247c478bd9Sstevel@tonic-gate 	}
19257c478bd9Sstevel@tonic-gate 
19267c478bd9Sstevel@tonic-gate       /* If the last entry was at the left column, no newline was printed
19277c478bd9Sstevel@tonic-gate 	 at the end.  */
19287c478bd9Sstevel@tonic-gate       if (! left)
19297c478bd9Sstevel@tonic-gate 	grub_putchar ('\n');
19307c478bd9Sstevel@tonic-gate     }
19317c478bd9Sstevel@tonic-gate   else
19327c478bd9Sstevel@tonic-gate     {
19337c478bd9Sstevel@tonic-gate       /* Invoked with one or more patterns.  */
19347c478bd9Sstevel@tonic-gate       do
19357c478bd9Sstevel@tonic-gate 	{
19367c478bd9Sstevel@tonic-gate 	  struct builtin **builtin;
19377c478bd9Sstevel@tonic-gate 	  char *next_arg;
19387c478bd9Sstevel@tonic-gate 
19397c478bd9Sstevel@tonic-gate 	  /* Get the next argument.  */
19407c478bd9Sstevel@tonic-gate 	  next_arg = skip_to (0, arg);
19417c478bd9Sstevel@tonic-gate 
19427c478bd9Sstevel@tonic-gate 	  /* Terminate ARG.  */
19437c478bd9Sstevel@tonic-gate 	  nul_terminate (arg);
19447c478bd9Sstevel@tonic-gate 
19457c478bd9Sstevel@tonic-gate 	  for (builtin = builtin_table; *builtin; builtin++)
19467c478bd9Sstevel@tonic-gate 	    {
19477c478bd9Sstevel@tonic-gate 	      /* Skip this if this is only for the configuration file.  */
19487c478bd9Sstevel@tonic-gate 	      if (! ((*builtin)->flags & BUILTIN_CMDLINE))
19497c478bd9Sstevel@tonic-gate 		continue;
19507c478bd9Sstevel@tonic-gate 
19517c478bd9Sstevel@tonic-gate 	      if (substring (arg, (*builtin)->name) < 1)
19527c478bd9Sstevel@tonic-gate 		{
19537c478bd9Sstevel@tonic-gate 		  char *doc = (*builtin)->long_doc;
19547c478bd9Sstevel@tonic-gate 
19557c478bd9Sstevel@tonic-gate 		  /* At first, print the name and the short doc.  */
19567c478bd9Sstevel@tonic-gate 		  grub_printf ("%s: %s\n",
19577c478bd9Sstevel@tonic-gate 			       (*builtin)->name, (*builtin)->short_doc);
19587c478bd9Sstevel@tonic-gate 
19597c478bd9Sstevel@tonic-gate 		  /* Print the long doc.  */
19607c478bd9Sstevel@tonic-gate 		  while (*doc)
19617c478bd9Sstevel@tonic-gate 		    {
19627c478bd9Sstevel@tonic-gate 		      int len = grub_strlen (doc);
19637c478bd9Sstevel@tonic-gate 		      int i;
19647c478bd9Sstevel@tonic-gate 
19657c478bd9Sstevel@tonic-gate 		      /* If LEN is too long, fold DOC.  */
19667c478bd9Sstevel@tonic-gate 		      if (len > MAX_LONG_DOC_LEN)
19677c478bd9Sstevel@tonic-gate 			{
19687c478bd9Sstevel@tonic-gate 			  /* Fold this line at the position of a space.  */
19697c478bd9Sstevel@tonic-gate 			  for (len = MAX_LONG_DOC_LEN; len > 0; len--)
19707c478bd9Sstevel@tonic-gate 			    if (doc[len - 1] == ' ')
19717c478bd9Sstevel@tonic-gate 			      break;
19727c478bd9Sstevel@tonic-gate 			}
19737c478bd9Sstevel@tonic-gate 
19747c478bd9Sstevel@tonic-gate 		      grub_printf ("    ");
19757c478bd9Sstevel@tonic-gate 		      for (i = 0; i < len; i++)
19767c478bd9Sstevel@tonic-gate 			grub_putchar (*doc++);
19777c478bd9Sstevel@tonic-gate 		      grub_putchar ('\n');
19787c478bd9Sstevel@tonic-gate 		    }
19797c478bd9Sstevel@tonic-gate 		}
19807c478bd9Sstevel@tonic-gate 	    }
19817c478bd9Sstevel@tonic-gate 
19827c478bd9Sstevel@tonic-gate 	  arg = next_arg;
19837c478bd9Sstevel@tonic-gate 	}
19847c478bd9Sstevel@tonic-gate       while (*arg);
19857c478bd9Sstevel@tonic-gate     }
19867c478bd9Sstevel@tonic-gate 
19877c478bd9Sstevel@tonic-gate   return 0;
19887c478bd9Sstevel@tonic-gate }
19897c478bd9Sstevel@tonic-gate 
19907c478bd9Sstevel@tonic-gate static struct builtin builtin_help =
19917c478bd9Sstevel@tonic-gate {
19927c478bd9Sstevel@tonic-gate   "help",
19937c478bd9Sstevel@tonic-gate   help_func,
19947c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
19957c478bd9Sstevel@tonic-gate   "help [--all] [PATTERN ...]",
19967c478bd9Sstevel@tonic-gate   "Display helpful information about builtin commands. Not all commands"
19977c478bd9Sstevel@tonic-gate   " aren't shown without the option `--all'."
19987c478bd9Sstevel@tonic-gate };
19997c478bd9Sstevel@tonic-gate 
20007c478bd9Sstevel@tonic-gate 
20017c478bd9Sstevel@tonic-gate /* hiddenmenu */
20027c478bd9Sstevel@tonic-gate static int
20037c478bd9Sstevel@tonic-gate hiddenmenu_func (char *arg, int flags)
20047c478bd9Sstevel@tonic-gate {
20057c478bd9Sstevel@tonic-gate   show_menu = 0;
20067c478bd9Sstevel@tonic-gate   return 0;
20077c478bd9Sstevel@tonic-gate }
20087c478bd9Sstevel@tonic-gate 
20097c478bd9Sstevel@tonic-gate static struct builtin builtin_hiddenmenu =
20107c478bd9Sstevel@tonic-gate {
20117c478bd9Sstevel@tonic-gate   "hiddenmenu",
20127c478bd9Sstevel@tonic-gate   hiddenmenu_func,
20137c478bd9Sstevel@tonic-gate   BUILTIN_MENU,
20147c478bd9Sstevel@tonic-gate #if 0
20157c478bd9Sstevel@tonic-gate   "hiddenmenu",
20167c478bd9Sstevel@tonic-gate   "Hide the menu."
20177c478bd9Sstevel@tonic-gate #endif
20187c478bd9Sstevel@tonic-gate };
20197c478bd9Sstevel@tonic-gate 
20207c478bd9Sstevel@tonic-gate 
20217c478bd9Sstevel@tonic-gate /* hide */
20227c478bd9Sstevel@tonic-gate static int
20237c478bd9Sstevel@tonic-gate hide_func (char *arg, int flags)
20247c478bd9Sstevel@tonic-gate {
20257c478bd9Sstevel@tonic-gate   if (! set_device (arg))
20267c478bd9Sstevel@tonic-gate     return 1;
20277c478bd9Sstevel@tonic-gate 
20287c478bd9Sstevel@tonic-gate   if (! set_partition_hidden_flag (1))
20297c478bd9Sstevel@tonic-gate     return 1;
20307c478bd9Sstevel@tonic-gate 
20317c478bd9Sstevel@tonic-gate   return 0;
20327c478bd9Sstevel@tonic-gate }
20337c478bd9Sstevel@tonic-gate 
20347c478bd9Sstevel@tonic-gate static struct builtin builtin_hide =
20357c478bd9Sstevel@tonic-gate {
20367c478bd9Sstevel@tonic-gate   "hide",
20377c478bd9Sstevel@tonic-gate   hide_func,
20387c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
20397c478bd9Sstevel@tonic-gate   "hide PARTITION",
20407c478bd9Sstevel@tonic-gate   "Hide PARTITION by setting the \"hidden\" bit in"
20417c478bd9Sstevel@tonic-gate   " its partition type code."
20427c478bd9Sstevel@tonic-gate };
20437c478bd9Sstevel@tonic-gate 
20447c478bd9Sstevel@tonic-gate 
20457c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
20467c478bd9Sstevel@tonic-gate /* ifconfig */
20477c478bd9Sstevel@tonic-gate static int
20487c478bd9Sstevel@tonic-gate ifconfig_func (char *arg, int flags)
20497c478bd9Sstevel@tonic-gate {
20507c478bd9Sstevel@tonic-gate   char *svr = 0, *ip = 0, *gw = 0, *sm = 0;
20517c478bd9Sstevel@tonic-gate 
20527c478bd9Sstevel@tonic-gate   if (! grub_eth_probe ())
20537c478bd9Sstevel@tonic-gate     {
20547c478bd9Sstevel@tonic-gate       grub_printf ("No ethernet card found.\n");
20557c478bd9Sstevel@tonic-gate       errnum = ERR_DEV_VALUES;
20567c478bd9Sstevel@tonic-gate       return 1;
20577c478bd9Sstevel@tonic-gate     }
20587c478bd9Sstevel@tonic-gate 
20597c478bd9Sstevel@tonic-gate   while (*arg)
20607c478bd9Sstevel@tonic-gate     {
20617c478bd9Sstevel@tonic-gate       if (! grub_memcmp ("--server=", arg, sizeof ("--server=") - 1))
20627c478bd9Sstevel@tonic-gate 	svr = arg + sizeof("--server=") - 1;
20637c478bd9Sstevel@tonic-gate       else if (! grub_memcmp ("--address=", arg, sizeof ("--address=") - 1))
20647c478bd9Sstevel@tonic-gate 	ip = arg + sizeof ("--address=") - 1;
20657c478bd9Sstevel@tonic-gate       else if (! grub_memcmp ("--gateway=", arg, sizeof ("--gateway=") - 1))
20667c478bd9Sstevel@tonic-gate 	gw = arg + sizeof ("--gateway=") - 1;
20677c478bd9Sstevel@tonic-gate       else if (! grub_memcmp ("--mask=", arg, sizeof("--mask=") - 1))
20687c478bd9Sstevel@tonic-gate 	sm = arg + sizeof ("--mask=") - 1;
20697c478bd9Sstevel@tonic-gate       else
20707c478bd9Sstevel@tonic-gate 	{
20717c478bd9Sstevel@tonic-gate 	  errnum = ERR_BAD_ARGUMENT;
20727c478bd9Sstevel@tonic-gate 	  return 1;
20737c478bd9Sstevel@tonic-gate 	}
20747c478bd9Sstevel@tonic-gate 
20757c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
20767c478bd9Sstevel@tonic-gate     }
20777c478bd9Sstevel@tonic-gate 
20787c478bd9Sstevel@tonic-gate   if (! ifconfig (ip, sm, gw, svr))
20797c478bd9Sstevel@tonic-gate     {
20807c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
20817c478bd9Sstevel@tonic-gate       return 1;
20827c478bd9Sstevel@tonic-gate     }
20837c478bd9Sstevel@tonic-gate 
20847c478bd9Sstevel@tonic-gate   print_network_configuration ();
20857c478bd9Sstevel@tonic-gate   return 0;
20867c478bd9Sstevel@tonic-gate }
20877c478bd9Sstevel@tonic-gate 
20887c478bd9Sstevel@tonic-gate static struct builtin builtin_ifconfig =
20897c478bd9Sstevel@tonic-gate {
20907c478bd9Sstevel@tonic-gate   "ifconfig",
20917c478bd9Sstevel@tonic-gate   ifconfig_func,
20927c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
20937c478bd9Sstevel@tonic-gate   "ifconfig [--address=IP] [--gateway=IP] [--mask=MASK] [--server=IP]",
20947c478bd9Sstevel@tonic-gate   "Configure the IP address, the netmask, the gateway and the server"
20957c478bd9Sstevel@tonic-gate   " address or print current network configuration."
20967c478bd9Sstevel@tonic-gate };
20977c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
20987c478bd9Sstevel@tonic-gate 
20997c478bd9Sstevel@tonic-gate 
21007c478bd9Sstevel@tonic-gate /* impsprobe */
21017c478bd9Sstevel@tonic-gate static int
21027c478bd9Sstevel@tonic-gate impsprobe_func (char *arg, int flags)
21037c478bd9Sstevel@tonic-gate {
21047c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
21057c478bd9Sstevel@tonic-gate   /* In the grub shell, we cannot probe IMPS.  */
21067c478bd9Sstevel@tonic-gate   errnum = ERR_UNRECOGNIZED;
21077c478bd9Sstevel@tonic-gate   return 1;
21087c478bd9Sstevel@tonic-gate #else /* ! GRUB_UTIL */
21097c478bd9Sstevel@tonic-gate   if (!imps_probe ())
21107c478bd9Sstevel@tonic-gate     printf (" No MPS information found or probe failed\n");
21117c478bd9Sstevel@tonic-gate 
21127c478bd9Sstevel@tonic-gate   return 0;
21137c478bd9Sstevel@tonic-gate #endif /* ! GRUB_UTIL */
21147c478bd9Sstevel@tonic-gate }
21157c478bd9Sstevel@tonic-gate 
21167c478bd9Sstevel@tonic-gate static struct builtin builtin_impsprobe =
21177c478bd9Sstevel@tonic-gate {
21187c478bd9Sstevel@tonic-gate   "impsprobe",
21197c478bd9Sstevel@tonic-gate   impsprobe_func,
21207c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
21217c478bd9Sstevel@tonic-gate   "impsprobe",
21227c478bd9Sstevel@tonic-gate   "Probe the Intel Multiprocessor Specification 1.1 or 1.4"
21237c478bd9Sstevel@tonic-gate   " configuration table and boot the various CPUs which are found into"
21247c478bd9Sstevel@tonic-gate   " a tight loop."
21257c478bd9Sstevel@tonic-gate };
21267c478bd9Sstevel@tonic-gate 
21277c478bd9Sstevel@tonic-gate 
21287c478bd9Sstevel@tonic-gate /* initrd */
21297c478bd9Sstevel@tonic-gate static int
21307c478bd9Sstevel@tonic-gate initrd_func (char *arg, int flags)
21317c478bd9Sstevel@tonic-gate {
21327c478bd9Sstevel@tonic-gate   switch (kernel_type)
21337c478bd9Sstevel@tonic-gate     {
21347c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_LINUX:
21357c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_BIG_LINUX:
21367c478bd9Sstevel@tonic-gate       if (! load_initrd (arg))
21377c478bd9Sstevel@tonic-gate 	return 1;
21387c478bd9Sstevel@tonic-gate       break;
21397c478bd9Sstevel@tonic-gate 
21407c478bd9Sstevel@tonic-gate     default:
21417c478bd9Sstevel@tonic-gate       errnum = ERR_NEED_LX_KERNEL;
21427c478bd9Sstevel@tonic-gate       return 1;
21437c478bd9Sstevel@tonic-gate     }
21447c478bd9Sstevel@tonic-gate 
21457c478bd9Sstevel@tonic-gate   return 0;
21467c478bd9Sstevel@tonic-gate }
21477c478bd9Sstevel@tonic-gate 
21487c478bd9Sstevel@tonic-gate static struct builtin builtin_initrd =
21497c478bd9Sstevel@tonic-gate {
21507c478bd9Sstevel@tonic-gate   "initrd",
21517c478bd9Sstevel@tonic-gate   initrd_func,
21527c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
21537c478bd9Sstevel@tonic-gate   "initrd FILE [ARG ...]",
21547c478bd9Sstevel@tonic-gate   "Load an initial ramdisk FILE for a Linux format boot image and set the"
21557c478bd9Sstevel@tonic-gate   " appropriate parameters in the Linux setup area in memory."
21567c478bd9Sstevel@tonic-gate };
21577c478bd9Sstevel@tonic-gate 
21587c478bd9Sstevel@tonic-gate 
21597c478bd9Sstevel@tonic-gate /* install */
21607c478bd9Sstevel@tonic-gate static int
21617c478bd9Sstevel@tonic-gate install_func (char *arg, int flags)
21627c478bd9Sstevel@tonic-gate {
21637c478bd9Sstevel@tonic-gate   char *stage1_file, *dest_dev, *file, *addr;
21647c478bd9Sstevel@tonic-gate   char *stage1_buffer = (char *) RAW_ADDR (0x100000);
21657c478bd9Sstevel@tonic-gate   char *stage2_buffer = stage1_buffer + SECTOR_SIZE;
21667c478bd9Sstevel@tonic-gate   char *old_sect = stage2_buffer + SECTOR_SIZE;
21677c478bd9Sstevel@tonic-gate   char *stage2_first_buffer = old_sect + SECTOR_SIZE;
21687c478bd9Sstevel@tonic-gate   char *stage2_second_buffer = stage2_first_buffer + SECTOR_SIZE;
21697c478bd9Sstevel@tonic-gate   /* XXX: Probably SECTOR_SIZE is reasonable.  */
21707c478bd9Sstevel@tonic-gate   char *config_filename = stage2_second_buffer + SECTOR_SIZE;
21717c478bd9Sstevel@tonic-gate   char *dummy = config_filename + SECTOR_SIZE;
21727c478bd9Sstevel@tonic-gate   int new_drive = GRUB_INVALID_DRIVE;
2173342440ecSPrasad Singamsetty   int dest_drive, dest_partition;
2174342440ecSPrasad Singamsetty   unsigned int dest_sector;
21757c478bd9Sstevel@tonic-gate   int src_drive, src_partition, src_part_start;
21767c478bd9Sstevel@tonic-gate   int i;
21777c478bd9Sstevel@tonic-gate   struct geometry dest_geom, src_geom;
2178342440ecSPrasad Singamsetty   unsigned int saved_sector;
2179342440ecSPrasad Singamsetty   unsigned int stage2_first_sector, stage2_second_sector;
21807c478bd9Sstevel@tonic-gate   char *ptr;
21817c478bd9Sstevel@tonic-gate   int installaddr, installlist;
21827c478bd9Sstevel@tonic-gate   /* Point to the location of the name of a configuration file in Stage 2.  */
21837c478bd9Sstevel@tonic-gate   char *config_file_location;
21847c478bd9Sstevel@tonic-gate   /* If FILE is a Stage 1.5?  */
21857c478bd9Sstevel@tonic-gate   int is_stage1_5 = 0;
21867c478bd9Sstevel@tonic-gate   /* Must call grub_close?  */
21877c478bd9Sstevel@tonic-gate   int is_open = 0;
21887c478bd9Sstevel@tonic-gate   /* If LBA is forced?  */
21897c478bd9Sstevel@tonic-gate   int is_force_lba = 0;
21907c478bd9Sstevel@tonic-gate   /* Was the last sector full? */
21917c478bd9Sstevel@tonic-gate   int last_length = SECTOR_SIZE;
21927c478bd9Sstevel@tonic-gate 
21937c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
21947c478bd9Sstevel@tonic-gate   /* If the Stage 2 is in a partition mounted by an OS, this will store
21957c478bd9Sstevel@tonic-gate      the filename under the OS.  */
21967c478bd9Sstevel@tonic-gate   char *stage2_os_file = 0;
21977c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
21987c478bd9Sstevel@tonic-gate 
21991b8adde7SWilliam Kucharski   auto void disk_read_savesect_func (unsigned int sector, int offset,
22001b8adde7SWilliam Kucharski       int length);
22011b8adde7SWilliam Kucharski   auto void disk_read_blocklist_func (unsigned int sector, int offset,
22021b8adde7SWilliam Kucharski       int length);
22031b8adde7SWilliam Kucharski 
22047c478bd9Sstevel@tonic-gate   /* Save the first sector of Stage2 in STAGE2_SECT.  */
22051b8adde7SWilliam Kucharski   auto void disk_read_savesect_func (unsigned int sector, int offset,
22061b8adde7SWilliam Kucharski       int length)
22077c478bd9Sstevel@tonic-gate     {
22087c478bd9Sstevel@tonic-gate       if (debug)
2209342440ecSPrasad Singamsetty 	printf ("[%u]", sector);
22107c478bd9Sstevel@tonic-gate 
22117c478bd9Sstevel@tonic-gate       /* ReiserFS has files which sometimes contain data not aligned
22127c478bd9Sstevel@tonic-gate          on sector boundaries.  Returning an error is better than
22137c478bd9Sstevel@tonic-gate          silently failing. */
22147c478bd9Sstevel@tonic-gate       if (offset != 0 || length != SECTOR_SIZE)
22157c478bd9Sstevel@tonic-gate 	errnum = ERR_UNALIGNED;
22167c478bd9Sstevel@tonic-gate 
22177c478bd9Sstevel@tonic-gate       saved_sector = sector;
22187c478bd9Sstevel@tonic-gate     }
22197c478bd9Sstevel@tonic-gate 
22207c478bd9Sstevel@tonic-gate   /* Write SECTOR to INSTALLLIST, and update INSTALLADDR and
22217c478bd9Sstevel@tonic-gate      INSTALLSECT.  */
22221b8adde7SWilliam Kucharski   auto void disk_read_blocklist_func (unsigned int sector, int offset,
22231b8adde7SWilliam Kucharski       int length)
22247c478bd9Sstevel@tonic-gate     {
22257c478bd9Sstevel@tonic-gate       if (debug)
2226342440ecSPrasad Singamsetty 	printf("[%u]", sector);
22277c478bd9Sstevel@tonic-gate 
22287c478bd9Sstevel@tonic-gate       if (offset != 0 || last_length != SECTOR_SIZE)
22297c478bd9Sstevel@tonic-gate 	{
22307c478bd9Sstevel@tonic-gate 	  /* We found a non-sector-aligned data block. */
22317c478bd9Sstevel@tonic-gate 	  errnum = ERR_UNALIGNED;
22327c478bd9Sstevel@tonic-gate 	  return;
22337c478bd9Sstevel@tonic-gate 	}
22347c478bd9Sstevel@tonic-gate 
22357c478bd9Sstevel@tonic-gate       last_length = length;
22367c478bd9Sstevel@tonic-gate 
22377c478bd9Sstevel@tonic-gate       if (*((unsigned long *) (installlist - 4))
22387c478bd9Sstevel@tonic-gate 	  + *((unsigned short *) installlist) != sector
22397c478bd9Sstevel@tonic-gate 	  || installlist == (int) stage2_first_buffer + SECTOR_SIZE + 4)
22407c478bd9Sstevel@tonic-gate 	{
22417c478bd9Sstevel@tonic-gate 	  installlist -= 8;
22427c478bd9Sstevel@tonic-gate 
22437c478bd9Sstevel@tonic-gate 	  if (*((unsigned long *) (installlist - 8)))
22447c478bd9Sstevel@tonic-gate 	    errnum = ERR_WONT_FIT;
22457c478bd9Sstevel@tonic-gate 	  else
22467c478bd9Sstevel@tonic-gate 	    {
22477c478bd9Sstevel@tonic-gate 	      *((unsigned short *) (installlist + 2)) = (installaddr >> 4);
22487c478bd9Sstevel@tonic-gate 	      *((unsigned long *) (installlist - 4)) = sector;
22497c478bd9Sstevel@tonic-gate 	    }
22507c478bd9Sstevel@tonic-gate 	}
22517c478bd9Sstevel@tonic-gate 
22527c478bd9Sstevel@tonic-gate       *((unsigned short *) installlist) += 1;
22537c478bd9Sstevel@tonic-gate       installaddr += 512;
22547c478bd9Sstevel@tonic-gate     }
22557c478bd9Sstevel@tonic-gate 
22567c478bd9Sstevel@tonic-gate   /* First, check the GNU-style long option.  */
22577c478bd9Sstevel@tonic-gate   while (1)
22587c478bd9Sstevel@tonic-gate     {
22597c478bd9Sstevel@tonic-gate       if (grub_memcmp ("--force-lba", arg, sizeof ("--force-lba") - 1) == 0)
22607c478bd9Sstevel@tonic-gate 	{
22617c478bd9Sstevel@tonic-gate 	  is_force_lba = 1;
22627c478bd9Sstevel@tonic-gate 	  arg = skip_to (0, arg);
22637c478bd9Sstevel@tonic-gate 	}
22647c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
22657c478bd9Sstevel@tonic-gate       else if (grub_memcmp ("--stage2=", arg, sizeof ("--stage2=") - 1) == 0)
22667c478bd9Sstevel@tonic-gate 	{
22677c478bd9Sstevel@tonic-gate 	  stage2_os_file = arg + sizeof ("--stage2=") - 1;
22687c478bd9Sstevel@tonic-gate 	  arg = skip_to (0, arg);
22697c478bd9Sstevel@tonic-gate 	  nul_terminate (stage2_os_file);
22707c478bd9Sstevel@tonic-gate 	}
22717c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
22727c478bd9Sstevel@tonic-gate       else
22737c478bd9Sstevel@tonic-gate 	break;
22747c478bd9Sstevel@tonic-gate     }
22757c478bd9Sstevel@tonic-gate 
22767c478bd9Sstevel@tonic-gate   stage1_file = arg;
22777c478bd9Sstevel@tonic-gate   dest_dev = skip_to (0, stage1_file);
22787c478bd9Sstevel@tonic-gate   if (*dest_dev == 'd')
22797c478bd9Sstevel@tonic-gate     {
22807c478bd9Sstevel@tonic-gate       new_drive = 0;
22817c478bd9Sstevel@tonic-gate       dest_dev = skip_to (0, dest_dev);
22827c478bd9Sstevel@tonic-gate     }
22837c478bd9Sstevel@tonic-gate   file = skip_to (0, dest_dev);
22847c478bd9Sstevel@tonic-gate   addr = skip_to (0, file);
22857c478bd9Sstevel@tonic-gate 
22867c478bd9Sstevel@tonic-gate   /* Get the installation address.  */
22877c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&addr, &installaddr))
22887c478bd9Sstevel@tonic-gate     {
22897c478bd9Sstevel@tonic-gate       /* ADDR is not specified.  */
22907c478bd9Sstevel@tonic-gate       installaddr = 0;
22917c478bd9Sstevel@tonic-gate       ptr = addr;
22927c478bd9Sstevel@tonic-gate       errnum = 0;
22937c478bd9Sstevel@tonic-gate     }
22947c478bd9Sstevel@tonic-gate   else
22957c478bd9Sstevel@tonic-gate     ptr = skip_to (0, addr);
22967c478bd9Sstevel@tonic-gate 
22977c478bd9Sstevel@tonic-gate #ifndef NO_DECOMPRESSION
22987c478bd9Sstevel@tonic-gate   /* Do not decompress Stage 1 or Stage 2.  */
22997c478bd9Sstevel@tonic-gate   no_decompression = 1;
23007c478bd9Sstevel@tonic-gate #endif
23017c478bd9Sstevel@tonic-gate 
23027c478bd9Sstevel@tonic-gate   /* Read Stage 1.  */
23037c478bd9Sstevel@tonic-gate   is_open = grub_open (stage1_file);
23047c478bd9Sstevel@tonic-gate   if (! is_open
23057c478bd9Sstevel@tonic-gate       || ! grub_read (stage1_buffer, SECTOR_SIZE) == SECTOR_SIZE)
23067c478bd9Sstevel@tonic-gate     goto fail;
23077c478bd9Sstevel@tonic-gate 
23087c478bd9Sstevel@tonic-gate   /* Read the old sector from DEST_DEV.  */
23097c478bd9Sstevel@tonic-gate   if (! set_device (dest_dev)
23107c478bd9Sstevel@tonic-gate       || ! open_partition ()
23117c478bd9Sstevel@tonic-gate       || ! devread (0, 0, SECTOR_SIZE, old_sect))
23127c478bd9Sstevel@tonic-gate     goto fail;
23137c478bd9Sstevel@tonic-gate 
23147c478bd9Sstevel@tonic-gate   /* Store the information for the destination device.  */
23157c478bd9Sstevel@tonic-gate   dest_drive = current_drive;
23167c478bd9Sstevel@tonic-gate   dest_partition = current_partition;
23177c478bd9Sstevel@tonic-gate   dest_geom = buf_geom;
23187c478bd9Sstevel@tonic-gate   dest_sector = part_start;
23197c478bd9Sstevel@tonic-gate 
23207c478bd9Sstevel@tonic-gate   /* Copy the possible DOS BPB, 59 bytes at byte offset 3.  */
23217c478bd9Sstevel@tonic-gate   grub_memmove (stage1_buffer + BOOTSEC_BPB_OFFSET,
23227c478bd9Sstevel@tonic-gate 		old_sect + BOOTSEC_BPB_OFFSET,
23237c478bd9Sstevel@tonic-gate 		BOOTSEC_BPB_LENGTH);
23247c478bd9Sstevel@tonic-gate 
23257c478bd9Sstevel@tonic-gate   /* If for a hard disk, copy the possible MBR/extended part table.  */
23267c478bd9Sstevel@tonic-gate   if (dest_drive & 0x80)
23277c478bd9Sstevel@tonic-gate     grub_memmove (stage1_buffer + STAGE1_WINDOWS_NT_MAGIC,
23287c478bd9Sstevel@tonic-gate 		  old_sect + STAGE1_WINDOWS_NT_MAGIC,
23297c478bd9Sstevel@tonic-gate 		  STAGE1_PARTEND - STAGE1_WINDOWS_NT_MAGIC);
23307c478bd9Sstevel@tonic-gate 
23317c478bd9Sstevel@tonic-gate   /* Check for the version and the signature of Stage 1.  */
23327c478bd9Sstevel@tonic-gate   if (*((short *)(stage1_buffer + STAGE1_VER_MAJ_OFFS)) != COMPAT_VERSION
23337c478bd9Sstevel@tonic-gate       || (*((unsigned short *) (stage1_buffer + BOOTSEC_SIG_OFFSET))
23347c478bd9Sstevel@tonic-gate 	  != BOOTSEC_SIGNATURE))
23357c478bd9Sstevel@tonic-gate     {
23367c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_VERSION;
23377c478bd9Sstevel@tonic-gate       goto fail;
23387c478bd9Sstevel@tonic-gate     }
23397c478bd9Sstevel@tonic-gate 
23407c478bd9Sstevel@tonic-gate   /* This below is not true any longer. But should we leave this alone?  */
23417c478bd9Sstevel@tonic-gate 
23427c478bd9Sstevel@tonic-gate   /* If DEST_DRIVE is a floppy, Stage 2 must have the iteration probe
23437c478bd9Sstevel@tonic-gate      routine.  */
23447c478bd9Sstevel@tonic-gate   if (! (dest_drive & 0x80)
23457c478bd9Sstevel@tonic-gate       && (*((unsigned char *) (stage1_buffer + BOOTSEC_PART_OFFSET)) == 0x80
23467c478bd9Sstevel@tonic-gate 	  || stage1_buffer[BOOTSEC_PART_OFFSET] == 0))
23477c478bd9Sstevel@tonic-gate     {
23487c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_VERSION;
23497c478bd9Sstevel@tonic-gate       goto fail;
23507c478bd9Sstevel@tonic-gate     }
23517c478bd9Sstevel@tonic-gate 
23527c478bd9Sstevel@tonic-gate   grub_close ();
23537c478bd9Sstevel@tonic-gate 
23547c478bd9Sstevel@tonic-gate   /* Open Stage 2.  */
23557c478bd9Sstevel@tonic-gate   is_open = grub_open (file);
23567c478bd9Sstevel@tonic-gate   if (! is_open)
23577c478bd9Sstevel@tonic-gate     goto fail;
23587c478bd9Sstevel@tonic-gate 
23597c478bd9Sstevel@tonic-gate   src_drive = current_drive;
23607c478bd9Sstevel@tonic-gate   src_partition = current_partition;
23617c478bd9Sstevel@tonic-gate   src_part_start = part_start;
23627c478bd9Sstevel@tonic-gate   src_geom = buf_geom;
23637c478bd9Sstevel@tonic-gate 
23647c478bd9Sstevel@tonic-gate   if (! new_drive)
23657c478bd9Sstevel@tonic-gate     new_drive = src_drive;
23667c478bd9Sstevel@tonic-gate   else if (src_drive != dest_drive)
23677c478bd9Sstevel@tonic-gate     grub_printf ("Warning: the option `d' was not used, but the Stage 1 will"
23687c478bd9Sstevel@tonic-gate 		 " be installed on a\ndifferent drive than the drive where"
23697c478bd9Sstevel@tonic-gate 		 " the Stage 2 resides.\n");
23707c478bd9Sstevel@tonic-gate 
23717c478bd9Sstevel@tonic-gate   /* Set the boot drive.  */
23727c478bd9Sstevel@tonic-gate   *((unsigned char *) (stage1_buffer + STAGE1_BOOT_DRIVE)) = new_drive;
23737c478bd9Sstevel@tonic-gate 
23747c478bd9Sstevel@tonic-gate   /* Set the "force LBA" flag.  */
23757c478bd9Sstevel@tonic-gate   *((unsigned char *) (stage1_buffer + STAGE1_FORCE_LBA)) = is_force_lba;
23767c478bd9Sstevel@tonic-gate 
23771b8adde7SWilliam Kucharski   /* If DEST_DRIVE is a hard disk, enable the workaround, which is
23781b8adde7SWilliam Kucharski      for buggy BIOSes which don't pass boot drive correctly. Instead,
23791b8adde7SWilliam Kucharski      they pass 0x00 or 0x01 even when booted from 0x80.  */
23801b8adde7SWilliam Kucharski   if (dest_drive & BIOS_FLAG_FIXED_DISK)
23811b8adde7SWilliam Kucharski     /* Replace the jmp (2 bytes) with double nop's.  */
23821b8adde7SWilliam Kucharski     *((unsigned short *) (stage1_buffer + STAGE1_BOOT_DRIVE_CHECK))
23831b8adde7SWilliam Kucharski       = 0x9090;
23841b8adde7SWilliam Kucharski 
23857c478bd9Sstevel@tonic-gate   /* Read the first sector of Stage 2.  */
23867c478bd9Sstevel@tonic-gate   disk_read_hook = disk_read_savesect_func;
23877c478bd9Sstevel@tonic-gate   if (grub_read (stage2_first_buffer, SECTOR_SIZE) != SECTOR_SIZE)
23887c478bd9Sstevel@tonic-gate     goto fail;
23897c478bd9Sstevel@tonic-gate 
23907c478bd9Sstevel@tonic-gate   stage2_first_sector = saved_sector;
23917c478bd9Sstevel@tonic-gate 
23927c478bd9Sstevel@tonic-gate   /* Read the second sector of Stage 2.  */
23937c478bd9Sstevel@tonic-gate   if (grub_read (stage2_second_buffer, SECTOR_SIZE) != SECTOR_SIZE)
23947c478bd9Sstevel@tonic-gate     goto fail;
23957c478bd9Sstevel@tonic-gate 
23967c478bd9Sstevel@tonic-gate   stage2_second_sector = saved_sector;
23977c478bd9Sstevel@tonic-gate 
23987c478bd9Sstevel@tonic-gate   /* Check for the version of Stage 2.  */
23997c478bd9Sstevel@tonic-gate   if (*((short *) (stage2_second_buffer + STAGE2_VER_MAJ_OFFS))
24007c478bd9Sstevel@tonic-gate       != COMPAT_VERSION)
24017c478bd9Sstevel@tonic-gate     {
24027c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_VERSION;
24037c478bd9Sstevel@tonic-gate       goto fail;
24047c478bd9Sstevel@tonic-gate     }
24057c478bd9Sstevel@tonic-gate 
24067c478bd9Sstevel@tonic-gate   /* Check for the Stage 2 id.  */
24077c478bd9Sstevel@tonic-gate   if (stage2_second_buffer[STAGE2_STAGE2_ID] != STAGE2_ID_STAGE2)
24087c478bd9Sstevel@tonic-gate     is_stage1_5 = 1;
24097c478bd9Sstevel@tonic-gate 
24107c478bd9Sstevel@tonic-gate   /* If INSTALLADDR is not specified explicitly in the command-line,
24117c478bd9Sstevel@tonic-gate      determine it by the Stage 2 id.  */
24127c478bd9Sstevel@tonic-gate   if (! installaddr)
24137c478bd9Sstevel@tonic-gate     {
24147c478bd9Sstevel@tonic-gate       if (! is_stage1_5)
24157c478bd9Sstevel@tonic-gate 	/* Stage 2.  */
24167c478bd9Sstevel@tonic-gate 	installaddr = 0x8000;
24177c478bd9Sstevel@tonic-gate       else
24187c478bd9Sstevel@tonic-gate 	/* Stage 1.5.  */
24197c478bd9Sstevel@tonic-gate 	installaddr = 0x2000;
24207c478bd9Sstevel@tonic-gate     }
24217c478bd9Sstevel@tonic-gate 
24227c478bd9Sstevel@tonic-gate   *((unsigned long *) (stage1_buffer + STAGE1_STAGE2_SECTOR))
24237c478bd9Sstevel@tonic-gate     = stage2_first_sector;
24247c478bd9Sstevel@tonic-gate   *((unsigned short *) (stage1_buffer + STAGE1_STAGE2_ADDRESS))
24257c478bd9Sstevel@tonic-gate     = installaddr;
24267c478bd9Sstevel@tonic-gate   *((unsigned short *) (stage1_buffer + STAGE1_STAGE2_SEGMENT))
24277c478bd9Sstevel@tonic-gate     = installaddr >> 4;
24287c478bd9Sstevel@tonic-gate 
24297c478bd9Sstevel@tonic-gate   i = (int) stage2_first_buffer + SECTOR_SIZE - 4;
24307c478bd9Sstevel@tonic-gate   while (*((unsigned long *) i))
24317c478bd9Sstevel@tonic-gate     {
24327c478bd9Sstevel@tonic-gate       if (i < (int) stage2_first_buffer
24337c478bd9Sstevel@tonic-gate 	  || (*((int *) (i - 4)) & 0x80000000)
24347c478bd9Sstevel@tonic-gate 	  || *((unsigned short *) i) >= 0xA00
24357c478bd9Sstevel@tonic-gate 	  || *((short *) (i + 2)) == 0)
24367c478bd9Sstevel@tonic-gate 	{
24377c478bd9Sstevel@tonic-gate 	  errnum = ERR_BAD_VERSION;
24387c478bd9Sstevel@tonic-gate 	  goto fail;
24397c478bd9Sstevel@tonic-gate 	}
24407c478bd9Sstevel@tonic-gate 
24417c478bd9Sstevel@tonic-gate       *((int *) i) = 0;
24427c478bd9Sstevel@tonic-gate       *((int *) (i - 4)) = 0;
24437c478bd9Sstevel@tonic-gate       i -= 8;
24447c478bd9Sstevel@tonic-gate     }
24457c478bd9Sstevel@tonic-gate 
24467c478bd9Sstevel@tonic-gate   installlist = (int) stage2_first_buffer + SECTOR_SIZE + 4;
24477c478bd9Sstevel@tonic-gate   installaddr += SECTOR_SIZE;
24487c478bd9Sstevel@tonic-gate 
24497c478bd9Sstevel@tonic-gate   /* Read the whole of Stage2 except for the first sector.  */
24507c478bd9Sstevel@tonic-gate   grub_seek (SECTOR_SIZE);
24517c478bd9Sstevel@tonic-gate 
24527c478bd9Sstevel@tonic-gate   disk_read_hook = disk_read_blocklist_func;
24537c478bd9Sstevel@tonic-gate   if (! grub_read (dummy, -1))
24547c478bd9Sstevel@tonic-gate     goto fail;
24557c478bd9Sstevel@tonic-gate 
24567c478bd9Sstevel@tonic-gate   disk_read_hook = 0;
24577c478bd9Sstevel@tonic-gate 
24587c478bd9Sstevel@tonic-gate   /* Find a string for the configuration filename.  */
24597c478bd9Sstevel@tonic-gate   config_file_location = stage2_second_buffer + STAGE2_VER_STR_OFFS;
24607c478bd9Sstevel@tonic-gate   while (*(config_file_location++))
24617c478bd9Sstevel@tonic-gate     ;
24627c478bd9Sstevel@tonic-gate 
24637c478bd9Sstevel@tonic-gate   /* Set the "force LBA" flag for Stage2.  */
24647c478bd9Sstevel@tonic-gate   *((unsigned char *) (stage2_second_buffer + STAGE2_FORCE_LBA))
24657c478bd9Sstevel@tonic-gate     = is_force_lba;
24667c478bd9Sstevel@tonic-gate 
24677c478bd9Sstevel@tonic-gate   if (*ptr == 'p')
24687c478bd9Sstevel@tonic-gate     {
24697c478bd9Sstevel@tonic-gate       *((long *) (stage2_second_buffer + STAGE2_INSTALLPART))
24707c478bd9Sstevel@tonic-gate 	= src_partition;
24717c478bd9Sstevel@tonic-gate       if (is_stage1_5)
24727c478bd9Sstevel@tonic-gate 	{
24737c478bd9Sstevel@tonic-gate 	  /* Reset the device information in FILE if it is a Stage 1.5.  */
24747c478bd9Sstevel@tonic-gate 	  unsigned long device = 0xFFFFFFFF;
24757c478bd9Sstevel@tonic-gate 
24767c478bd9Sstevel@tonic-gate 	  grub_memmove (config_file_location, (char *) &device,
24777c478bd9Sstevel@tonic-gate 			sizeof (device));
24787c478bd9Sstevel@tonic-gate 	}
24797c478bd9Sstevel@tonic-gate 
24807c478bd9Sstevel@tonic-gate       ptr = skip_to (0, ptr);
24817c478bd9Sstevel@tonic-gate     }
24827c478bd9Sstevel@tonic-gate 
24837c478bd9Sstevel@tonic-gate   if (*ptr)
24847c478bd9Sstevel@tonic-gate     {
24857c478bd9Sstevel@tonic-gate       grub_strcpy (config_filename, ptr);
24867c478bd9Sstevel@tonic-gate       nul_terminate (config_filename);
24877c478bd9Sstevel@tonic-gate 
24887c478bd9Sstevel@tonic-gate       if (! is_stage1_5)
24897c478bd9Sstevel@tonic-gate 	/* If it is a Stage 2, just copy PTR to CONFIG_FILE_LOCATION.  */
24907c478bd9Sstevel@tonic-gate 	grub_strcpy (config_file_location, ptr);
24917c478bd9Sstevel@tonic-gate       else
24927c478bd9Sstevel@tonic-gate 	{
24937c478bd9Sstevel@tonic-gate 	  char *real_config;
24947c478bd9Sstevel@tonic-gate 	  unsigned long device;
24957c478bd9Sstevel@tonic-gate 
24967c478bd9Sstevel@tonic-gate 	  /* Translate the external device syntax to the internal device
24977c478bd9Sstevel@tonic-gate 	     syntax.  */
24987c478bd9Sstevel@tonic-gate 	  if (! (real_config = set_device (ptr)))
24997c478bd9Sstevel@tonic-gate 	    {
25007c478bd9Sstevel@tonic-gate 	      /* The Stage 2 PTR does not contain the device name, so
25017c478bd9Sstevel@tonic-gate 		 use the root device instead.  */
25027c478bd9Sstevel@tonic-gate 	      errnum = ERR_NONE;
25037c478bd9Sstevel@tonic-gate 	      current_drive = saved_drive;
25047c478bd9Sstevel@tonic-gate 	      current_partition = saved_partition;
25057c478bd9Sstevel@tonic-gate 	      real_config = ptr;
25067c478bd9Sstevel@tonic-gate 	    }
25077c478bd9Sstevel@tonic-gate 
25087c478bd9Sstevel@tonic-gate 	  if (current_drive == src_drive)
25097c478bd9Sstevel@tonic-gate 	    {
25107c478bd9Sstevel@tonic-gate 	      /* If the drive where the Stage 2 resides is the same as
25117c478bd9Sstevel@tonic-gate 		 the one where the Stage 1.5 resides, do not embed the
25127c478bd9Sstevel@tonic-gate 		 drive number.  */
25137c478bd9Sstevel@tonic-gate 	      current_drive = GRUB_INVALID_DRIVE;
25147c478bd9Sstevel@tonic-gate 	    }
25157c478bd9Sstevel@tonic-gate 
25167c478bd9Sstevel@tonic-gate 	  device = (current_drive << 24) | current_partition;
25177c478bd9Sstevel@tonic-gate 	  grub_memmove (config_file_location, (char *) &device,
25187c478bd9Sstevel@tonic-gate 			sizeof (device));
25197c478bd9Sstevel@tonic-gate 	  grub_strcpy (config_file_location + sizeof (device),
25207c478bd9Sstevel@tonic-gate 		       real_config);
25217c478bd9Sstevel@tonic-gate 	}
25227c478bd9Sstevel@tonic-gate 
25237c478bd9Sstevel@tonic-gate       /* If a Stage 1.5 is used, then we need to modify the Stage2.  */
25247c478bd9Sstevel@tonic-gate       if (is_stage1_5)
25257c478bd9Sstevel@tonic-gate 	{
25267c478bd9Sstevel@tonic-gate 	  char *real_config_filename = skip_to (0, ptr);
25277c478bd9Sstevel@tonic-gate 
25287c478bd9Sstevel@tonic-gate 	  is_open = grub_open (config_filename);
25297c478bd9Sstevel@tonic-gate 	  if (! is_open)
25307c478bd9Sstevel@tonic-gate 	    goto fail;
25317c478bd9Sstevel@tonic-gate 
25327c478bd9Sstevel@tonic-gate 	  /* Skip the first sector.  */
25337c478bd9Sstevel@tonic-gate 	  grub_seek (SECTOR_SIZE);
25347c478bd9Sstevel@tonic-gate 
25357c478bd9Sstevel@tonic-gate 	  disk_read_hook = disk_read_savesect_func;
25367c478bd9Sstevel@tonic-gate 	  if (grub_read (stage2_buffer, SECTOR_SIZE) != SECTOR_SIZE)
25377c478bd9Sstevel@tonic-gate 	    goto fail;
25387c478bd9Sstevel@tonic-gate 
25397c478bd9Sstevel@tonic-gate 	  disk_read_hook = 0;
25407c478bd9Sstevel@tonic-gate 	  grub_close ();
25417c478bd9Sstevel@tonic-gate 	  is_open = 0;
25427c478bd9Sstevel@tonic-gate 
25437c478bd9Sstevel@tonic-gate 	  /* Sanity check.  */
25447c478bd9Sstevel@tonic-gate 	  if (*(stage2_buffer + STAGE2_STAGE2_ID) != STAGE2_ID_STAGE2)
25457c478bd9Sstevel@tonic-gate 	    {
25467c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_VERSION;
25477c478bd9Sstevel@tonic-gate 	      goto fail;
25487c478bd9Sstevel@tonic-gate 	    }
25497c478bd9Sstevel@tonic-gate 
25507c478bd9Sstevel@tonic-gate 	  /* Set the "force LBA" flag for Stage2.  */
25517c478bd9Sstevel@tonic-gate 	  *(stage2_buffer + STAGE2_FORCE_LBA) = is_force_lba;
25527c478bd9Sstevel@tonic-gate 
25537c478bd9Sstevel@tonic-gate 	  /* If REAL_CONFIG_FILENAME is specified, copy it to the Stage2.  */
25547c478bd9Sstevel@tonic-gate 	  if (*real_config_filename)
25557c478bd9Sstevel@tonic-gate 	    {
25567c478bd9Sstevel@tonic-gate 	      /* Specified */
25577c478bd9Sstevel@tonic-gate 	      char *location;
25587c478bd9Sstevel@tonic-gate 
25597c478bd9Sstevel@tonic-gate 	      /* Find a string for the configuration filename.  */
25607c478bd9Sstevel@tonic-gate 	      location = stage2_buffer + STAGE2_VER_STR_OFFS;
25617c478bd9Sstevel@tonic-gate 	      while (*(location++))
25627c478bd9Sstevel@tonic-gate 		;
25637c478bd9Sstevel@tonic-gate 
25647c478bd9Sstevel@tonic-gate 	      /* Copy the name.  */
25657c478bd9Sstevel@tonic-gate 	      grub_strcpy (location, real_config_filename);
25667c478bd9Sstevel@tonic-gate 	    }
25677c478bd9Sstevel@tonic-gate 
25687c478bd9Sstevel@tonic-gate 	  /* Write it to the disk.  */
2569342440ecSPrasad Singamsetty 	  buf_track = BUF_CACHE_INVALID;
25707c478bd9Sstevel@tonic-gate 
25717c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
25727c478bd9Sstevel@tonic-gate 	  /* In the grub shell, access the Stage 2 via the OS filesystem
25737c478bd9Sstevel@tonic-gate 	     service, if possible.  */
25747c478bd9Sstevel@tonic-gate 	  if (stage2_os_file)
25757c478bd9Sstevel@tonic-gate 	    {
25767c478bd9Sstevel@tonic-gate 	      FILE *fp;
25777c478bd9Sstevel@tonic-gate 
25787c478bd9Sstevel@tonic-gate 	      fp = fopen (stage2_os_file, "r+");
25797c478bd9Sstevel@tonic-gate 	      if (! fp)
25807c478bd9Sstevel@tonic-gate 		{
25817c478bd9Sstevel@tonic-gate 		  errnum = ERR_FILE_NOT_FOUND;
25827c478bd9Sstevel@tonic-gate 		  goto fail;
25837c478bd9Sstevel@tonic-gate 		}
25847c478bd9Sstevel@tonic-gate 
25857c478bd9Sstevel@tonic-gate 	      if (fseek (fp, SECTOR_SIZE, SEEK_SET) != 0)
25867c478bd9Sstevel@tonic-gate 		{
25877c478bd9Sstevel@tonic-gate 		  fclose (fp);
25887c478bd9Sstevel@tonic-gate 		  errnum = ERR_BAD_VERSION;
25897c478bd9Sstevel@tonic-gate 		  goto fail;
25907c478bd9Sstevel@tonic-gate 		}
25917c478bd9Sstevel@tonic-gate 
25927c478bd9Sstevel@tonic-gate 	      if (fwrite (stage2_buffer, 1, SECTOR_SIZE, fp)
25937c478bd9Sstevel@tonic-gate 		  != SECTOR_SIZE)
25947c478bd9Sstevel@tonic-gate 		{
25957c478bd9Sstevel@tonic-gate 		  fclose (fp);
25967c478bd9Sstevel@tonic-gate 		  errnum = ERR_WRITE;
25977c478bd9Sstevel@tonic-gate 		  goto fail;
25987c478bd9Sstevel@tonic-gate 		}
25997c478bd9Sstevel@tonic-gate 
26007c478bd9Sstevel@tonic-gate 	      fclose (fp);
26017c478bd9Sstevel@tonic-gate 	    }
26027c478bd9Sstevel@tonic-gate 	  else
26037c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
26047c478bd9Sstevel@tonic-gate 	    {
26057c478bd9Sstevel@tonic-gate 	      if (! devwrite (saved_sector - part_start, 1, stage2_buffer))
26067c478bd9Sstevel@tonic-gate 		goto fail;
26077c478bd9Sstevel@tonic-gate 	    }
26087c478bd9Sstevel@tonic-gate 	}
26097c478bd9Sstevel@tonic-gate     }
26107c478bd9Sstevel@tonic-gate 
26117c478bd9Sstevel@tonic-gate   /* Clear the cache.  */
2612342440ecSPrasad Singamsetty   buf_track = BUF_CACHE_INVALID;
26137c478bd9Sstevel@tonic-gate 
26147c478bd9Sstevel@tonic-gate   /* Write the modified sectors of Stage2 to the disk.  */
26157c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
26167c478bd9Sstevel@tonic-gate   if (! is_stage1_5 && stage2_os_file)
26177c478bd9Sstevel@tonic-gate     {
26187c478bd9Sstevel@tonic-gate       FILE *fp;
26197c478bd9Sstevel@tonic-gate 
26207c478bd9Sstevel@tonic-gate       fp = fopen (stage2_os_file, "r+");
26217c478bd9Sstevel@tonic-gate       if (! fp)
26227c478bd9Sstevel@tonic-gate 	{
26237c478bd9Sstevel@tonic-gate 	  errnum = ERR_FILE_NOT_FOUND;
26247c478bd9Sstevel@tonic-gate 	  goto fail;
26257c478bd9Sstevel@tonic-gate 	}
26267c478bd9Sstevel@tonic-gate 
26277c478bd9Sstevel@tonic-gate       if (fwrite (stage2_first_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE)
26287c478bd9Sstevel@tonic-gate 	{
26297c478bd9Sstevel@tonic-gate 	  fclose (fp);
26307c478bd9Sstevel@tonic-gate 	  errnum = ERR_WRITE;
26317c478bd9Sstevel@tonic-gate 	  goto fail;
26327c478bd9Sstevel@tonic-gate 	}
26337c478bd9Sstevel@tonic-gate 
26347c478bd9Sstevel@tonic-gate       if (fwrite (stage2_second_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE)
26357c478bd9Sstevel@tonic-gate 	{
26367c478bd9Sstevel@tonic-gate 	  fclose (fp);
26377c478bd9Sstevel@tonic-gate 	  errnum = ERR_WRITE;
26387c478bd9Sstevel@tonic-gate 	  goto fail;
26397c478bd9Sstevel@tonic-gate 	}
26407c478bd9Sstevel@tonic-gate 
26417c478bd9Sstevel@tonic-gate       fclose (fp);
26427c478bd9Sstevel@tonic-gate     }
26437c478bd9Sstevel@tonic-gate   else
26447c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
26457c478bd9Sstevel@tonic-gate     {
26467c478bd9Sstevel@tonic-gate       /* The first.  */
26477c478bd9Sstevel@tonic-gate       current_drive = src_drive;
26487c478bd9Sstevel@tonic-gate       current_partition = src_partition;
26497c478bd9Sstevel@tonic-gate 
26507c478bd9Sstevel@tonic-gate       if (! open_partition ())
26517c478bd9Sstevel@tonic-gate 	goto fail;
26527c478bd9Sstevel@tonic-gate 
26537c478bd9Sstevel@tonic-gate       if (! devwrite (stage2_first_sector - src_part_start, 1,
26547c478bd9Sstevel@tonic-gate 		      stage2_first_buffer))
26557c478bd9Sstevel@tonic-gate 	goto fail;
26567c478bd9Sstevel@tonic-gate 
26577c478bd9Sstevel@tonic-gate       if (! devwrite (stage2_second_sector - src_part_start, 1,
26587c478bd9Sstevel@tonic-gate 		      stage2_second_buffer))
26597c478bd9Sstevel@tonic-gate 	goto fail;
26607c478bd9Sstevel@tonic-gate     }
26617c478bd9Sstevel@tonic-gate 
26627c478bd9Sstevel@tonic-gate   /* Write the modified sector of Stage 1 to the disk.  */
26637c478bd9Sstevel@tonic-gate   current_drive = dest_drive;
26647c478bd9Sstevel@tonic-gate   current_partition = dest_partition;
26657c478bd9Sstevel@tonic-gate   if (! open_partition ())
26667c478bd9Sstevel@tonic-gate     goto fail;
26677c478bd9Sstevel@tonic-gate 
26687c478bd9Sstevel@tonic-gate   devwrite (0, 1, stage1_buffer);
26697c478bd9Sstevel@tonic-gate 
26707c478bd9Sstevel@tonic-gate  fail:
26717c478bd9Sstevel@tonic-gate   if (is_open)
26727c478bd9Sstevel@tonic-gate     grub_close ();
26737c478bd9Sstevel@tonic-gate 
26747c478bd9Sstevel@tonic-gate   disk_read_hook = 0;
26757c478bd9Sstevel@tonic-gate 
26767c478bd9Sstevel@tonic-gate #ifndef NO_DECOMPRESSION
26777c478bd9Sstevel@tonic-gate   no_decompression = 0;
26787c478bd9Sstevel@tonic-gate #endif
26797c478bd9Sstevel@tonic-gate 
26807c478bd9Sstevel@tonic-gate   return errnum;
26817c478bd9Sstevel@tonic-gate }
26827c478bd9Sstevel@tonic-gate 
26837c478bd9Sstevel@tonic-gate static struct builtin builtin_install =
26847c478bd9Sstevel@tonic-gate {
26857c478bd9Sstevel@tonic-gate   "install",
26867c478bd9Sstevel@tonic-gate   install_func,
26877c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
26887c478bd9Sstevel@tonic-gate   "install [--stage2=STAGE2_FILE] [--force-lba] STAGE1 [d] DEVICE STAGE2 [ADDR] [p] [CONFIG_FILE] [REAL_CONFIG_FILE]",
26897c478bd9Sstevel@tonic-gate   "Install STAGE1 on DEVICE, and install a blocklist for loading STAGE2"
26907c478bd9Sstevel@tonic-gate   " as a Stage 2. If the option `d' is present, the Stage 1 will always"
26917c478bd9Sstevel@tonic-gate   " look for the disk where STAGE2 was installed, rather than using"
26927c478bd9Sstevel@tonic-gate   " the booting drive. The Stage 2 will be loaded at address ADDR, which"
26937c478bd9Sstevel@tonic-gate   " will be determined automatically if you don't specify it. If"
26947c478bd9Sstevel@tonic-gate   " the option `p' or CONFIG_FILE is present, then the first block"
26957c478bd9Sstevel@tonic-gate   " of Stage 2 is patched with new values of the partition and name"
26967c478bd9Sstevel@tonic-gate   " of the configuration file used by the true Stage 2 (for a Stage 1.5,"
26977c478bd9Sstevel@tonic-gate   " this is the name of the true Stage 2) at boot time. If STAGE2 is a Stage"
26987c478bd9Sstevel@tonic-gate   " 1.5 and REAL_CONFIG_FILE is present, then the Stage 2 CONFIG_FILE is"
26997c478bd9Sstevel@tonic-gate   " patched with the configuration filename REAL_CONFIG_FILE."
27007c478bd9Sstevel@tonic-gate   " If the option `--force-lba' is specified, disable some sanity checks"
27017c478bd9Sstevel@tonic-gate   " for LBA mode. If the option `--stage2' is specified, rewrite the Stage"
27027c478bd9Sstevel@tonic-gate   " 2 via your OS's filesystem instead of the raw device."
27037c478bd9Sstevel@tonic-gate };
27047c478bd9Sstevel@tonic-gate 
27057c478bd9Sstevel@tonic-gate 
27067c478bd9Sstevel@tonic-gate /* ioprobe */
27077c478bd9Sstevel@tonic-gate static int
27087c478bd9Sstevel@tonic-gate ioprobe_func (char *arg, int flags)
27097c478bd9Sstevel@tonic-gate {
27107c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
27117c478bd9Sstevel@tonic-gate 
27127c478bd9Sstevel@tonic-gate   errnum = ERR_UNRECOGNIZED;
27137c478bd9Sstevel@tonic-gate   return 1;
27147c478bd9Sstevel@tonic-gate 
27157c478bd9Sstevel@tonic-gate #else /* ! GRUB_UTIL */
27167c478bd9Sstevel@tonic-gate 
27177c478bd9Sstevel@tonic-gate   unsigned short *port;
27187c478bd9Sstevel@tonic-gate 
27197c478bd9Sstevel@tonic-gate   /* Get the drive number.  */
27207c478bd9Sstevel@tonic-gate   set_device (arg);
27217c478bd9Sstevel@tonic-gate   if (errnum)
27227c478bd9Sstevel@tonic-gate     return 1;
27237c478bd9Sstevel@tonic-gate 
27247c478bd9Sstevel@tonic-gate   /* Clean out IO_MAP.  */
27257c478bd9Sstevel@tonic-gate   grub_memset ((char *) io_map, 0, IO_MAP_SIZE * sizeof (unsigned short));
27267c478bd9Sstevel@tonic-gate 
27277c478bd9Sstevel@tonic-gate   /* Track the int13 handler.  */
27287c478bd9Sstevel@tonic-gate   track_int13 (current_drive);
27297c478bd9Sstevel@tonic-gate 
27307c478bd9Sstevel@tonic-gate   /* Print out the result.  */
27317c478bd9Sstevel@tonic-gate   for (port = io_map; *port != 0; port++)
27327c478bd9Sstevel@tonic-gate     grub_printf (" 0x%x", (unsigned int) *port);
27337c478bd9Sstevel@tonic-gate 
27347c478bd9Sstevel@tonic-gate   return 0;
27357c478bd9Sstevel@tonic-gate 
27367c478bd9Sstevel@tonic-gate #endif /* ! GRUB_UTIL */
27377c478bd9Sstevel@tonic-gate }
27387c478bd9Sstevel@tonic-gate 
27397c478bd9Sstevel@tonic-gate static struct builtin builtin_ioprobe =
27407c478bd9Sstevel@tonic-gate {
27417c478bd9Sstevel@tonic-gate   "ioprobe",
27427c478bd9Sstevel@tonic-gate   ioprobe_func,
27437c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
27447c478bd9Sstevel@tonic-gate   "ioprobe DRIVE",
27457c478bd9Sstevel@tonic-gate   "Probe I/O ports used for the drive DRIVE."
27467c478bd9Sstevel@tonic-gate };
27477c478bd9Sstevel@tonic-gate 
27487c478bd9Sstevel@tonic-gate 
2749b1b8ab34Slling /*
2750b1b8ab34Slling  * To boot from a ZFS root filesystem, the kernel$ or module$ commands
2751ffb5616eSLin Ling  * must include "-B $ZFS-BOOTFS" to expand to the zfs-bootfs, bootpath,
2752ffb5616eSLin Ling  * and diskdevid boot property values for passing to the kernel:
2753b1b8ab34Slling  *
2754b1b8ab34Slling  * e.g.
2755b1b8ab34Slling  * kernel$ /platform/i86pc/kernel/$ISADIR/unix -B $ZFS-BOOTFS,console=ttya
2756b1b8ab34Slling  *
2757ffb5616eSLin Ling  * $ZFS-BOOTFS is expanded to
2758ffb5616eSLin Ling  *
2759ffb5616eSLin Ling  *    zfs-bootfs=<rootpool-name/zfs-rootfilesystem-object-num>,
2760ffb5616eSLin Ling  *    bootpath=<device phys path>,
2761ffb5616eSLin Ling  *    diskdevid=<device id>
2762ffb5616eSLin Ling  *
2763ffb5616eSLin Ling  * if both bootpath and diskdevid can be found.
2764ffb5616eSLin Ling  * e.g
2765ffb5616eSLin Ling  *    zfs-bootfs=rpool/85,
2766ffb5616eSLin Ling  *    bootpath="/pci@0,0/pci1022,7450@a/pci17c2,10@4/sd@0,0:a",
2767ffb5616eSLin Ling  *    diskdevid="id1,sd@SSEAGATE_ST336607LC______3JA0LNHE0000741326W6/a"
2768b1b8ab34Slling  */
2769b1b8ab34Slling static int
2770b1b8ab34Slling expand_dollar_bootfs(char *in, char *out)
2771b1b8ab34Slling {
2772b1b8ab34Slling 	char *token, *tmpout = out;
2773b1b8ab34Slling 	int outlen, blen;
2774bf82a41bSeschrock 	int postcomma = 0;
2775b1b8ab34Slling 
2776ffb5616eSLin Ling 	if (current_bootpath[0] == '\0' && current_devid[0] == '\0') {
2777ffb5616eSLin Ling 		errnum = ERR_NO_BOOTPATH;
2778ffb5616eSLin Ling 		return (1);
2779ffb5616eSLin Ling 	}
2780ffb5616eSLin Ling 
2781b1b8ab34Slling 	outlen = strlen(in);
2782b1b8ab34Slling 	blen = current_bootfs_obj == 0 ? strlen(current_rootpool) :
2783b1b8ab34Slling 	    strlen(current_rootpool) + 11;
2784b1b8ab34Slling 
2785b1b8ab34Slling 	out[0] = '\0';
2786b1b8ab34Slling 	while (token = strstr(in, "$ZFS-BOOTFS")) {
2787b1b8ab34Slling 
2788ffb5616eSLin Ling 		if ((outlen += blen) >= MAX_CMDLINE) {
2789b1b8ab34Slling 			errnum = ERR_WONT_FIT;
2790b1b8ab34Slling 			return (1);
2791b1b8ab34Slling 		}
2792b1b8ab34Slling 
2793b1b8ab34Slling 		token[0] = '\0';
2794b1b8ab34Slling 		grub_sprintf(tmpout, "%s", in);
2795b1b8ab34Slling 		token[0] = '$';
2796051aabe6Staylor 		in = token + 11; /* skip over $ZFS-BOOTFS */
2797b1b8ab34Slling 		tmpout = out + strlen(out);
2798b1b8ab34Slling 
2799b1b8ab34Slling 		/* Note: %u only fits 32 bit integer; */
2800b1b8ab34Slling 		if (current_bootfs_obj > 0)
2801b1b8ab34Slling 			grub_sprintf(tmpout, "zfs-bootfs=%s/%u",
2802b1b8ab34Slling 			    current_rootpool, current_bootfs_obj);
2803b1b8ab34Slling 		else
2804b1b8ab34Slling 			grub_sprintf(tmpout, "zfs-bootfs=%s",
2805b1b8ab34Slling 			    current_rootpool);
2806b1b8ab34Slling 		tmpout = out + strlen(out);
2807b1b8ab34Slling 	}
2808b1b8ab34Slling 
2809e7cbe64fSgw 	/*
2810bf82a41bSeschrock 	 * Check to see if 'zfs-bootfs' was explicitly specified on the command
2811bf82a41bSeschrock 	 * line so that we can insert the 'bootpath' property.
2812bf82a41bSeschrock 	 */
2813bf82a41bSeschrock 	if ((tmpout == out) && (token = strstr(in, "zfs-bootfs")) != NULL) {
2814bf82a41bSeschrock 		token[0] = '\0';
2815bf82a41bSeschrock 		grub_strcpy(tmpout, in);
2816bf82a41bSeschrock 		token[0] = 'z';
2817bf82a41bSeschrock 		in = token;
2818bf82a41bSeschrock 
2819bf82a41bSeschrock 		tmpout = out + strlen(out);
2820bf82a41bSeschrock 		postcomma = 1;
2821bf82a41bSeschrock 	}
2822bf82a41bSeschrock 
2823bf82a41bSeschrock 	/*
2824bf82a41bSeschrock 	 * Set the 'bootpath' property if a ZFS dataset was specified, either
2825bf82a41bSeschrock 	 * through '$ZFS-BOOTFS' or an explicit 'zfs-bootfs' setting.
2826e7cbe64fSgw 	 */
2827e7cbe64fSgw 	if (tmpout != out) {
2828ffb5616eSLin Ling 		if (current_bootpath[0] != '\0') {
2829ffb5616eSLin Ling 			if ((outlen += 12 + strlen(current_bootpath))
2830ffb5616eSLin Ling 			    >= MAX_CMDLINE) {
2831ffb5616eSLin Ling 				errnum = ERR_WONT_FIT;
2832ffb5616eSLin Ling 				return (1);
2833ffb5616eSLin Ling 			}
2834ffb5616eSLin Ling 			grub_sprintf(tmpout,
2835ffb5616eSLin Ling 			    postcomma ? "bootpath=\"%s\"," : ",bootpath=\"%s\"",
2836ffb5616eSLin Ling 			    current_bootpath);
2837ffb5616eSLin Ling 			tmpout = out + strlen(out);
2838e7cbe64fSgw 		}
2839ffb5616eSLin Ling 
2840ffb5616eSLin Ling 		if (current_devid[0] != '\0') {
2841ffb5616eSLin Ling 			if ((outlen += 13 + strlen(current_devid))
2842ffb5616eSLin Ling 			    >= MAX_CMDLINE) {
2843ffb5616eSLin Ling 				errnum = ERR_WONT_FIT;
2844ffb5616eSLin Ling 				return (1);
2845ffb5616eSLin Ling 			}
2846ffb5616eSLin Ling 			grub_sprintf(tmpout,
2847ffb5616eSLin Ling 			    postcomma ? "diskdevid=\"%s\"," : ",diskdevid=\"%s\"",
2848ffb5616eSLin Ling 			    current_devid);
2849051aabe6Staylor 		}
2850e7cbe64fSgw 	}
2851e7cbe64fSgw 
2852b1b8ab34Slling 	strncat(out, in, MAX_CMDLINE);
2853b1b8ab34Slling 	return (0);
2854b1b8ab34Slling }
2855b1b8ab34Slling 
28567c478bd9Sstevel@tonic-gate /* kernel */
28577c478bd9Sstevel@tonic-gate static int
28587c478bd9Sstevel@tonic-gate kernel_func (char *arg, int flags)
28597c478bd9Sstevel@tonic-gate {
28607c478bd9Sstevel@tonic-gate   int len;
28617c478bd9Sstevel@tonic-gate   kernel_t suggested_type = KERNEL_TYPE_NONE;
28627c478bd9Sstevel@tonic-gate   unsigned long load_flags = 0;
28637c478bd9Sstevel@tonic-gate 
28647c478bd9Sstevel@tonic-gate #ifndef AUTO_LINUX_MEM_OPT
28657c478bd9Sstevel@tonic-gate   load_flags |= KERNEL_LOAD_NO_MEM_OPTION;
28667c478bd9Sstevel@tonic-gate #endif
28677c478bd9Sstevel@tonic-gate 
28687c478bd9Sstevel@tonic-gate   /* Deal with GNU-style long options.  */
28697c478bd9Sstevel@tonic-gate   while (1)
28707c478bd9Sstevel@tonic-gate     {
28717c478bd9Sstevel@tonic-gate       /* If the option `--type=TYPE' is specified, convert the string to
28727c478bd9Sstevel@tonic-gate 	 a kernel type.  */
28737c478bd9Sstevel@tonic-gate       if (grub_memcmp (arg, "--type=", 7) == 0)
28747c478bd9Sstevel@tonic-gate 	{
28757c478bd9Sstevel@tonic-gate 	  arg += 7;
28767c478bd9Sstevel@tonic-gate 
28777c478bd9Sstevel@tonic-gate 	  if (grub_memcmp (arg, "netbsd", 6) == 0)
28787c478bd9Sstevel@tonic-gate 	    suggested_type = KERNEL_TYPE_NETBSD;
28797c478bd9Sstevel@tonic-gate 	  else if (grub_memcmp (arg, "freebsd", 7) == 0)
28807c478bd9Sstevel@tonic-gate 	    suggested_type = KERNEL_TYPE_FREEBSD;
28817c478bd9Sstevel@tonic-gate 	  else if (grub_memcmp (arg, "openbsd", 7) == 0)
28827c478bd9Sstevel@tonic-gate 	    /* XXX: For now, OpenBSD is identical to NetBSD, from GRUB's
28837c478bd9Sstevel@tonic-gate 	       point of view.  */
28847c478bd9Sstevel@tonic-gate 	    suggested_type = KERNEL_TYPE_NETBSD;
28857c478bd9Sstevel@tonic-gate 	  else if (grub_memcmp (arg, "linux", 5) == 0)
28867c478bd9Sstevel@tonic-gate 	    suggested_type = KERNEL_TYPE_LINUX;
28877c478bd9Sstevel@tonic-gate 	  else if (grub_memcmp (arg, "biglinux", 8) == 0)
28887c478bd9Sstevel@tonic-gate 	    suggested_type = KERNEL_TYPE_BIG_LINUX;
28897c478bd9Sstevel@tonic-gate 	  else if (grub_memcmp (arg, "multiboot", 9) == 0)
28907c478bd9Sstevel@tonic-gate 	    suggested_type = KERNEL_TYPE_MULTIBOOT;
28917c478bd9Sstevel@tonic-gate 	  else
28927c478bd9Sstevel@tonic-gate 	    {
28937c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_ARGUMENT;
28947c478bd9Sstevel@tonic-gate 	      return 1;
28957c478bd9Sstevel@tonic-gate 	    }
28967c478bd9Sstevel@tonic-gate 	}
28977c478bd9Sstevel@tonic-gate       /* If the `--no-mem-option' is specified, don't pass a Linux's mem
28987c478bd9Sstevel@tonic-gate 	 option automatically. If the kernel is another type, this flag
28997c478bd9Sstevel@tonic-gate 	 has no effect.  */
29007c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--no-mem-option", 15) == 0)
29017c478bd9Sstevel@tonic-gate 	load_flags |= KERNEL_LOAD_NO_MEM_OPTION;
29027c478bd9Sstevel@tonic-gate       else
29037c478bd9Sstevel@tonic-gate 	break;
29047c478bd9Sstevel@tonic-gate 
29057c478bd9Sstevel@tonic-gate       /* Try the next.  */
29067c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
29077c478bd9Sstevel@tonic-gate     }
29087c478bd9Sstevel@tonic-gate 
29097c478bd9Sstevel@tonic-gate   len = grub_strlen (arg);
29107c478bd9Sstevel@tonic-gate 
29117c478bd9Sstevel@tonic-gate   /* Reset MB_CMDLINE.  */
29127c478bd9Sstevel@tonic-gate   mb_cmdline = (char *) MB_CMDLINE_BUF;
29137c478bd9Sstevel@tonic-gate   if (len + 1 > MB_CMDLINE_BUFLEN)
29147c478bd9Sstevel@tonic-gate     {
29157c478bd9Sstevel@tonic-gate       errnum = ERR_WONT_FIT;
29167c478bd9Sstevel@tonic-gate       return 1;
29177c478bd9Sstevel@tonic-gate     }
29187c478bd9Sstevel@tonic-gate 
29197c478bd9Sstevel@tonic-gate   /* Copy the command-line to MB_CMDLINE.  */
29207c478bd9Sstevel@tonic-gate   grub_memmove (mb_cmdline, arg, len + 1);
29217c478bd9Sstevel@tonic-gate   kernel_type = load_image (arg, mb_cmdline, suggested_type, load_flags);
29227c478bd9Sstevel@tonic-gate   if (kernel_type == KERNEL_TYPE_NONE)
29237c478bd9Sstevel@tonic-gate     return 1;
29247c478bd9Sstevel@tonic-gate 
2925b1b8ab34Slling   mb_cmdline += grub_strlen(mb_cmdline) + 1;
29267c478bd9Sstevel@tonic-gate   return 0;
29277c478bd9Sstevel@tonic-gate }
29287c478bd9Sstevel@tonic-gate 
29297c478bd9Sstevel@tonic-gate static struct builtin builtin_kernel =
29307c478bd9Sstevel@tonic-gate {
29317c478bd9Sstevel@tonic-gate   "kernel",
29327c478bd9Sstevel@tonic-gate   kernel_func,
29337c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
29347c478bd9Sstevel@tonic-gate   "kernel [--no-mem-option] [--type=TYPE] FILE [ARG ...]",
29357c478bd9Sstevel@tonic-gate   "Attempt to load the primary boot image from FILE. The rest of the"
29367c478bd9Sstevel@tonic-gate   " line is passed verbatim as the \"kernel command line\".  Any modules"
29377c478bd9Sstevel@tonic-gate   " must be reloaded after using this command. The option --type is used"
29387c478bd9Sstevel@tonic-gate   " to suggest what type of kernel to be loaded. TYPE must be either of"
29397c478bd9Sstevel@tonic-gate   " \"netbsd\", \"freebsd\", \"openbsd\", \"linux\", \"biglinux\" and"
29407c478bd9Sstevel@tonic-gate   " \"multiboot\". The option --no-mem-option tells GRUB not to pass a"
29417c478bd9Sstevel@tonic-gate   " Linux's mem option automatically."
29427c478bd9Sstevel@tonic-gate };
29437c478bd9Sstevel@tonic-gate 
2944342440ecSPrasad Singamsetty int
2945342440ecSPrasad Singamsetty min_mem64_func(char *arg, int flags)
2946342440ecSPrasad Singamsetty {
2947342440ecSPrasad Singamsetty 	if (!safe_parse_maxint(&arg, &min_mem64))
2948342440ecSPrasad Singamsetty 		return (1);
2949342440ecSPrasad Singamsetty }
2950342440ecSPrasad Singamsetty 
2951342440ecSPrasad Singamsetty static struct builtin builtin_min_mem64 =
2952342440ecSPrasad Singamsetty {
2953342440ecSPrasad Singamsetty 	"min_mem64",
2954342440ecSPrasad Singamsetty 	min_mem64_func,
2955342440ecSPrasad Singamsetty 	BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_SCRIPT | BUILTIN_HELP_LIST,
2956342440ecSPrasad Singamsetty 	"min_mem64 <memory in MB>",
2957342440ecSPrasad Singamsetty 	"Sets minimum memory (in MB) required for $ISADIR to expand to amd64, "
2958342440ecSPrasad Singamsetty 	"even on 64-bit capable hardware."
2959342440ecSPrasad Singamsetty };
2960342440ecSPrasad Singamsetty 
2961342440ecSPrasad Singamsetty int
2962342440ecSPrasad Singamsetty check_min_mem64()
2963342440ecSPrasad Singamsetty {
2964342440ecSPrasad Singamsetty 	if (min_mem64 == 0)
2965342440ecSPrasad Singamsetty 		return (1);
2966342440ecSPrasad Singamsetty 
2967342440ecSPrasad Singamsetty 	if ((mbi.mem_upper / 10240) * 11 >= min_mem64)
2968342440ecSPrasad Singamsetty 		return (1);
2969342440ecSPrasad Singamsetty 
2970342440ecSPrasad Singamsetty 	return (0);
2971342440ecSPrasad Singamsetty }
2972ae115bc7Smrj 
2973ae115bc7Smrj static int detect_target_operating_mode();
2974ae115bc7Smrj 
2975ae115bc7Smrj int
2976ae115bc7Smrj amd64_config_cpu(void)
2977ae115bc7Smrj {
2978ae115bc7Smrj         struct amd64_cpuid_regs __vcr, *vcr = &__vcr;
2979ae115bc7Smrj         uint32_t maxeax;
2980ae115bc7Smrj         uint32_t max_maxeax = 0x100;
2981ae115bc7Smrj         char vendor[13];
2982ae115bc7Smrj         int isamd64 = 0;
2983ae115bc7Smrj         uint32_t stdfeatures = 0, xtdfeatures = 0;
2984ae115bc7Smrj         uint64_t efer;
2985ae115bc7Smrj 
2986ae115bc7Smrj         /*
2987ae115bc7Smrj          * This check may seem silly, but if the C preprocesor symbol __amd64
2988ae115bc7Smrj          * is #defined during compilation, something that may outwardly seem
2989ae115bc7Smrj          * like a good idea, uts/common/sys/isa_defs.h will #define _LP64,
2990ae115bc7Smrj          * which will cause uts/common/sys/int_types.h to typedef uint64_t as
2991ae115bc7Smrj          * an unsigned long - which is only 4 bytes in size when using a 32-bit
2992ae115bc7Smrj          * compiler.
2993ae115bc7Smrj          *
2994ae115bc7Smrj          * If that happens, all the page table translation routines will fail
2995ae115bc7Smrj          * horribly, so check the size of uint64_t just to insure some degree
2996ae115bc7Smrj          * of sanity in future operations.
2997ae115bc7Smrj          */
2998ae115bc7Smrj         /*LINTED [sizeof result is invarient]*/
2999ae115bc7Smrj         if (sizeof (uint64_t) != 8)
3000ae115bc7Smrj                 prom_panic("grub compiled improperly, unable to boot "
3001ae115bc7Smrj                     "64-bit AMD64 executables");
3002ae115bc7Smrj 
3003ae115bc7Smrj         /*
3004ae115bc7Smrj          * If the CPU doesn't support the CPUID instruction, it's definitely
3005ae115bc7Smrj          * not an AMD64.
3006ae115bc7Smrj          */
3007ae115bc7Smrj         if (amd64_cpuid_supported() == 0)
3008ae115bc7Smrj                 return (0);
3009ae115bc7Smrj 
3010ae115bc7Smrj         amd64_cpuid_insn(0, vcr);
3011ae115bc7Smrj 
3012ae115bc7Smrj         maxeax = vcr->r_eax;
3013ae115bc7Smrj         {
3014ae115bc7Smrj                 /*LINTED [vendor string from cpuid data]*/
3015ae115bc7Smrj                 uint32_t *iptr = (uint32_t *)vendor;
3016ae115bc7Smrj 
3017ae115bc7Smrj                 *iptr++ = vcr->r_ebx;
3018ae115bc7Smrj                 *iptr++ = vcr->r_edx;
3019ae115bc7Smrj                 *iptr++ = vcr->r_ecx;
3020ae115bc7Smrj 
3021ae115bc7Smrj                 vendor[12] = '\0';
3022ae115bc7Smrj         }
3023ae115bc7Smrj 
3024ae115bc7Smrj         if (maxeax > max_maxeax) {
3025ae115bc7Smrj                 grub_printf("cpu: warning, maxeax was 0x%x -> 0x%x\n",
3026ae115bc7Smrj                     maxeax, max_maxeax);
3027ae115bc7Smrj                 maxeax = max_maxeax;
3028ae115bc7Smrj         }
3029ae115bc7Smrj 
3030ae115bc7Smrj         if (maxeax < 1)
3031ae115bc7Smrj                 return (0);     /* no additional functions, not an AMD64 */
3032ae115bc7Smrj         else {
3033ae115bc7Smrj                 uint_t family, model, step;
3034ae115bc7Smrj 
3035ae115bc7Smrj                 amd64_cpuid_insn(1, vcr);
3036ae115bc7Smrj 
3037ae115bc7Smrj                 /*
3038ae115bc7Smrj                  * All AMD64/IA32e processors technically SHOULD report
3039ae115bc7Smrj                  * themselves as being in family 0xf, but for some reason
3040ae115bc7Smrj                  * Simics doesn't, and this may change in the future, so
3041ae115bc7Smrj                  * don't error out if it's not true.
3042ae115bc7Smrj                  */
3043ae115bc7Smrj                 if ((family = BITX(vcr->r_eax, 11, 8)) == 0xf)
3044ae115bc7Smrj                         family += BITX(vcr->r_eax, 27, 20);
3045ae115bc7Smrj 
3046ae115bc7Smrj                 if ((model = BITX(vcr->r_eax, 7, 4)) == 0xf)
3047ae115bc7Smrj                         model += BITX(vcr->r_eax, 19, 16) << 4;
3048ae115bc7Smrj                 step = BITX(vcr->r_eax, 3, 0);
3049ae115bc7Smrj 
3050ae115bc7Smrj                 grub_printf("cpu: '%s' family %d model %d step %d\n",
3051ae115bc7Smrj                     vendor, family, model, step);
3052ae115bc7Smrj                 stdfeatures = vcr->r_edx;
3053ae115bc7Smrj         }
3054ae115bc7Smrj 
3055ae115bc7Smrj         amd64_cpuid_insn(0x80000000, vcr);
3056ae115bc7Smrj 
3057ae115bc7Smrj         if (vcr->r_eax & 0x80000000) {
3058ae115bc7Smrj                 uint32_t xmaxeax = vcr->r_eax;
3059ae115bc7Smrj                 const uint32_t max_xmaxeax = 0x80000100;
3060ae115bc7Smrj 
3061ae115bc7Smrj                 if (xmaxeax > max_xmaxeax) {
3062ae115bc7Smrj                         grub_printf("amd64: warning, xmaxeax was "
3063ae115bc7Smrj 			    "0x%x -> 0x%x\n", xmaxeax, max_xmaxeax);
3064ae115bc7Smrj                         xmaxeax = max_xmaxeax;
3065ae115bc7Smrj                 }
3066ae115bc7Smrj 
3067ae115bc7Smrj                 if (xmaxeax >= 0x80000001) {
3068ae115bc7Smrj                         amd64_cpuid_insn(0x80000001, vcr);
3069ae115bc7Smrj                         xtdfeatures = vcr->r_edx;
3070ae115bc7Smrj                 }
3071ae115bc7Smrj         }
3072ae115bc7Smrj 
3073ae115bc7Smrj         if (BITX(xtdfeatures, 29, 29))          /* long mode */
3074ae115bc7Smrj                 isamd64++;
3075ae115bc7Smrj         else
3076ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support long mode\n");
3077ae115bc7Smrj 
3078ae115bc7Smrj         if (!BITX(stdfeatures, 0, 0)) {
3079ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support FPU\n");
3080ae115bc7Smrj                 isamd64--;
3081ae115bc7Smrj         }
3082ae115bc7Smrj 
3083ae115bc7Smrj         if (!BITX(stdfeatures, 4, 4)) {
3084ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support TSC\n");
3085ae115bc7Smrj                 isamd64--;
3086ae115bc7Smrj         }
3087ae115bc7Smrj 
3088ae115bc7Smrj         if (!BITX(stdfeatures, 5, 5)) {
3089ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support MSRs\n");
3090ae115bc7Smrj                 isamd64--;
3091ae115bc7Smrj         }
3092ae115bc7Smrj 
3093ae115bc7Smrj         if (!BITX(stdfeatures, 6, 6)) {
3094ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support PAE\n");
3095ae115bc7Smrj                 isamd64--;
3096ae115bc7Smrj         }
3097ae115bc7Smrj 
3098ae115bc7Smrj         if (!BITX(stdfeatures, 8, 8)) {
3099ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support CX8\n");
3100ae115bc7Smrj                 isamd64--;
3101ae115bc7Smrj         }
3102ae115bc7Smrj 
3103ae115bc7Smrj         if (!BITX(stdfeatures, 13, 13)) {
3104ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support PGE\n");
3105ae115bc7Smrj                 isamd64--;
3106ae115bc7Smrj         }
3107ae115bc7Smrj 
3108ae115bc7Smrj         if (!BITX(stdfeatures, 19, 19)) {
3109ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support CLFSH\n");
3110ae115bc7Smrj                 isamd64--;
3111ae115bc7Smrj         }
3112ae115bc7Smrj 
3113ae115bc7Smrj         if (!BITX(stdfeatures, 23, 23)) {
3114ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support MMX\n");
3115ae115bc7Smrj                 isamd64--;
3116ae115bc7Smrj         }
3117ae115bc7Smrj 
3118ae115bc7Smrj         if (!BITX(stdfeatures, 24, 24)) {
3119ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support FXSR\n");
3120ae115bc7Smrj                 isamd64--;
3121ae115bc7Smrj         }
3122ae115bc7Smrj 
3123ae115bc7Smrj         if (!BITX(stdfeatures, 25, 25)) {
3124ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support SSE\n");
3125ae115bc7Smrj                 isamd64--;
3126ae115bc7Smrj         }
3127ae115bc7Smrj 
3128ae115bc7Smrj         if (!BITX(stdfeatures, 26, 26)) {
3129ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support SSE2\n");
3130ae115bc7Smrj                 isamd64--;
3131ae115bc7Smrj         }
3132ae115bc7Smrj 
3133ae115bc7Smrj         if (isamd64 < 1) {
3134ae115bc7Smrj                 grub_printf("amd64: CPU does not support amd64 executables.\n");
3135ae115bc7Smrj                 return (0);
3136ae115bc7Smrj         }
3137ae115bc7Smrj 
3138ae115bc7Smrj         amd64_rdmsr(MSR_AMD_EFER, &efer);
3139ae115bc7Smrj         if (efer & AMD_EFER_SCE)
3140ae115bc7Smrj                 grub_printf("amd64: EFER_SCE (syscall/sysret) already "
3141ae115bc7Smrj 		    "enabled\n");
3142ae115bc7Smrj         if (efer & AMD_EFER_NXE)
3143ae115bc7Smrj                 grub_printf("amd64: EFER_NXE (no-exec prot) already enabled\n");
3144ae115bc7Smrj         if (efer & AMD_EFER_LME)
3145ae115bc7Smrj                 grub_printf("amd64: EFER_LME (long mode) already enabled\n");
3146ae115bc7Smrj 
3147ae115bc7Smrj         return (detect_target_operating_mode());
3148ae115bc7Smrj }
3149ae115bc7Smrj 
3150ae115bc7Smrj static int
3151ae115bc7Smrj detect_target_operating_mode()
3152ae115bc7Smrj {
3153ae115bc7Smrj         int ret, ah;
3154ae115bc7Smrj 
3155ae115bc7Smrj 	ah = get_target_operating_mode();
3156ae115bc7Smrj 
3157ae115bc7Smrj         ah = ah >> 8;
3158ae115bc7Smrj 
3159ae115bc7Smrj 	/* XXX still need to pass back the return from the call  */
3160ae115bc7Smrj 	ret = 0;
3161ae115bc7Smrj 
3162ae115bc7Smrj         if (ah == 0x86 && (ret & CB) != 0) {
3163ae115bc7Smrj                 grub_printf("[BIOS 'Detect Target Operating Mode' "
3164ae115bc7Smrj                     "callback unsupported on this platform]\n");
3165ae115bc7Smrj                 return (1);     /* unsupported, ignore */
3166ae115bc7Smrj         }
3167ae115bc7Smrj 
3168ae115bc7Smrj         if (ah == 0x0 && (ret & CB) == 0) {
3169ae115bc7Smrj                 grub_printf("[BIOS accepted mixed-mode target setting!]\n");
3170ae115bc7Smrj                 return (1);     /* told the bios what we're up to */
3171ae115bc7Smrj         }
3172ae115bc7Smrj 
3173ae115bc7Smrj         if (ah == 0 && ret & CB) {
3174ae115bc7Smrj                 grub_printf("fatal: BIOS reports this machine CANNOT run in "
3175ae115bc7Smrj 		    "mixed 32/64-bit mode!\n");
3176ae115bc7Smrj                 return (0);
3177ae115bc7Smrj         }
3178ae115bc7Smrj 
3179ae115bc7Smrj         grub_printf("warning: BIOS Detect Target Operating Mode callback "
3180ae115bc7Smrj             "confused.\n         %%ax >> 8 = 0x%x, carry = %d\n", ah,
3181ae115bc7Smrj             ret & CB ? 1 : 0);
3182ae115bc7Smrj 
3183ae115bc7Smrj         return (1);
3184ae115bc7Smrj }
3185ae115bc7Smrj 
3186ae115bc7Smrj 
3187ae115bc7Smrj int
3188ae115bc7Smrj isamd64()
3189ae115bc7Smrj {
3190ae115bc7Smrj 	static int ret = -1;
3191ae115bc7Smrj 
3192ae115bc7Smrj 	if (ret == -1)
3193ae115bc7Smrj 		ret = amd64_config_cpu();
3194ae115bc7Smrj 
3195ae115bc7Smrj 	return (ret);
3196ae115bc7Smrj }
3197ae115bc7Smrj 
3198b1b8ab34Slling static void
3199b1b8ab34Slling expand_arch (char *arg, char *newarg)
3200ae115bc7Smrj {
3201ae115bc7Smrj   char *index;
3202ae115bc7Smrj 
3203ae115bc7Smrj   newarg[0] = '\0';
3204ae115bc7Smrj 
3205ae115bc7Smrj   while ((index = strstr(arg, "$ISADIR")) != NULL) {
3206ae115bc7Smrj 
3207ae115bc7Smrj     index[0] = '\0';
3208ae115bc7Smrj     strncat(newarg, arg, MAX_CMDLINE);
3209ae115bc7Smrj     index[0] = '$';
3210ae115bc7Smrj 
3211342440ecSPrasad Singamsetty     if (isamd64() && check_min_mem64())
3212ae115bc7Smrj       strncat(newarg, "amd64", MAX_CMDLINE);
3213ae115bc7Smrj 
3214ae115bc7Smrj     arg = index + 7;
3215ae115bc7Smrj   }
3216ae115bc7Smrj 
3217ae115bc7Smrj   strncat(newarg, arg, MAX_CMDLINE);
3218b1b8ab34Slling   return;
3219ae115bc7Smrj }
3220ae115bc7Smrj 
3221ae115bc7Smrj /* kernel$ */
3222ae115bc7Smrj static int
3223ae115bc7Smrj kernel_dollar_func (char *arg, int flags)
3224ae115bc7Smrj {
3225b1b8ab34Slling   char newarg[MAX_CMDLINE];	/* everything boils down to MAX_CMDLINE */
3226b1b8ab34Slling 
3227b1b8ab34Slling   grub_printf("loading '%s' ...\n", arg);
3228b1b8ab34Slling   expand_arch(arg, newarg);
3229b1b8ab34Slling 
3230b1b8ab34Slling   if (kernel_func(newarg, flags))
3231b1b8ab34Slling 	return (1);
3232b1b8ab34Slling 
3233b1b8ab34Slling   mb_cmdline = (char *)MB_CMDLINE_BUF;
3234ffb5616eSLin Ling   if (expand_dollar_bootfs(newarg, mb_cmdline)) {
3235ffb5616eSLin Ling 	grub_printf("cannot expand $ZFS-BOOTFS for dataset %s\n",
3236ffb5616eSLin Ling 	    current_bootfs);
3237b1b8ab34Slling 	return (1);
3238ffb5616eSLin Ling   }
3239b1b8ab34Slling 
3240b1b8ab34Slling   grub_printf("'%s' is loaded\n", mb_cmdline);
3241b1b8ab34Slling   mb_cmdline += grub_strlen(mb_cmdline) + 1;
3242b1b8ab34Slling 
3243b1b8ab34Slling   return (0);
3244ae115bc7Smrj }
3245ae115bc7Smrj 
3246ae115bc7Smrj static struct builtin builtin_kernel_dollar =
3247ae115bc7Smrj {
3248ae115bc7Smrj   "kernel$",
3249ae115bc7Smrj   kernel_dollar_func,
3250ae115bc7Smrj   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
3251ae115bc7Smrj   "kernel$ [--no-mem-option] [--type=TYPE] FILE [ARG ...]",
3252ae115bc7Smrj   " Just like kernel, but with $ISADIR expansion."
3253ae115bc7Smrj };
3254ae115bc7Smrj 
32557c478bd9Sstevel@tonic-gate 
32567c478bd9Sstevel@tonic-gate /* lock */
32577c478bd9Sstevel@tonic-gate static int
32587c478bd9Sstevel@tonic-gate lock_func (char *arg, int flags)
32597c478bd9Sstevel@tonic-gate {
32607c478bd9Sstevel@tonic-gate   if (! auth && password)
32617c478bd9Sstevel@tonic-gate     {
32627c478bd9Sstevel@tonic-gate       errnum = ERR_PRIVILEGED;
32637c478bd9Sstevel@tonic-gate       return 1;
32647c478bd9Sstevel@tonic-gate     }
32657c478bd9Sstevel@tonic-gate 
32667c478bd9Sstevel@tonic-gate   return 0;
32677c478bd9Sstevel@tonic-gate }
32687c478bd9Sstevel@tonic-gate 
32697c478bd9Sstevel@tonic-gate static struct builtin builtin_lock =
32707c478bd9Sstevel@tonic-gate {
32717c478bd9Sstevel@tonic-gate   "lock",
32727c478bd9Sstevel@tonic-gate   lock_func,
32737c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
32747c478bd9Sstevel@tonic-gate   "lock",
32757c478bd9Sstevel@tonic-gate   "Break a command execution unless the user is authenticated."
32767c478bd9Sstevel@tonic-gate };
32777c478bd9Sstevel@tonic-gate 
32787c478bd9Sstevel@tonic-gate 
32797c478bd9Sstevel@tonic-gate /* makeactive */
32807c478bd9Sstevel@tonic-gate static int
32817c478bd9Sstevel@tonic-gate makeactive_func (char *arg, int flags)
32827c478bd9Sstevel@tonic-gate {
32837c478bd9Sstevel@tonic-gate   if (! make_saved_active ())
32847c478bd9Sstevel@tonic-gate     return 1;
32857c478bd9Sstevel@tonic-gate 
32867c478bd9Sstevel@tonic-gate   return 0;
32877c478bd9Sstevel@tonic-gate }
32887c478bd9Sstevel@tonic-gate 
32897c478bd9Sstevel@tonic-gate static struct builtin builtin_makeactive =
32907c478bd9Sstevel@tonic-gate {
32917c478bd9Sstevel@tonic-gate   "makeactive",
32927c478bd9Sstevel@tonic-gate   makeactive_func,
32937c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
32947c478bd9Sstevel@tonic-gate   "makeactive",
32957c478bd9Sstevel@tonic-gate   "Set the active partition on the root disk to GRUB's root device."
32967c478bd9Sstevel@tonic-gate   " This command is limited to _primary_ PC partitions on a hard disk."
32977c478bd9Sstevel@tonic-gate };
32987c478bd9Sstevel@tonic-gate 
32997c478bd9Sstevel@tonic-gate 
33007c478bd9Sstevel@tonic-gate /* map */
33017c478bd9Sstevel@tonic-gate /* Map FROM_DRIVE to TO_DRIVE.  */
33027c478bd9Sstevel@tonic-gate static int
33037c478bd9Sstevel@tonic-gate map_func (char *arg, int flags)
33047c478bd9Sstevel@tonic-gate {
33057c478bd9Sstevel@tonic-gate   char *to_drive;
33067c478bd9Sstevel@tonic-gate   char *from_drive;
33077c478bd9Sstevel@tonic-gate   unsigned long to, from;
33087c478bd9Sstevel@tonic-gate   int i;
33097c478bd9Sstevel@tonic-gate 
33107c478bd9Sstevel@tonic-gate   to_drive = arg;
33117c478bd9Sstevel@tonic-gate   from_drive = skip_to (0, arg);
33127c478bd9Sstevel@tonic-gate 
33137c478bd9Sstevel@tonic-gate   /* Get the drive number for TO_DRIVE.  */
33147c478bd9Sstevel@tonic-gate   set_device (to_drive);
33157c478bd9Sstevel@tonic-gate   if (errnum)
33167c478bd9Sstevel@tonic-gate     return 1;
33177c478bd9Sstevel@tonic-gate   to = current_drive;
33187c478bd9Sstevel@tonic-gate 
33197c478bd9Sstevel@tonic-gate   /* Get the drive number for FROM_DRIVE.  */
33207c478bd9Sstevel@tonic-gate   set_device (from_drive);
33217c478bd9Sstevel@tonic-gate   if (errnum)
33227c478bd9Sstevel@tonic-gate     return 1;
33237c478bd9Sstevel@tonic-gate   from = current_drive;
33247c478bd9Sstevel@tonic-gate 
33257c478bd9Sstevel@tonic-gate   /* Search for an empty slot in BIOS_DRIVE_MAP.  */
33267c478bd9Sstevel@tonic-gate   for (i = 0; i < DRIVE_MAP_SIZE; i++)
33277c478bd9Sstevel@tonic-gate     {
33287c478bd9Sstevel@tonic-gate       /* Perhaps the user wants to override the map.  */
33297c478bd9Sstevel@tonic-gate       if ((bios_drive_map[i] & 0xff) == from)
33307c478bd9Sstevel@tonic-gate 	break;
33317c478bd9Sstevel@tonic-gate 
33327c478bd9Sstevel@tonic-gate       if (! bios_drive_map[i])
33337c478bd9Sstevel@tonic-gate 	break;
33347c478bd9Sstevel@tonic-gate     }
33357c478bd9Sstevel@tonic-gate 
33367c478bd9Sstevel@tonic-gate   if (i == DRIVE_MAP_SIZE)
33377c478bd9Sstevel@tonic-gate     {
33387c478bd9Sstevel@tonic-gate       errnum = ERR_WONT_FIT;
33397c478bd9Sstevel@tonic-gate       return 1;
33407c478bd9Sstevel@tonic-gate     }
33417c478bd9Sstevel@tonic-gate 
33427c478bd9Sstevel@tonic-gate   if (to == from)
33437c478bd9Sstevel@tonic-gate     /* If TO is equal to FROM, delete the entry.  */
33447c478bd9Sstevel@tonic-gate     grub_memmove ((char *) &bios_drive_map[i], (char *) &bios_drive_map[i + 1],
33457c478bd9Sstevel@tonic-gate 		  sizeof (unsigned short) * (DRIVE_MAP_SIZE - i));
33467c478bd9Sstevel@tonic-gate   else
33477c478bd9Sstevel@tonic-gate     bios_drive_map[i] = from | (to << 8);
33487c478bd9Sstevel@tonic-gate 
33497c478bd9Sstevel@tonic-gate   return 0;
33507c478bd9Sstevel@tonic-gate }
33517c478bd9Sstevel@tonic-gate 
33527c478bd9Sstevel@tonic-gate static struct builtin builtin_map =
33537c478bd9Sstevel@tonic-gate {
33547c478bd9Sstevel@tonic-gate   "map",
33557c478bd9Sstevel@tonic-gate   map_func,
33567c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
33577c478bd9Sstevel@tonic-gate   "map TO_DRIVE FROM_DRIVE",
33587c478bd9Sstevel@tonic-gate   "Map the drive FROM_DRIVE to the drive TO_DRIVE. This is necessary"
33597c478bd9Sstevel@tonic-gate   " when you chain-load some operating systems, such as DOS, if such an"
33607c478bd9Sstevel@tonic-gate   " OS resides at a non-first drive."
33617c478bd9Sstevel@tonic-gate };
33627c478bd9Sstevel@tonic-gate 
33637c478bd9Sstevel@tonic-gate 
33647c478bd9Sstevel@tonic-gate #ifdef USE_MD5_PASSWORDS
33657c478bd9Sstevel@tonic-gate /* md5crypt */
33667c478bd9Sstevel@tonic-gate static int
33677c478bd9Sstevel@tonic-gate md5crypt_func (char *arg, int flags)
33687c478bd9Sstevel@tonic-gate {
33697c478bd9Sstevel@tonic-gate   char crypted[36];
33707c478bd9Sstevel@tonic-gate   char key[32];
33717c478bd9Sstevel@tonic-gate   unsigned int seed;
33727c478bd9Sstevel@tonic-gate   int i;
33737c478bd9Sstevel@tonic-gate   const char *const seedchars =
33747c478bd9Sstevel@tonic-gate     "./0123456789ABCDEFGHIJKLMNOPQRST"
33757c478bd9Sstevel@tonic-gate     "UVWXYZabcdefghijklmnopqrstuvwxyz";
33767c478bd9Sstevel@tonic-gate 
33777c478bd9Sstevel@tonic-gate   /* First create a salt.  */
33787c478bd9Sstevel@tonic-gate 
33797c478bd9Sstevel@tonic-gate   /* The magical prefix.  */
33807c478bd9Sstevel@tonic-gate   grub_memset (crypted, 0, sizeof (crypted));
33817c478bd9Sstevel@tonic-gate   grub_memmove (crypted, "$1$", 3);
33827c478bd9Sstevel@tonic-gate 
33837c478bd9Sstevel@tonic-gate   /* Create the length of a salt.  */
33847c478bd9Sstevel@tonic-gate   seed = currticks ();
33857c478bd9Sstevel@tonic-gate 
33867c478bd9Sstevel@tonic-gate   /* Generate a salt.  */
33877c478bd9Sstevel@tonic-gate   for (i = 0; i < 8 && seed; i++)
33887c478bd9Sstevel@tonic-gate     {
33897c478bd9Sstevel@tonic-gate       /* FIXME: This should be more random.  */
33907c478bd9Sstevel@tonic-gate       crypted[3 + i] = seedchars[seed & 0x3f];
33917c478bd9Sstevel@tonic-gate       seed >>= 6;
33927c478bd9Sstevel@tonic-gate     }
33937c478bd9Sstevel@tonic-gate 
33947c478bd9Sstevel@tonic-gate   /* A salt must be terminated with `$', if it is less than 8 chars.  */
33957c478bd9Sstevel@tonic-gate   crypted[3 + i] = '$';
33967c478bd9Sstevel@tonic-gate 
33977c478bd9Sstevel@tonic-gate #ifdef DEBUG_MD5CRYPT
33987c478bd9Sstevel@tonic-gate   grub_printf ("salt = %s\n", crypted);
33997c478bd9Sstevel@tonic-gate #endif
34007c478bd9Sstevel@tonic-gate 
34017c478bd9Sstevel@tonic-gate   /* Get a password.  */
34027c478bd9Sstevel@tonic-gate   grub_memset (key, 0, sizeof (key));
34037c478bd9Sstevel@tonic-gate   get_cmdline ("Password: ", key, sizeof (key) - 1, '*', 0);
34047c478bd9Sstevel@tonic-gate 
34057c478bd9Sstevel@tonic-gate   /* Crypt the key.  */
34067c478bd9Sstevel@tonic-gate   make_md5_password (key, crypted);
34077c478bd9Sstevel@tonic-gate 
34087c478bd9Sstevel@tonic-gate   grub_printf ("Encrypted: %s\n", crypted);
34097c478bd9Sstevel@tonic-gate   return 0;
34107c478bd9Sstevel@tonic-gate }
34117c478bd9Sstevel@tonic-gate 
34127c478bd9Sstevel@tonic-gate static struct builtin builtin_md5crypt =
34137c478bd9Sstevel@tonic-gate {
34147c478bd9Sstevel@tonic-gate   "md5crypt",
34157c478bd9Sstevel@tonic-gate   md5crypt_func,
34167c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
34177c478bd9Sstevel@tonic-gate   "md5crypt",
34187c478bd9Sstevel@tonic-gate   "Generate a password in MD5 format."
34197c478bd9Sstevel@tonic-gate };
34207c478bd9Sstevel@tonic-gate #endif /* USE_MD5_PASSWORDS */
34217c478bd9Sstevel@tonic-gate 
34227c478bd9Sstevel@tonic-gate 
34237c478bd9Sstevel@tonic-gate /* module */
34247c478bd9Sstevel@tonic-gate static int
34257c478bd9Sstevel@tonic-gate module_func (char *arg, int flags)
34267c478bd9Sstevel@tonic-gate {
34277c478bd9Sstevel@tonic-gate   int len = grub_strlen (arg);
34287c478bd9Sstevel@tonic-gate 
34297c478bd9Sstevel@tonic-gate   switch (kernel_type)
34307c478bd9Sstevel@tonic-gate     {
34317c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_MULTIBOOT:
34327c478bd9Sstevel@tonic-gate       if (mb_cmdline + len + 1 > (char *) MB_CMDLINE_BUF + MB_CMDLINE_BUFLEN)
34337c478bd9Sstevel@tonic-gate 	{
34347c478bd9Sstevel@tonic-gate 	  errnum = ERR_WONT_FIT;
34357c478bd9Sstevel@tonic-gate 	  return 1;
34367c478bd9Sstevel@tonic-gate 	}
34377c478bd9Sstevel@tonic-gate       grub_memmove (mb_cmdline, arg, len + 1);
34387c478bd9Sstevel@tonic-gate       if (! load_module (arg, mb_cmdline))
34397c478bd9Sstevel@tonic-gate 	return 1;
3440b1b8ab34Slling 
3441b1b8ab34Slling       mb_cmdline += grub_strlen(mb_cmdline) + 1;
34427c478bd9Sstevel@tonic-gate       break;
34437c478bd9Sstevel@tonic-gate 
34447c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_LINUX:
34457c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_BIG_LINUX:
34467c478bd9Sstevel@tonic-gate       if (! load_initrd (arg))
34477c478bd9Sstevel@tonic-gate 	return 1;
34487c478bd9Sstevel@tonic-gate       break;
34497c478bd9Sstevel@tonic-gate 
34507c478bd9Sstevel@tonic-gate     default:
34517c478bd9Sstevel@tonic-gate       errnum = ERR_NEED_MB_KERNEL;
34527c478bd9Sstevel@tonic-gate       return 1;
34537c478bd9Sstevel@tonic-gate     }
34547c478bd9Sstevel@tonic-gate 
34557c478bd9Sstevel@tonic-gate   return 0;
34567c478bd9Sstevel@tonic-gate }
34577c478bd9Sstevel@tonic-gate 
34587c478bd9Sstevel@tonic-gate static struct builtin builtin_module =
34597c478bd9Sstevel@tonic-gate {
34607c478bd9Sstevel@tonic-gate   "module",
34617c478bd9Sstevel@tonic-gate   module_func,
34627c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
34637c478bd9Sstevel@tonic-gate   "module FILE [ARG ...]",
34647c478bd9Sstevel@tonic-gate   "Load a boot module FILE for a Multiboot format boot image (no"
34657c478bd9Sstevel@tonic-gate   " interpretation of the file contents is made, so users of this"
34667c478bd9Sstevel@tonic-gate   " command must know what the kernel in question expects). The"
34677c478bd9Sstevel@tonic-gate   " rest of the line is passed as the \"module command line\", like"
34687c478bd9Sstevel@tonic-gate   " the `kernel' command."
34697c478bd9Sstevel@tonic-gate };
34707c478bd9Sstevel@tonic-gate 
3471ae115bc7Smrj /* module$ */
3472ae115bc7Smrj static int
3473ae115bc7Smrj module_dollar_func (char *arg, int flags)
3474ae115bc7Smrj {
3475b1b8ab34Slling   char newarg[MAX_CMDLINE];	/* everything boils down to MAX_CMDLINE */
3476b1b8ab34Slling   char *cmdline_sav;
3477b1b8ab34Slling 
3478b1b8ab34Slling   grub_printf("loading '%s' ...\n", arg);
3479b1b8ab34Slling   expand_arch(arg, newarg);
3480b1b8ab34Slling 
3481b1b8ab34Slling   cmdline_sav = (char *)mb_cmdline;
3482b1b8ab34Slling   if (module_func(newarg, flags))
3483b1b8ab34Slling 	return (1);
3484b1b8ab34Slling 
3485ffb5616eSLin Ling   if (expand_dollar_bootfs(newarg, cmdline_sav)) {
3486ffb5616eSLin Ling 	grub_printf("cannot expand $ZFS-BOOTFS for dataset %s\n",
3487ffb5616eSLin Ling 	    current_bootfs);
3488b1b8ab34Slling 	return (1);
3489ffb5616eSLin Ling   }
3490b1b8ab34Slling 
3491b1b8ab34Slling   grub_printf("'%s' is loaded\n", (char *)cmdline_sav);
3492b1b8ab34Slling   mb_cmdline += grub_strlen(cmdline_sav) + 1;
3493b1b8ab34Slling 
3494b1b8ab34Slling   return (0);
3495ae115bc7Smrj }
3496ae115bc7Smrj 
3497ae115bc7Smrj static struct builtin builtin_module_dollar =
3498ae115bc7Smrj {
3499ae115bc7Smrj   "module$",
3500ae115bc7Smrj   module_dollar_func,
3501ae115bc7Smrj   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
3502ae115bc7Smrj   "module FILE [ARG ...]",
3503ae115bc7Smrj   " Just like module, but with $ISADIR expansion."
3504ae115bc7Smrj };
3505ae115bc7Smrj 
35067c478bd9Sstevel@tonic-gate 
35077c478bd9Sstevel@tonic-gate /* modulenounzip */
35087c478bd9Sstevel@tonic-gate static int
35097c478bd9Sstevel@tonic-gate modulenounzip_func (char *arg, int flags)
35107c478bd9Sstevel@tonic-gate {
35117c478bd9Sstevel@tonic-gate   int ret;
35127c478bd9Sstevel@tonic-gate 
35137c478bd9Sstevel@tonic-gate #ifndef NO_DECOMPRESSION
35147c478bd9Sstevel@tonic-gate   no_decompression = 1;
35157c478bd9Sstevel@tonic-gate #endif
35167c478bd9Sstevel@tonic-gate 
35177c478bd9Sstevel@tonic-gate   ret = module_func (arg, flags);
35187c478bd9Sstevel@tonic-gate 
35197c478bd9Sstevel@tonic-gate #ifndef NO_DECOMPRESSION
35207c478bd9Sstevel@tonic-gate   no_decompression = 0;
35217c478bd9Sstevel@tonic-gate #endif
35227c478bd9Sstevel@tonic-gate 
35237c478bd9Sstevel@tonic-gate   return ret;
35247c478bd9Sstevel@tonic-gate }
35257c478bd9Sstevel@tonic-gate 
35267c478bd9Sstevel@tonic-gate static struct builtin builtin_modulenounzip =
35277c478bd9Sstevel@tonic-gate {
35287c478bd9Sstevel@tonic-gate   "modulenounzip",
35297c478bd9Sstevel@tonic-gate   modulenounzip_func,
35307c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
35317c478bd9Sstevel@tonic-gate   "modulenounzip FILE [ARG ...]",
35327c478bd9Sstevel@tonic-gate   "The same as `module', except that automatic decompression is"
35337c478bd9Sstevel@tonic-gate   " disabled."
35347c478bd9Sstevel@tonic-gate };
35357c478bd9Sstevel@tonic-gate 
35367c478bd9Sstevel@tonic-gate 
35377c478bd9Sstevel@tonic-gate /* pager [on|off] */
35387c478bd9Sstevel@tonic-gate static int
35397c478bd9Sstevel@tonic-gate pager_func (char *arg, int flags)
35407c478bd9Sstevel@tonic-gate {
35417c478bd9Sstevel@tonic-gate   /* If ARG is empty, toggle the flag.  */
35427c478bd9Sstevel@tonic-gate   if (! *arg)
35437c478bd9Sstevel@tonic-gate     use_pager = ! use_pager;
35447c478bd9Sstevel@tonic-gate   else if (grub_memcmp (arg, "on", 2) == 0)
35457c478bd9Sstevel@tonic-gate     use_pager = 1;
35467c478bd9Sstevel@tonic-gate   else if (grub_memcmp (arg, "off", 3) == 0)
35477c478bd9Sstevel@tonic-gate     use_pager = 0;
35487c478bd9Sstevel@tonic-gate   else
35497c478bd9Sstevel@tonic-gate     {
35507c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
35517c478bd9Sstevel@tonic-gate       return 1;
35527c478bd9Sstevel@tonic-gate     }
35537c478bd9Sstevel@tonic-gate 
35547c478bd9Sstevel@tonic-gate   grub_printf (" Internal pager is now %s\n", use_pager ? "on" : "off");
35557c478bd9Sstevel@tonic-gate   return 0;
35567c478bd9Sstevel@tonic-gate }
35577c478bd9Sstevel@tonic-gate 
35587c478bd9Sstevel@tonic-gate static struct builtin builtin_pager =
35597c478bd9Sstevel@tonic-gate {
35607c478bd9Sstevel@tonic-gate   "pager",
35617c478bd9Sstevel@tonic-gate   pager_func,
35627c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
35637c478bd9Sstevel@tonic-gate   "pager [FLAG]",
35647c478bd9Sstevel@tonic-gate   "Toggle pager mode with no argument. If FLAG is given and its value"
35657c478bd9Sstevel@tonic-gate   " is `on', turn on the mode. If FLAG is `off', turn off the mode."
35667c478bd9Sstevel@tonic-gate };
35677c478bd9Sstevel@tonic-gate 
35687c478bd9Sstevel@tonic-gate 
35697c478bd9Sstevel@tonic-gate /* partnew PART TYPE START LEN */
35707c478bd9Sstevel@tonic-gate static int
35717c478bd9Sstevel@tonic-gate partnew_func (char *arg, int flags)
35727c478bd9Sstevel@tonic-gate {
35737c478bd9Sstevel@tonic-gate   int new_type, new_start, new_len;
35747c478bd9Sstevel@tonic-gate   int start_cl, start_ch, start_dh;
35757c478bd9Sstevel@tonic-gate   int end_cl, end_ch, end_dh;
35767c478bd9Sstevel@tonic-gate   int entry;
35777c478bd9Sstevel@tonic-gate   char mbr[512];
35787c478bd9Sstevel@tonic-gate 
35797c478bd9Sstevel@tonic-gate   /* Convert a LBA address to a CHS address in the INT 13 format.  */
35807c478bd9Sstevel@tonic-gate   auto void lba_to_chs (int lba, int *cl, int *ch, int *dh);
35817c478bd9Sstevel@tonic-gate   void lba_to_chs (int lba, int *cl, int *ch, int *dh)
35827c478bd9Sstevel@tonic-gate     {
35837c478bd9Sstevel@tonic-gate       int cylinder, head, sector;
35847c478bd9Sstevel@tonic-gate 
35857c478bd9Sstevel@tonic-gate       sector = lba % buf_geom.sectors + 1;
35867c478bd9Sstevel@tonic-gate       head = (lba / buf_geom.sectors) % buf_geom.heads;
35877c478bd9Sstevel@tonic-gate       cylinder = lba / (buf_geom.sectors * buf_geom.heads);
35887c478bd9Sstevel@tonic-gate 
35897c478bd9Sstevel@tonic-gate       if (cylinder >= buf_geom.cylinders)
35907c478bd9Sstevel@tonic-gate 	cylinder = buf_geom.cylinders - 1;
35917c478bd9Sstevel@tonic-gate 
35927c478bd9Sstevel@tonic-gate       *cl = sector | ((cylinder & 0x300) >> 2);
35937c478bd9Sstevel@tonic-gate       *ch = cylinder & 0xFF;
35947c478bd9Sstevel@tonic-gate       *dh = head;
35957c478bd9Sstevel@tonic-gate     }
35967c478bd9Sstevel@tonic-gate 
35977c478bd9Sstevel@tonic-gate   /* Get the drive and the partition.  */
35987c478bd9Sstevel@tonic-gate   if (! set_device (arg))
35997c478bd9Sstevel@tonic-gate     return 1;
36007c478bd9Sstevel@tonic-gate 
36017c478bd9Sstevel@tonic-gate   /* The drive must be a hard disk.  */
36027c478bd9Sstevel@tonic-gate   if (! (current_drive & 0x80))
36037c478bd9Sstevel@tonic-gate     {
36047c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
36057c478bd9Sstevel@tonic-gate       return 1;
36067c478bd9Sstevel@tonic-gate     }
36077c478bd9Sstevel@tonic-gate 
36087c478bd9Sstevel@tonic-gate   /* The partition must a primary partition.  */
36097c478bd9Sstevel@tonic-gate   if ((current_partition >> 16) > 3
36107c478bd9Sstevel@tonic-gate       || (current_partition & 0xFFFF) != 0xFFFF)
36117c478bd9Sstevel@tonic-gate     {
36127c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
36137c478bd9Sstevel@tonic-gate       return 1;
36147c478bd9Sstevel@tonic-gate     }
36157c478bd9Sstevel@tonic-gate 
36167c478bd9Sstevel@tonic-gate   entry = current_partition >> 16;
36177c478bd9Sstevel@tonic-gate 
36187c478bd9Sstevel@tonic-gate   /* Get the new partition type.  */
36197c478bd9Sstevel@tonic-gate   arg = skip_to (0, arg);
36207c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &new_type))
36217c478bd9Sstevel@tonic-gate     return 1;
36227c478bd9Sstevel@tonic-gate 
36237c478bd9Sstevel@tonic-gate   /* The partition type is unsigned char.  */
36247c478bd9Sstevel@tonic-gate   if (new_type > 0xFF)
36257c478bd9Sstevel@tonic-gate     {
36267c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
36277c478bd9Sstevel@tonic-gate       return 1;
36287c478bd9Sstevel@tonic-gate     }
36297c478bd9Sstevel@tonic-gate 
36307c478bd9Sstevel@tonic-gate   /* Get the new partition start.  */
36317c478bd9Sstevel@tonic-gate   arg = skip_to (0, arg);
36327c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &new_start))
36337c478bd9Sstevel@tonic-gate     return 1;
36347c478bd9Sstevel@tonic-gate 
36357c478bd9Sstevel@tonic-gate   /* Get the new partition length.  */
36367c478bd9Sstevel@tonic-gate   arg = skip_to (0, arg);
36377c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &new_len))
36387c478bd9Sstevel@tonic-gate     return 1;
36397c478bd9Sstevel@tonic-gate 
36407c478bd9Sstevel@tonic-gate   /* Read the MBR.  */
36417c478bd9Sstevel@tonic-gate   if (! rawread (current_drive, 0, 0, SECTOR_SIZE, mbr))
36427c478bd9Sstevel@tonic-gate     return 1;
36437c478bd9Sstevel@tonic-gate 
36447c478bd9Sstevel@tonic-gate   /* Check if the new partition will fit in the disk.  */
36457c478bd9Sstevel@tonic-gate   if (new_start + new_len > buf_geom.total_sectors)
36467c478bd9Sstevel@tonic-gate     {
36477c478bd9Sstevel@tonic-gate       errnum = ERR_GEOM;
36487c478bd9Sstevel@tonic-gate       return 1;
36497c478bd9Sstevel@tonic-gate     }
36507c478bd9Sstevel@tonic-gate 
36517c478bd9Sstevel@tonic-gate   /* Store the partition information in the MBR.  */
36527c478bd9Sstevel@tonic-gate   lba_to_chs (new_start, &start_cl, &start_ch, &start_dh);
36537c478bd9Sstevel@tonic-gate   lba_to_chs (new_start + new_len - 1, &end_cl, &end_ch, &end_dh);
36547c478bd9Sstevel@tonic-gate 
36557c478bd9Sstevel@tonic-gate   PC_SLICE_FLAG (mbr, entry) = 0;
36567c478bd9Sstevel@tonic-gate   PC_SLICE_HEAD (mbr, entry) = start_dh;
36577c478bd9Sstevel@tonic-gate   PC_SLICE_SEC (mbr, entry) = start_cl;
36587c478bd9Sstevel@tonic-gate   PC_SLICE_CYL (mbr, entry) = start_ch;
36597c478bd9Sstevel@tonic-gate   PC_SLICE_TYPE (mbr, entry) = new_type;
36607c478bd9Sstevel@tonic-gate   PC_SLICE_EHEAD (mbr, entry) = end_dh;
36617c478bd9Sstevel@tonic-gate   PC_SLICE_ESEC (mbr, entry) = end_cl;
36627c478bd9Sstevel@tonic-gate   PC_SLICE_ECYL (mbr, entry) = end_ch;
36637c478bd9Sstevel@tonic-gate   PC_SLICE_START (mbr, entry) = new_start;
36647c478bd9Sstevel@tonic-gate   PC_SLICE_LENGTH (mbr, entry) = new_len;
36657c478bd9Sstevel@tonic-gate 
36667c478bd9Sstevel@tonic-gate   /* Make sure that the MBR has a valid signature.  */
36677c478bd9Sstevel@tonic-gate   PC_MBR_SIG (mbr) = PC_MBR_SIGNATURE;
36687c478bd9Sstevel@tonic-gate 
36697c478bd9Sstevel@tonic-gate   /* Write back the MBR to the disk.  */
3670342440ecSPrasad Singamsetty   buf_track = BUF_CACHE_INVALID;
36717c478bd9Sstevel@tonic-gate   if (! rawwrite (current_drive, 0, mbr))
36727c478bd9Sstevel@tonic-gate     return 1;
36737c478bd9Sstevel@tonic-gate 
36747c478bd9Sstevel@tonic-gate   return 0;
36757c478bd9Sstevel@tonic-gate }
36767c478bd9Sstevel@tonic-gate 
36777c478bd9Sstevel@tonic-gate static struct builtin builtin_partnew =
36787c478bd9Sstevel@tonic-gate {
36797c478bd9Sstevel@tonic-gate   "partnew",
36807c478bd9Sstevel@tonic-gate   partnew_func,
36817c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
36827c478bd9Sstevel@tonic-gate   "partnew PART TYPE START LEN",
36837c478bd9Sstevel@tonic-gate   "Create a primary partition at the starting address START with the"
36847c478bd9Sstevel@tonic-gate   " length LEN, with the type TYPE. START and LEN are in sector units."
36857c478bd9Sstevel@tonic-gate };
36867c478bd9Sstevel@tonic-gate 
36877c478bd9Sstevel@tonic-gate 
36887c478bd9Sstevel@tonic-gate /* parttype PART TYPE */
36897c478bd9Sstevel@tonic-gate static int
36907c478bd9Sstevel@tonic-gate parttype_func (char *arg, int flags)
36917c478bd9Sstevel@tonic-gate {
36927c478bd9Sstevel@tonic-gate   int new_type;
36937c478bd9Sstevel@tonic-gate   unsigned long part = 0xFFFFFF;
36947c478bd9Sstevel@tonic-gate   unsigned long start, len, offset, ext_offset;
36957c478bd9Sstevel@tonic-gate   int entry, type;
36967c478bd9Sstevel@tonic-gate   char mbr[512];
36977c478bd9Sstevel@tonic-gate 
36987c478bd9Sstevel@tonic-gate   /* Get the drive and the partition.  */
36997c478bd9Sstevel@tonic-gate   if (! set_device (arg))
37007c478bd9Sstevel@tonic-gate     return 1;
37017c478bd9Sstevel@tonic-gate 
37027c478bd9Sstevel@tonic-gate   /* The drive must be a hard disk.  */
37037c478bd9Sstevel@tonic-gate   if (! (current_drive & 0x80))
37047c478bd9Sstevel@tonic-gate     {
37057c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
37067c478bd9Sstevel@tonic-gate       return 1;
37077c478bd9Sstevel@tonic-gate     }
37087c478bd9Sstevel@tonic-gate 
37097c478bd9Sstevel@tonic-gate   /* The partition must be a PC slice.  */
37107c478bd9Sstevel@tonic-gate   if ((current_partition >> 16) == 0xFF
37117c478bd9Sstevel@tonic-gate       || (current_partition & 0xFFFF) != 0xFFFF)
37127c478bd9Sstevel@tonic-gate     {
37137c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
37147c478bd9Sstevel@tonic-gate       return 1;
37157c478bd9Sstevel@tonic-gate     }
37167c478bd9Sstevel@tonic-gate 
37177c478bd9Sstevel@tonic-gate   /* Get the new partition type.  */
37187c478bd9Sstevel@tonic-gate   arg = skip_to (0, arg);
37197c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &new_type))
37207c478bd9Sstevel@tonic-gate     return 1;
37217c478bd9Sstevel@tonic-gate 
37227c478bd9Sstevel@tonic-gate   /* The partition type is unsigned char.  */
37237c478bd9Sstevel@tonic-gate   if (new_type > 0xFF)
37247c478bd9Sstevel@tonic-gate     {
37257c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
37267c478bd9Sstevel@tonic-gate       return 1;
37277c478bd9Sstevel@tonic-gate     }
37287c478bd9Sstevel@tonic-gate 
37297c478bd9Sstevel@tonic-gate   /* Look for the partition.  */
37307c478bd9Sstevel@tonic-gate   while (next_partition (current_drive, 0xFFFFFF, &part, &type,
37317c478bd9Sstevel@tonic-gate 			 &start, &len, &offset, &entry,
37327c478bd9Sstevel@tonic-gate 			 &ext_offset, mbr))
37337c478bd9Sstevel@tonic-gate     {
37347c478bd9Sstevel@tonic-gate       if (part == current_partition)
37357c478bd9Sstevel@tonic-gate 	{
37367c478bd9Sstevel@tonic-gate 	  /* Found.  */
37377c478bd9Sstevel@tonic-gate 
37387c478bd9Sstevel@tonic-gate 	  /* Set the type to NEW_TYPE.  */
37397c478bd9Sstevel@tonic-gate 	  PC_SLICE_TYPE (mbr, entry) = new_type;
37407c478bd9Sstevel@tonic-gate 
37417c478bd9Sstevel@tonic-gate 	  /* Write back the MBR to the disk.  */
3742342440ecSPrasad Singamsetty 	  buf_track = BUF_CACHE_INVALID;
37437c478bd9Sstevel@tonic-gate 	  if (! rawwrite (current_drive, offset, mbr))
37447c478bd9Sstevel@tonic-gate 	    return 1;
37457c478bd9Sstevel@tonic-gate 
37467c478bd9Sstevel@tonic-gate 	  /* Succeed.  */
37477c478bd9Sstevel@tonic-gate 	  return 0;
37487c478bd9Sstevel@tonic-gate 	}
37497c478bd9Sstevel@tonic-gate     }
37507c478bd9Sstevel@tonic-gate 
37517c478bd9Sstevel@tonic-gate   /* The partition was not found.  ERRNUM was set by next_partition.  */
37527c478bd9Sstevel@tonic-gate   return 1;
37537c478bd9Sstevel@tonic-gate }
37547c478bd9Sstevel@tonic-gate 
37557c478bd9Sstevel@tonic-gate static struct builtin builtin_parttype =
37567c478bd9Sstevel@tonic-gate {
37577c478bd9Sstevel@tonic-gate   "parttype",
37587c478bd9Sstevel@tonic-gate   parttype_func,
37597c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
37607c478bd9Sstevel@tonic-gate   "parttype PART TYPE",
37617c478bd9Sstevel@tonic-gate   "Change the type of the partition PART to TYPE."
37627c478bd9Sstevel@tonic-gate };
37637c478bd9Sstevel@tonic-gate 
37647c478bd9Sstevel@tonic-gate 
37657c478bd9Sstevel@tonic-gate /* password */
37667c478bd9Sstevel@tonic-gate static int
37677c478bd9Sstevel@tonic-gate password_func (char *arg, int flags)
37687c478bd9Sstevel@tonic-gate {
37697c478bd9Sstevel@tonic-gate   int len;
37707c478bd9Sstevel@tonic-gate   password_t type = PASSWORD_PLAIN;
37717c478bd9Sstevel@tonic-gate 
37727c478bd9Sstevel@tonic-gate #ifdef USE_MD5_PASSWORDS
37737c478bd9Sstevel@tonic-gate   if (grub_memcmp (arg, "--md5", 5) == 0)
37747c478bd9Sstevel@tonic-gate     {
37757c478bd9Sstevel@tonic-gate       type = PASSWORD_MD5;
37767c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
37777c478bd9Sstevel@tonic-gate     }
37787c478bd9Sstevel@tonic-gate #endif
37797c478bd9Sstevel@tonic-gate   if (grub_memcmp (arg, "--", 2) == 0)
37807c478bd9Sstevel@tonic-gate     {
37817c478bd9Sstevel@tonic-gate       type = PASSWORD_UNSUPPORTED;
37827c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
37837c478bd9Sstevel@tonic-gate     }
37847c478bd9Sstevel@tonic-gate 
37857c478bd9Sstevel@tonic-gate   if ((flags & (BUILTIN_CMDLINE | BUILTIN_SCRIPT)) != 0)
37867c478bd9Sstevel@tonic-gate     {
37877c478bd9Sstevel@tonic-gate       /* Do password check! */
37887c478bd9Sstevel@tonic-gate       char entered[32];
37897c478bd9Sstevel@tonic-gate 
37907c478bd9Sstevel@tonic-gate       /* Wipe out any previously entered password */
37917c478bd9Sstevel@tonic-gate       entered[0] = 0;
37927c478bd9Sstevel@tonic-gate       get_cmdline ("Password: ", entered, 31, '*', 0);
37937c478bd9Sstevel@tonic-gate 
37947c478bd9Sstevel@tonic-gate       nul_terminate (arg);
37957c478bd9Sstevel@tonic-gate       if (check_password (entered, arg, type) != 0)
37967c478bd9Sstevel@tonic-gate 	{
37977c478bd9Sstevel@tonic-gate 	  errnum = ERR_PRIVILEGED;
37987c478bd9Sstevel@tonic-gate 	  return 1;
37997c478bd9Sstevel@tonic-gate 	}
38007c478bd9Sstevel@tonic-gate     }
38017c478bd9Sstevel@tonic-gate   else
38027c478bd9Sstevel@tonic-gate     {
38037c478bd9Sstevel@tonic-gate       len = grub_strlen (arg);
38047c478bd9Sstevel@tonic-gate 
38057c478bd9Sstevel@tonic-gate       /* PASSWORD NUL NUL ... */
38067c478bd9Sstevel@tonic-gate       if (len + 2 > PASSWORD_BUFLEN)
38077c478bd9Sstevel@tonic-gate 	{
38087c478bd9Sstevel@tonic-gate 	  errnum = ERR_WONT_FIT;
38097c478bd9Sstevel@tonic-gate 	  return 1;
38107c478bd9Sstevel@tonic-gate 	}
38117c478bd9Sstevel@tonic-gate 
38127c478bd9Sstevel@tonic-gate       /* Copy the password and clear the rest of the buffer.  */
38137c478bd9Sstevel@tonic-gate       password = (char *) PASSWORD_BUF;
38147c478bd9Sstevel@tonic-gate       grub_memmove (password, arg, len);
38157c478bd9Sstevel@tonic-gate       grub_memset (password + len, 0, PASSWORD_BUFLEN - len);
38167c478bd9Sstevel@tonic-gate       password_type = type;
38177c478bd9Sstevel@tonic-gate     }
38187c478bd9Sstevel@tonic-gate   return 0;
38197c478bd9Sstevel@tonic-gate }
38207c478bd9Sstevel@tonic-gate 
38217c478bd9Sstevel@tonic-gate static struct builtin builtin_password =
38227c478bd9Sstevel@tonic-gate {
38237c478bd9Sstevel@tonic-gate   "password",
38247c478bd9Sstevel@tonic-gate   password_func,
38257c478bd9Sstevel@tonic-gate   BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_NO_ECHO,
38267c478bd9Sstevel@tonic-gate   "password [--md5] PASSWD [FILE]",
38277c478bd9Sstevel@tonic-gate   "If used in the first section of a menu file, disable all"
38287c478bd9Sstevel@tonic-gate   " interactive editing control (menu entry editor and"
38297c478bd9Sstevel@tonic-gate   " command line). If the password PASSWD is entered, it loads the"
38307c478bd9Sstevel@tonic-gate   " FILE as a new config file and restarts the GRUB Stage 2. If you"
38317c478bd9Sstevel@tonic-gate   " omit the argument FILE, then GRUB just unlocks privileged"
38327c478bd9Sstevel@tonic-gate   " instructions.  You can also use it in the script section, in"
38337c478bd9Sstevel@tonic-gate   " which case it will ask for the password, before continueing."
38347c478bd9Sstevel@tonic-gate   " The option --md5 tells GRUB that PASSWD is encrypted with"
38357c478bd9Sstevel@tonic-gate   " md5crypt."
38367c478bd9Sstevel@tonic-gate };
38377c478bd9Sstevel@tonic-gate 
38387c478bd9Sstevel@tonic-gate 
38397c478bd9Sstevel@tonic-gate /* pause */
38407c478bd9Sstevel@tonic-gate static int
38417c478bd9Sstevel@tonic-gate pause_func (char *arg, int flags)
38427c478bd9Sstevel@tonic-gate {
38437c478bd9Sstevel@tonic-gate   printf("%s\n", arg);
38447c478bd9Sstevel@tonic-gate 
38457c478bd9Sstevel@tonic-gate   /* If ESC is returned, then abort this entry.  */
38467c478bd9Sstevel@tonic-gate   if (ASCII_CHAR (getkey ()) == 27)
38477c478bd9Sstevel@tonic-gate     return 1;
38487c478bd9Sstevel@tonic-gate 
38497c478bd9Sstevel@tonic-gate   return 0;
38507c478bd9Sstevel@tonic-gate }
38517c478bd9Sstevel@tonic-gate 
38527c478bd9Sstevel@tonic-gate static struct builtin builtin_pause =
38537c478bd9Sstevel@tonic-gate {
38547c478bd9Sstevel@tonic-gate   "pause",
38557c478bd9Sstevel@tonic-gate   pause_func,
38567c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_NO_ECHO,
38577c478bd9Sstevel@tonic-gate   "pause [MESSAGE ...]",
38587c478bd9Sstevel@tonic-gate   "Print MESSAGE, then wait until a key is pressed."
38597c478bd9Sstevel@tonic-gate };
38607c478bd9Sstevel@tonic-gate 
38617c478bd9Sstevel@tonic-gate 
38627c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
38637c478bd9Sstevel@tonic-gate /* quit */
38647c478bd9Sstevel@tonic-gate static int
38657c478bd9Sstevel@tonic-gate quit_func (char *arg, int flags)
38667c478bd9Sstevel@tonic-gate {
38677c478bd9Sstevel@tonic-gate   stop ();
38687c478bd9Sstevel@tonic-gate 
38697c478bd9Sstevel@tonic-gate   /* Never reach here.  */
38707c478bd9Sstevel@tonic-gate   return 0;
38717c478bd9Sstevel@tonic-gate }
38727c478bd9Sstevel@tonic-gate 
38737c478bd9Sstevel@tonic-gate static struct builtin builtin_quit =
38747c478bd9Sstevel@tonic-gate {
38757c478bd9Sstevel@tonic-gate   "quit",
38767c478bd9Sstevel@tonic-gate   quit_func,
38777c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
38787c478bd9Sstevel@tonic-gate   "quit",
38797c478bd9Sstevel@tonic-gate   "Exit from the GRUB shell."
38807c478bd9Sstevel@tonic-gate };
38817c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
38827c478bd9Sstevel@tonic-gate 
38837c478bd9Sstevel@tonic-gate 
38847c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
38857c478bd9Sstevel@tonic-gate /* rarp */
38867c478bd9Sstevel@tonic-gate static int
38877c478bd9Sstevel@tonic-gate rarp_func (char *arg, int flags)
38887c478bd9Sstevel@tonic-gate {
38897c478bd9Sstevel@tonic-gate   if (! rarp ())
38907c478bd9Sstevel@tonic-gate     {
38917c478bd9Sstevel@tonic-gate       if (errnum == ERR_NONE)
38927c478bd9Sstevel@tonic-gate 	errnum = ERR_DEV_VALUES;
38937c478bd9Sstevel@tonic-gate 
38947c478bd9Sstevel@tonic-gate       return 1;
38957c478bd9Sstevel@tonic-gate     }
38967c478bd9Sstevel@tonic-gate 
38977c478bd9Sstevel@tonic-gate   /* Notify the configuration.  */
38987c478bd9Sstevel@tonic-gate   print_network_configuration ();
38997c478bd9Sstevel@tonic-gate   return 0;
39007c478bd9Sstevel@tonic-gate }
39017c478bd9Sstevel@tonic-gate 
39027c478bd9Sstevel@tonic-gate static struct builtin builtin_rarp =
39037c478bd9Sstevel@tonic-gate {
39047c478bd9Sstevel@tonic-gate   "rarp",
39057c478bd9Sstevel@tonic-gate   rarp_func,
39067c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
39077c478bd9Sstevel@tonic-gate   "rarp",
39087c478bd9Sstevel@tonic-gate   "Initialize a network device via RARP."
39097c478bd9Sstevel@tonic-gate };
39107c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
39117c478bd9Sstevel@tonic-gate 
39127c478bd9Sstevel@tonic-gate 
39137c478bd9Sstevel@tonic-gate static int
39147c478bd9Sstevel@tonic-gate read_func (char *arg, int flags)
39157c478bd9Sstevel@tonic-gate {
39167c478bd9Sstevel@tonic-gate   int addr;
39177c478bd9Sstevel@tonic-gate 
39187c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &addr))
39197c478bd9Sstevel@tonic-gate     return 1;
39207c478bd9Sstevel@tonic-gate 
39217c478bd9Sstevel@tonic-gate   grub_printf ("Address 0x%x: Value 0x%x\n",
39227c478bd9Sstevel@tonic-gate 	       addr, *((unsigned *) RAW_ADDR (addr)));
39237c478bd9Sstevel@tonic-gate   return 0;
39247c478bd9Sstevel@tonic-gate }
39257c478bd9Sstevel@tonic-gate 
39267c478bd9Sstevel@tonic-gate static struct builtin builtin_read =
39277c478bd9Sstevel@tonic-gate {
39287c478bd9Sstevel@tonic-gate   "read",
39297c478bd9Sstevel@tonic-gate   read_func,
39307c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
39317c478bd9Sstevel@tonic-gate   "read ADDR",
39327c478bd9Sstevel@tonic-gate   "Read a 32-bit value from memory at address ADDR and"
39337c478bd9Sstevel@tonic-gate   " display it in hex format."
39347c478bd9Sstevel@tonic-gate };
39357c478bd9Sstevel@tonic-gate 
39367c478bd9Sstevel@tonic-gate 
39377c478bd9Sstevel@tonic-gate /* reboot */
39387c478bd9Sstevel@tonic-gate static int
39397c478bd9Sstevel@tonic-gate reboot_func (char *arg, int flags)
39407c478bd9Sstevel@tonic-gate {
39417c478bd9Sstevel@tonic-gate   grub_reboot ();
39427c478bd9Sstevel@tonic-gate 
39437c478bd9Sstevel@tonic-gate   /* Never reach here.  */
39447c478bd9Sstevel@tonic-gate   return 1;
39457c478bd9Sstevel@tonic-gate }
39467c478bd9Sstevel@tonic-gate 
39477c478bd9Sstevel@tonic-gate static struct builtin builtin_reboot =
39487c478bd9Sstevel@tonic-gate {
39497c478bd9Sstevel@tonic-gate   "reboot",
39507c478bd9Sstevel@tonic-gate   reboot_func,
39517c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
39527c478bd9Sstevel@tonic-gate   "reboot",
39537c478bd9Sstevel@tonic-gate   "Reboot your system."
39547c478bd9Sstevel@tonic-gate };
39557c478bd9Sstevel@tonic-gate 
39567c478bd9Sstevel@tonic-gate 
39577c478bd9Sstevel@tonic-gate /* Print the root device information.  */
39587c478bd9Sstevel@tonic-gate static void
39597c478bd9Sstevel@tonic-gate print_root_device (void)
39607c478bd9Sstevel@tonic-gate {
39617c478bd9Sstevel@tonic-gate   if (saved_drive == NETWORK_DRIVE)
39627c478bd9Sstevel@tonic-gate     {
39637c478bd9Sstevel@tonic-gate       /* Network drive.  */
39647c478bd9Sstevel@tonic-gate       grub_printf (" (nd):");
39657c478bd9Sstevel@tonic-gate     }
39667c478bd9Sstevel@tonic-gate   else if (saved_drive & 0x80)
39677c478bd9Sstevel@tonic-gate     {
39687c478bd9Sstevel@tonic-gate       /* Hard disk drive.  */
39697c478bd9Sstevel@tonic-gate       grub_printf (" (hd%d", saved_drive - 0x80);
39707c478bd9Sstevel@tonic-gate 
39717c478bd9Sstevel@tonic-gate       if ((saved_partition & 0xFF0000) != 0xFF0000)
39727c478bd9Sstevel@tonic-gate 	grub_printf (",%d", saved_partition >> 16);
39737c478bd9Sstevel@tonic-gate 
39747c478bd9Sstevel@tonic-gate       if ((saved_partition & 0x00FF00) != 0x00FF00)
39757c478bd9Sstevel@tonic-gate 	grub_printf (",%c", ((saved_partition >> 8) & 0xFF) + 'a');
39767c478bd9Sstevel@tonic-gate 
39777c478bd9Sstevel@tonic-gate       grub_printf ("):");
39787c478bd9Sstevel@tonic-gate     }
39797c478bd9Sstevel@tonic-gate   else
39807c478bd9Sstevel@tonic-gate     {
39817c478bd9Sstevel@tonic-gate       /* Floppy disk drive.  */
39827c478bd9Sstevel@tonic-gate       grub_printf (" (fd%d):", saved_drive);
39837c478bd9Sstevel@tonic-gate     }
39847c478bd9Sstevel@tonic-gate 
39857c478bd9Sstevel@tonic-gate   /* Print the filesystem information.  */
39867c478bd9Sstevel@tonic-gate   current_partition = saved_partition;
39877c478bd9Sstevel@tonic-gate   current_drive = saved_drive;
39887c478bd9Sstevel@tonic-gate   print_fsys_type ();
39897c478bd9Sstevel@tonic-gate }
39907c478bd9Sstevel@tonic-gate 
39917c478bd9Sstevel@tonic-gate static int
39927c478bd9Sstevel@tonic-gate real_root_func (char *arg, int attempt_mount)
39937c478bd9Sstevel@tonic-gate {
39947c478bd9Sstevel@tonic-gate   int hdbias = 0;
39957c478bd9Sstevel@tonic-gate   char *biasptr;
39967c478bd9Sstevel@tonic-gate   char *next;
39977c478bd9Sstevel@tonic-gate 
39987c478bd9Sstevel@tonic-gate   /* If ARG is empty, just print the current root device.  */
39997c478bd9Sstevel@tonic-gate   if (! *arg)
40007c478bd9Sstevel@tonic-gate     {
40017c478bd9Sstevel@tonic-gate       print_root_device ();
40027c478bd9Sstevel@tonic-gate       return 0;
40037c478bd9Sstevel@tonic-gate     }
40047c478bd9Sstevel@tonic-gate 
40057c478bd9Sstevel@tonic-gate   /* Call set_device to get the drive and the partition in ARG.  */
40067c478bd9Sstevel@tonic-gate   next = set_device (arg);
40077c478bd9Sstevel@tonic-gate   if (! next)
40087c478bd9Sstevel@tonic-gate     return 1;
40097c478bd9Sstevel@tonic-gate 
40107c478bd9Sstevel@tonic-gate   /* Ignore ERR_FSYS_MOUNT.  */
40117c478bd9Sstevel@tonic-gate   if (attempt_mount)
40127c478bd9Sstevel@tonic-gate     {
40137c478bd9Sstevel@tonic-gate       if (! open_device () && errnum != ERR_FSYS_MOUNT)
40147c478bd9Sstevel@tonic-gate 	return 1;
40157c478bd9Sstevel@tonic-gate     }
40167c478bd9Sstevel@tonic-gate   else
40177c478bd9Sstevel@tonic-gate     {
40187c478bd9Sstevel@tonic-gate       /* This is necessary, because the location of a partition table
40197c478bd9Sstevel@tonic-gate 	 must be set appropriately.  */
40207c478bd9Sstevel@tonic-gate       if (open_partition ())
40217c478bd9Sstevel@tonic-gate 	{
40227c478bd9Sstevel@tonic-gate 	  set_bootdev (0);
40237c478bd9Sstevel@tonic-gate 	  if (errnum)
40247c478bd9Sstevel@tonic-gate 	    return 1;
40257c478bd9Sstevel@tonic-gate 	}
40267c478bd9Sstevel@tonic-gate     }
40277c478bd9Sstevel@tonic-gate 
40287c478bd9Sstevel@tonic-gate   /* Clear ERRNUM.  */
40297c478bd9Sstevel@tonic-gate   errnum = 0;
40307c478bd9Sstevel@tonic-gate   saved_partition = current_partition;
40317c478bd9Sstevel@tonic-gate   saved_drive = current_drive;
40327c478bd9Sstevel@tonic-gate 
40337c478bd9Sstevel@tonic-gate   if (attempt_mount)
40347c478bd9Sstevel@tonic-gate     {
40357c478bd9Sstevel@tonic-gate       /* BSD and chainloading evil hacks !!  */
40367c478bd9Sstevel@tonic-gate       biasptr = skip_to (0, next);
40377c478bd9Sstevel@tonic-gate       safe_parse_maxint (&biasptr, &hdbias);
40387c478bd9Sstevel@tonic-gate       errnum = 0;
40397c478bd9Sstevel@tonic-gate       bootdev = set_bootdev (hdbias);
40407c478bd9Sstevel@tonic-gate       if (errnum)
40417c478bd9Sstevel@tonic-gate 	return 1;
40427c478bd9Sstevel@tonic-gate 
40437c478bd9Sstevel@tonic-gate       /* Print the type of the filesystem.  */
40447c478bd9Sstevel@tonic-gate       print_fsys_type ();
40457c478bd9Sstevel@tonic-gate     }
40467c478bd9Sstevel@tonic-gate 
40477c478bd9Sstevel@tonic-gate   return 0;
40487c478bd9Sstevel@tonic-gate }
40497c478bd9Sstevel@tonic-gate 
40507c478bd9Sstevel@tonic-gate static int
40517c478bd9Sstevel@tonic-gate root_func (char *arg, int flags)
40527c478bd9Sstevel@tonic-gate {
4053b1b8ab34Slling   is_zfs_mount = 0;
40547c478bd9Sstevel@tonic-gate   return real_root_func (arg, 1);
40557c478bd9Sstevel@tonic-gate }
40567c478bd9Sstevel@tonic-gate 
40577c478bd9Sstevel@tonic-gate static struct builtin builtin_root =
40587c478bd9Sstevel@tonic-gate {
40597c478bd9Sstevel@tonic-gate   "root",
40607c478bd9Sstevel@tonic-gate   root_func,
40617c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
40627c478bd9Sstevel@tonic-gate   "root [DEVICE [HDBIAS]]",
40637c478bd9Sstevel@tonic-gate   "Set the current \"root device\" to the device DEVICE, then"
40647c478bd9Sstevel@tonic-gate   " attempt to mount it to get the partition size (for passing the"
40657c478bd9Sstevel@tonic-gate   " partition descriptor in `ES:ESI', used by some chain-loaded"
40667c478bd9Sstevel@tonic-gate   " bootloaders), the BSD drive-type (for booting BSD kernels using"
40677c478bd9Sstevel@tonic-gate   " their native boot format), and correctly determine "
40687c478bd9Sstevel@tonic-gate   " the PC partition where a BSD sub-partition is located. The"
40697c478bd9Sstevel@tonic-gate   " optional HDBIAS parameter is a number to tell a BSD kernel"
40707c478bd9Sstevel@tonic-gate   " how many BIOS drive numbers are on controllers before the current"
40717c478bd9Sstevel@tonic-gate   " one. For example, if there is an IDE disk and a SCSI disk, and your"
40727c478bd9Sstevel@tonic-gate   " FreeBSD root partition is on the SCSI disk, then use a `1' for HDBIAS."
40737c478bd9Sstevel@tonic-gate };
40747c478bd9Sstevel@tonic-gate 
4075eb2bd662Svikram 
4076eb2bd662Svikram /* findroot */
4077eb2bd662Svikram static int
4078eb2bd662Svikram findroot_func (char *arg, int flags)
4079eb2bd662Svikram {
4080eb2bd662Svikram   int ret;
4081eb2bd662Svikram   char root[32];
4082eb2bd662Svikram 
4083eb2bd662Svikram   if (grub_strlen(arg) >= BOOTSIGN_ARGLEN) {
4084eb2bd662Svikram   	errnum = ERR_BAD_ARGUMENT;
4085eb2bd662Svikram 	return 1;
4086eb2bd662Svikram   }
4087eb2bd662Svikram 
4088eb2bd662Svikram   if (arg[0] == '\0') {
4089eb2bd662Svikram   	errnum = ERR_BAD_ARGUMENT;
4090eb2bd662Svikram 	return 1;
4091eb2bd662Svikram   }
4092eb2bd662Svikram 
4093eb2bd662Svikram   if (grub_strchr(arg, '/')) {
4094eb2bd662Svikram   	errnum = ERR_BAD_ARGUMENT;
4095eb2bd662Svikram 	return 1;
4096eb2bd662Svikram   }
4097eb2bd662Svikram 
4098051aabe6Staylor   find_best_root = 1;
4099051aabe6Staylor   best_drive = 0;
4100051aabe6Staylor   best_part = 0;
4101eb2bd662Svikram   ret = find_common(arg, root, 1, flags);
4102eb2bd662Svikram   if (ret != 0)
4103eb2bd662Svikram 	return (ret);
4104051aabe6Staylor   find_best_root = 0;
4105eb2bd662Svikram 
4106eb2bd662Svikram   return real_root_func (root, 1);
4107eb2bd662Svikram }
4108eb2bd662Svikram 
4109eb2bd662Svikram static struct builtin builtin_findroot =
4110eb2bd662Svikram {
4111eb2bd662Svikram   "findroot",
4112eb2bd662Svikram   findroot_func,
4113eb2bd662Svikram   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
4114963390b4Svikram   "findroot  <SIGNATURE | (SIGNATURE,partition[,slice])>",
4115963390b4Svikram   "Searches across all partitions for the file name SIGNATURE."
4116963390b4Svikram   " GRUB looks only in the directory /boot/grub/bootsign for the"
4117963390b4Svikram   " filename and it stops as soon as it finds the first instance of"
4118963390b4Svikram   " the file - so to be useful the name of the signature file must be"
4119963390b4Svikram   " unique across all partitions. Once the signature file is found,"
4120963390b4Svikram   " GRUB invokes the \"root\" command on that partition."
4121eb2bd662Svikram   " An optional partition and slice may be specified to optimize the search."
4122eb2bd662Svikram };
4123eb2bd662Svikram 
4124b1b8ab34Slling 
4125b1b8ab34Slling /*
4126b1b8ab34Slling  * COMMAND to override the default root filesystem for ZFS
4127b1b8ab34Slling  *	bootfs pool/fs
4128b1b8ab34Slling  */
4129b1b8ab34Slling static int
4130b1b8ab34Slling bootfs_func (char *arg, int flags)
4131b1b8ab34Slling {
4132b1b8ab34Slling 	int hdbias = 0;
4133b1b8ab34Slling 	char *biasptr;
4134b1b8ab34Slling 	char *next;
4135b1b8ab34Slling 
4136b1b8ab34Slling 	if (! *arg) {
4137b1b8ab34Slling 	    if (current_bootfs[0] != '\0')
4138b1b8ab34Slling 		grub_printf ("The zfs boot filesystem is set to '%s'.\n",
4139b1b8ab34Slling 				current_bootfs);
4140b1b8ab34Slling 	    else if (current_rootpool[0] != 0 && current_bootfs_obj != 0)
4141b1b8ab34Slling 		grub_printf("The zfs boot filesystem is <default: %s/%u>.",
4142b1b8ab34Slling 				current_rootpool, current_bootfs_obj);
4143b1b8ab34Slling 	    else
414411a41203Slling 		grub_printf ("The zfs boot filesystem will be derived from "
414511a41203Slling 			"the default bootfs pool property.\n");
4146b1b8ab34Slling 
4147b1b8ab34Slling 	    return (1);
4148b1b8ab34Slling 	}
4149b1b8ab34Slling 
4150b1b8ab34Slling 	/* Verify the zfs filesystem name */
4151b1b8ab34Slling 	if (arg[0] == '/' || arg[0] == '\0') {
4152b1b8ab34Slling 		errnum = ERR_BAD_ARGUMENT;
4153b1b8ab34Slling 		return 0;
4154b1b8ab34Slling 	}
4155b35c6776Staylor 	if (current_rootpool[0] != 0 && grub_strncmp(arg,
4156b35c6776Staylor 	    current_rootpool, strlen(current_rootpool))) {
4157b35c6776Staylor 		errnum = ERR_BAD_ARGUMENT;
4158b35c6776Staylor 		return 0;
4159b35c6776Staylor 	}
4160b1b8ab34Slling 
4161b1b8ab34Slling 	if (set_bootfs(arg) == 0) {
4162b1b8ab34Slling 		errnum = ERR_BAD_ARGUMENT;
4163b1b8ab34Slling 		return 0;
4164b1b8ab34Slling 	}
4165b1b8ab34Slling 
4166b1b8ab34Slling 	return (1);
4167b1b8ab34Slling }
4168b1b8ab34Slling 
4169b1b8ab34Slling static struct builtin builtin_bootfs =
4170b1b8ab34Slling {
4171b1b8ab34Slling   "bootfs",
4172b1b8ab34Slling   bootfs_func,
4173b1b8ab34Slling   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
4174b1b8ab34Slling   "bootfs [ZFSBOOTFS]",
4175b1b8ab34Slling   "Set the current zfs boot filesystem to ZFSBOOTFS (rootpool/rootfs)."
4176b1b8ab34Slling };
4177b1b8ab34Slling 
41787c478bd9Sstevel@tonic-gate 
41797c478bd9Sstevel@tonic-gate /* rootnoverify */
41807c478bd9Sstevel@tonic-gate static int
41817c478bd9Sstevel@tonic-gate rootnoverify_func (char *arg, int flags)
41827c478bd9Sstevel@tonic-gate {
41837c478bd9Sstevel@tonic-gate   return real_root_func (arg, 0);
41847c478bd9Sstevel@tonic-gate }
41857c478bd9Sstevel@tonic-gate 
41867c478bd9Sstevel@tonic-gate static struct builtin builtin_rootnoverify =
41877c478bd9Sstevel@tonic-gate {
41887c478bd9Sstevel@tonic-gate   "rootnoverify",
41897c478bd9Sstevel@tonic-gate   rootnoverify_func,
41907c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
41917c478bd9Sstevel@tonic-gate   "rootnoverify [DEVICE [HDBIAS]]",
41927c478bd9Sstevel@tonic-gate   "Similar to `root', but don't attempt to mount the partition. This"
41937c478bd9Sstevel@tonic-gate   " is useful for when an OS is outside of the area of the disk that"
41947c478bd9Sstevel@tonic-gate   " GRUB can read, but setting the correct root device is still"
41957c478bd9Sstevel@tonic-gate   " desired. Note that the items mentioned in `root' which"
41967c478bd9Sstevel@tonic-gate   " derived from attempting the mount will NOT work correctly."
41977c478bd9Sstevel@tonic-gate };
41987c478bd9Sstevel@tonic-gate 
41997c478bd9Sstevel@tonic-gate 
42007c478bd9Sstevel@tonic-gate /* savedefault */
42017c478bd9Sstevel@tonic-gate static int
42027c478bd9Sstevel@tonic-gate savedefault_func (char *arg, int flags)
42037c478bd9Sstevel@tonic-gate {
42047c478bd9Sstevel@tonic-gate #if !defined(SUPPORT_DISKLESS) && !defined(GRUB_UTIL)
42057c478bd9Sstevel@tonic-gate   unsigned long tmp_drive = saved_drive;
42067c478bd9Sstevel@tonic-gate   unsigned long tmp_partition = saved_partition;
42077c478bd9Sstevel@tonic-gate   char *default_file = (char *) DEFAULT_FILE_BUF;
42087c478bd9Sstevel@tonic-gate   char buf[10];
42097c478bd9Sstevel@tonic-gate   char sect[SECTOR_SIZE];
42107c478bd9Sstevel@tonic-gate   int entryno;
42117c478bd9Sstevel@tonic-gate   int sector_count = 0;
4212342440ecSPrasad Singamsetty   unsigned int saved_sectors[2];
42137c478bd9Sstevel@tonic-gate   int saved_offsets[2];
42147c478bd9Sstevel@tonic-gate   int saved_lengths[2];
42157c478bd9Sstevel@tonic-gate 
4216b1b8ab34Slling   /* not supported for zfs root */
4217b1b8ab34Slling   if (is_zfs_mount == 1) {
4218b1b8ab34Slling 	return (0); /* no-op */
4219b1b8ab34Slling   }
4220b1b8ab34Slling 
42217c478bd9Sstevel@tonic-gate   /* Save sector information about at most two sectors.  */
42221b8adde7SWilliam Kucharski   auto void disk_read_savesect_func (unsigned int sector, int offset,
42231b8adde7SWilliam Kucharski       int length);
42241b8adde7SWilliam Kucharski   void disk_read_savesect_func (unsigned int sector, int offset, int length)
42257c478bd9Sstevel@tonic-gate     {
42267c478bd9Sstevel@tonic-gate       if (sector_count < 2)
42277c478bd9Sstevel@tonic-gate 	{
42287c478bd9Sstevel@tonic-gate 	  saved_sectors[sector_count] = sector;
42297c478bd9Sstevel@tonic-gate 	  saved_offsets[sector_count] = offset;
42307c478bd9Sstevel@tonic-gate 	  saved_lengths[sector_count] = length;
42317c478bd9Sstevel@tonic-gate 	}
42327c478bd9Sstevel@tonic-gate       sector_count++;
42337c478bd9Sstevel@tonic-gate     }
42347c478bd9Sstevel@tonic-gate 
42357c478bd9Sstevel@tonic-gate   /* This command is only useful when you boot an entry from the menu
42367c478bd9Sstevel@tonic-gate      interface.  */
42377c478bd9Sstevel@tonic-gate   if (! (flags & BUILTIN_SCRIPT))
42387c478bd9Sstevel@tonic-gate     {
42397c478bd9Sstevel@tonic-gate       errnum = ERR_UNRECOGNIZED;
42407c478bd9Sstevel@tonic-gate       return 1;
42417c478bd9Sstevel@tonic-gate     }
42427c478bd9Sstevel@tonic-gate 
42437c478bd9Sstevel@tonic-gate   /* Determine a saved entry number.  */
42447c478bd9Sstevel@tonic-gate   if (*arg)
42457c478bd9Sstevel@tonic-gate     {
42467c478bd9Sstevel@tonic-gate       if (grub_memcmp (arg, "fallback", sizeof ("fallback") - 1) == 0)
42477c478bd9Sstevel@tonic-gate 	{
42487c478bd9Sstevel@tonic-gate 	  int i;
42497c478bd9Sstevel@tonic-gate 	  int index = 0;
42507c478bd9Sstevel@tonic-gate 
42517c478bd9Sstevel@tonic-gate 	  for (i = 0; i < MAX_FALLBACK_ENTRIES; i++)
42527c478bd9Sstevel@tonic-gate 	    {
42537c478bd9Sstevel@tonic-gate 	      if (fallback_entries[i] < 0)
42547c478bd9Sstevel@tonic-gate 		break;
42557c478bd9Sstevel@tonic-gate 	      if (fallback_entries[i] == current_entryno)
42567c478bd9Sstevel@tonic-gate 		{
42577c478bd9Sstevel@tonic-gate 		  index = i + 1;
42587c478bd9Sstevel@tonic-gate 		  break;
42597c478bd9Sstevel@tonic-gate 		}
42607c478bd9Sstevel@tonic-gate 	    }
42617c478bd9Sstevel@tonic-gate 
42627c478bd9Sstevel@tonic-gate 	  if (index >= MAX_FALLBACK_ENTRIES || fallback_entries[index] < 0)
42637c478bd9Sstevel@tonic-gate 	    {
42647c478bd9Sstevel@tonic-gate 	      /* This is the last.  */
42657c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_ARGUMENT;
42667c478bd9Sstevel@tonic-gate 	      return 1;
42677c478bd9Sstevel@tonic-gate 	    }
42687c478bd9Sstevel@tonic-gate 
42697c478bd9Sstevel@tonic-gate 	  entryno = fallback_entries[index];
42707c478bd9Sstevel@tonic-gate 	}
42717c478bd9Sstevel@tonic-gate       else if (! safe_parse_maxint (&arg, &entryno))
42727c478bd9Sstevel@tonic-gate 	return 1;
42737c478bd9Sstevel@tonic-gate     }
42747c478bd9Sstevel@tonic-gate   else
42757c478bd9Sstevel@tonic-gate     entryno = current_entryno;
42767c478bd9Sstevel@tonic-gate 
42777c478bd9Sstevel@tonic-gate   /* Open the default file.  */
42787c478bd9Sstevel@tonic-gate   saved_drive = boot_drive;
42797c478bd9Sstevel@tonic-gate   saved_partition = install_partition;
42807c478bd9Sstevel@tonic-gate   if (grub_open (default_file))
42817c478bd9Sstevel@tonic-gate     {
42827c478bd9Sstevel@tonic-gate       int len;
42837c478bd9Sstevel@tonic-gate 
42847c478bd9Sstevel@tonic-gate       disk_read_hook = disk_read_savesect_func;
42857c478bd9Sstevel@tonic-gate       len = grub_read (buf, sizeof (buf));
42867c478bd9Sstevel@tonic-gate       disk_read_hook = 0;
42877c478bd9Sstevel@tonic-gate       grub_close ();
42887c478bd9Sstevel@tonic-gate 
42897c478bd9Sstevel@tonic-gate       if (len != sizeof (buf))
42907c478bd9Sstevel@tonic-gate 	{
42917c478bd9Sstevel@tonic-gate 	  /* This is too small. Do not modify the file manually, please!  */
42927c478bd9Sstevel@tonic-gate 	  errnum = ERR_READ;
42937c478bd9Sstevel@tonic-gate 	  goto fail;
42947c478bd9Sstevel@tonic-gate 	}
42957c478bd9Sstevel@tonic-gate 
42967c478bd9Sstevel@tonic-gate       if (sector_count > 2)
42977c478bd9Sstevel@tonic-gate 	{
42987c478bd9Sstevel@tonic-gate 	  /* Is this possible?! Too fragmented!  */
42997c478bd9Sstevel@tonic-gate 	  errnum = ERR_FSYS_CORRUPT;
43007c478bd9Sstevel@tonic-gate 	  goto fail;
43017c478bd9Sstevel@tonic-gate 	}
43027c478bd9Sstevel@tonic-gate 
43037c478bd9Sstevel@tonic-gate       /* Set up a string to be written.  */
43047c478bd9Sstevel@tonic-gate       grub_memset (buf, '\n', sizeof (buf));
43057c478bd9Sstevel@tonic-gate       grub_sprintf (buf, "%d", entryno);
43067c478bd9Sstevel@tonic-gate 
43077c478bd9Sstevel@tonic-gate       if (saved_lengths[0] < sizeof (buf))
43087c478bd9Sstevel@tonic-gate 	{
43097c478bd9Sstevel@tonic-gate 	  /* The file is anchored to another file and the first few bytes
43107c478bd9Sstevel@tonic-gate 	     are spanned in two sectors. Uggh...  */
43117c478bd9Sstevel@tonic-gate 	  if (! rawread (current_drive, saved_sectors[0], 0, SECTOR_SIZE,
43127c478bd9Sstevel@tonic-gate 			 sect))
43137c478bd9Sstevel@tonic-gate 	    goto fail;
43147c478bd9Sstevel@tonic-gate 	  grub_memmove (sect + saved_offsets[0], buf, saved_lengths[0]);
43157c478bd9Sstevel@tonic-gate 	  if (! rawwrite (current_drive, saved_sectors[0], sect))
43167c478bd9Sstevel@tonic-gate 	    goto fail;
43177c478bd9Sstevel@tonic-gate 
43187c478bd9Sstevel@tonic-gate 	  if (! rawread (current_drive, saved_sectors[1], 0, SECTOR_SIZE,
43197c478bd9Sstevel@tonic-gate 			 sect))
43207c478bd9Sstevel@tonic-gate 	    goto fail;
43217c478bd9Sstevel@tonic-gate 	  grub_memmove (sect + saved_offsets[1],
43227c478bd9Sstevel@tonic-gate 			buf + saved_lengths[0],
43237c478bd9Sstevel@tonic-gate 			sizeof (buf) - saved_lengths[0]);
43247c478bd9Sstevel@tonic-gate 	  if (! rawwrite (current_drive, saved_sectors[1], sect))
43257c478bd9Sstevel@tonic-gate 	    goto fail;
43267c478bd9Sstevel@tonic-gate 	}
43277c478bd9Sstevel@tonic-gate       else
43287c478bd9Sstevel@tonic-gate 	{
43297c478bd9Sstevel@tonic-gate 	  /* This is a simple case. It fits into a single sector.  */
43307c478bd9Sstevel@tonic-gate 	  if (! rawread (current_drive, saved_sectors[0], 0, SECTOR_SIZE,
43317c478bd9Sstevel@tonic-gate 			 sect))
43327c478bd9Sstevel@tonic-gate 	    goto fail;
43337c478bd9Sstevel@tonic-gate 	  grub_memmove (sect + saved_offsets[0], buf, sizeof (buf));
43347c478bd9Sstevel@tonic-gate 	  if (! rawwrite (current_drive, saved_sectors[0], sect))
43357c478bd9Sstevel@tonic-gate 	    goto fail;
43367c478bd9Sstevel@tonic-gate 	}
43377c478bd9Sstevel@tonic-gate 
43387c478bd9Sstevel@tonic-gate       /* Clear the cache.  */
4339342440ecSPrasad Singamsetty       buf_track = BUF_CACHE_INVALID;
43407c478bd9Sstevel@tonic-gate     }
43417c478bd9Sstevel@tonic-gate 
43427c478bd9Sstevel@tonic-gate  fail:
43437c478bd9Sstevel@tonic-gate   saved_drive = tmp_drive;
43447c478bd9Sstevel@tonic-gate   saved_partition = tmp_partition;
43457c478bd9Sstevel@tonic-gate   return errnum;
43467c478bd9Sstevel@tonic-gate #else /* ! SUPPORT_DISKLESS && ! GRUB_UTIL */
43477c478bd9Sstevel@tonic-gate   errnum = ERR_UNRECOGNIZED;
43487c478bd9Sstevel@tonic-gate   return 1;
43497c478bd9Sstevel@tonic-gate #endif /* ! SUPPORT_DISKLESS && ! GRUB_UTIL */
43507c478bd9Sstevel@tonic-gate }
43517c478bd9Sstevel@tonic-gate 
43527c478bd9Sstevel@tonic-gate static struct builtin builtin_savedefault =
43537c478bd9Sstevel@tonic-gate {
43547c478bd9Sstevel@tonic-gate   "savedefault",
43557c478bd9Sstevel@tonic-gate   savedefault_func,
43567c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
43577c478bd9Sstevel@tonic-gate   "savedefault [NUM | `fallback']",
43587c478bd9Sstevel@tonic-gate   "Save the current entry as the default boot entry if no argument is"
43597c478bd9Sstevel@tonic-gate   " specified. If a number is specified, this number is saved. If"
43607c478bd9Sstevel@tonic-gate   " `fallback' is used, next fallback entry is saved."
43617c478bd9Sstevel@tonic-gate };
43627c478bd9Sstevel@tonic-gate 
43637c478bd9Sstevel@tonic-gate 
43647c478bd9Sstevel@tonic-gate #ifdef SUPPORT_SERIAL
43657c478bd9Sstevel@tonic-gate /* serial */
43667c478bd9Sstevel@tonic-gate static int
43677c478bd9Sstevel@tonic-gate serial_func (char *arg, int flags)
43687c478bd9Sstevel@tonic-gate {
43697c478bd9Sstevel@tonic-gate   unsigned short port = serial_hw_get_port (0);
43707c478bd9Sstevel@tonic-gate   unsigned int speed = 9600;
43717c478bd9Sstevel@tonic-gate   int word_len = UART_8BITS_WORD;
43727c478bd9Sstevel@tonic-gate   int parity = UART_NO_PARITY;
43737c478bd9Sstevel@tonic-gate   int stop_bit_len = UART_1_STOP_BIT;
43747c478bd9Sstevel@tonic-gate 
43757c478bd9Sstevel@tonic-gate   /* Process GNU-style long options.
43767c478bd9Sstevel@tonic-gate      FIXME: We should implement a getopt-like function, to avoid
43777c478bd9Sstevel@tonic-gate      duplications.  */
43787c478bd9Sstevel@tonic-gate   while (1)
43797c478bd9Sstevel@tonic-gate     {
43807c478bd9Sstevel@tonic-gate       if (grub_memcmp (arg, "--unit=", sizeof ("--unit=") - 1) == 0)
43817c478bd9Sstevel@tonic-gate 	{
43827c478bd9Sstevel@tonic-gate 	  char *p = arg + sizeof ("--unit=") - 1;
43837c478bd9Sstevel@tonic-gate 	  int unit;
43847c478bd9Sstevel@tonic-gate 
43857c478bd9Sstevel@tonic-gate 	  if (! safe_parse_maxint (&p, &unit))
43867c478bd9Sstevel@tonic-gate 	    return 1;
43877c478bd9Sstevel@tonic-gate 
43887c478bd9Sstevel@tonic-gate 	  if (unit < 0 || unit > 3)
43897c478bd9Sstevel@tonic-gate 	    {
43907c478bd9Sstevel@tonic-gate 	      errnum = ERR_DEV_VALUES;
43917c478bd9Sstevel@tonic-gate 	      return 1;
43927c478bd9Sstevel@tonic-gate 	    }
43937c478bd9Sstevel@tonic-gate 
43947c478bd9Sstevel@tonic-gate 	  port = serial_hw_get_port (unit);
43957c478bd9Sstevel@tonic-gate 	}
43967c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--speed=", sizeof ("--speed=") - 1) == 0)
43977c478bd9Sstevel@tonic-gate 	{
43987c478bd9Sstevel@tonic-gate 	  char *p = arg + sizeof ("--speed=") - 1;
43997c478bd9Sstevel@tonic-gate 	  int num;
44007c478bd9Sstevel@tonic-gate 
44017c478bd9Sstevel@tonic-gate 	  if (! safe_parse_maxint (&p, &num))
44027c478bd9Sstevel@tonic-gate 	    return 1;
44037c478bd9Sstevel@tonic-gate 
44047c478bd9Sstevel@tonic-gate 	  speed = (unsigned int) num;
44057c478bd9Sstevel@tonic-gate 	}
44067c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--port=", sizeof ("--port=") - 1) == 0)
44077c478bd9Sstevel@tonic-gate 	{
44087c478bd9Sstevel@tonic-gate 	  char *p = arg + sizeof ("--port=") - 1;
44097c478bd9Sstevel@tonic-gate 	  int num;
44107c478bd9Sstevel@tonic-gate 
44117c478bd9Sstevel@tonic-gate 	  if (! safe_parse_maxint (&p, &num))
44127c478bd9Sstevel@tonic-gate 	    return 1;
44137c478bd9Sstevel@tonic-gate 
44147c478bd9Sstevel@tonic-gate 	  port = (unsigned short) num;
44157c478bd9Sstevel@tonic-gate 	}
44167c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--word=", sizeof ("--word=") - 1) == 0)
44177c478bd9Sstevel@tonic-gate 	{
44187c478bd9Sstevel@tonic-gate 	  char *p = arg + sizeof ("--word=") - 1;
44197c478bd9Sstevel@tonic-gate 	  int len;
44207c478bd9Sstevel@tonic-gate 
44217c478bd9Sstevel@tonic-gate 	  if (! safe_parse_maxint (&p, &len))
44227c478bd9Sstevel@tonic-gate 	    return 1;
44237c478bd9Sstevel@tonic-gate 
44247c478bd9Sstevel@tonic-gate 	  switch (len)
44257c478bd9Sstevel@tonic-gate 	    {
44267c478bd9Sstevel@tonic-gate 	    case 5: word_len = UART_5BITS_WORD; break;
44277c478bd9Sstevel@tonic-gate 	    case 6: word_len = UART_6BITS_WORD; break;
44287c478bd9Sstevel@tonic-gate 	    case 7: word_len = UART_7BITS_WORD; break;
44297c478bd9Sstevel@tonic-gate 	    case 8: word_len = UART_8BITS_WORD; break;
44307c478bd9Sstevel@tonic-gate 	    default:
44317c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_ARGUMENT;
44327c478bd9Sstevel@tonic-gate 	      return 1;
44337c478bd9Sstevel@tonic-gate 	    }
44347c478bd9Sstevel@tonic-gate 	}
44357c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--stop=", sizeof ("--stop=") - 1) == 0)
44367c478bd9Sstevel@tonic-gate 	{
44377c478bd9Sstevel@tonic-gate 	  char *p = arg + sizeof ("--stop=") - 1;
44387c478bd9Sstevel@tonic-gate 	  int len;
44397c478bd9Sstevel@tonic-gate 
44407c478bd9Sstevel@tonic-gate 	  if (! safe_parse_maxint (&p, &len))
44417c478bd9Sstevel@tonic-gate 	    return 1;
44427c478bd9Sstevel@tonic-gate 
44437c478bd9Sstevel@tonic-gate 	  switch (len)
44447c478bd9Sstevel@tonic-gate 	    {
44457c478bd9Sstevel@tonic-gate 	    case 1: stop_bit_len = UART_1_STOP_BIT; break;
44467c478bd9Sstevel@tonic-gate 	    case 2: stop_bit_len = UART_2_STOP_BITS; break;
44477c478bd9Sstevel@tonic-gate 	    default:
44487c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_ARGUMENT;
44497c478bd9Sstevel@tonic-gate 	      return 1;
44507c478bd9Sstevel@tonic-gate 	    }
44517c478bd9Sstevel@tonic-gate 	}
44527c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--parity=", sizeof ("--parity=") - 1) == 0)
44537c478bd9Sstevel@tonic-gate 	{
44547c478bd9Sstevel@tonic-gate 	  char *p = arg + sizeof ("--parity=") - 1;
44557c478bd9Sstevel@tonic-gate 
44567c478bd9Sstevel@tonic-gate 	  if (grub_memcmp (p, "no", sizeof ("no") - 1) == 0)
44577c478bd9Sstevel@tonic-gate 	    parity = UART_NO_PARITY;
44587c478bd9Sstevel@tonic-gate 	  else if (grub_memcmp (p, "odd", sizeof ("odd") - 1) == 0)
44597c478bd9Sstevel@tonic-gate 	    parity = UART_ODD_PARITY;
44607c478bd9Sstevel@tonic-gate 	  else if (grub_memcmp (p, "even", sizeof ("even") - 1) == 0)
44617c478bd9Sstevel@tonic-gate 	    parity = UART_EVEN_PARITY;
44627c478bd9Sstevel@tonic-gate 	  else
44637c478bd9Sstevel@tonic-gate 	    {
44647c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_ARGUMENT;
44657c478bd9Sstevel@tonic-gate 	      return 1;
44667c478bd9Sstevel@tonic-gate 	    }
44677c478bd9Sstevel@tonic-gate 	}
44687c478bd9Sstevel@tonic-gate # ifdef GRUB_UTIL
44697c478bd9Sstevel@tonic-gate       /* In the grub shell, don't use any port number but open a tty
44707c478bd9Sstevel@tonic-gate 	 device instead.  */
44717c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--device=", sizeof ("--device=") - 1) == 0)
44727c478bd9Sstevel@tonic-gate 	{
44737c478bd9Sstevel@tonic-gate 	  char *p = arg + sizeof ("--device=") - 1;
44747c478bd9Sstevel@tonic-gate 	  char dev[256];	/* XXX */
44757c478bd9Sstevel@tonic-gate 	  char *q = dev;
44767c478bd9Sstevel@tonic-gate 
44777c478bd9Sstevel@tonic-gate 	  while (*p && ! grub_isspace (*p))
44787c478bd9Sstevel@tonic-gate 	    *q++ = *p++;
44797c478bd9Sstevel@tonic-gate 
44807c478bd9Sstevel@tonic-gate 	  *q = 0;
44817c478bd9Sstevel@tonic-gate 	  serial_set_device (dev);
44827c478bd9Sstevel@tonic-gate 	}
44837c478bd9Sstevel@tonic-gate # endif /* GRUB_UTIL */
44847c478bd9Sstevel@tonic-gate       else
44857c478bd9Sstevel@tonic-gate 	break;
44867c478bd9Sstevel@tonic-gate 
44877c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
44887c478bd9Sstevel@tonic-gate     }
44897c478bd9Sstevel@tonic-gate 
44907c478bd9Sstevel@tonic-gate   /* Initialize the serial unit.  */
44917c478bd9Sstevel@tonic-gate   if (! serial_hw_init (port, speed, word_len, parity, stop_bit_len))
44927c478bd9Sstevel@tonic-gate     {
44937c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
44947c478bd9Sstevel@tonic-gate       return 1;
44957c478bd9Sstevel@tonic-gate     }
44967c478bd9Sstevel@tonic-gate 
44977c478bd9Sstevel@tonic-gate   return 0;
44987c478bd9Sstevel@tonic-gate }
44997c478bd9Sstevel@tonic-gate 
45007c478bd9Sstevel@tonic-gate static struct builtin builtin_serial =
45017c478bd9Sstevel@tonic-gate {
45027c478bd9Sstevel@tonic-gate   "serial",
45037c478bd9Sstevel@tonic-gate   serial_func,
45047c478bd9Sstevel@tonic-gate   BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
45057c478bd9Sstevel@tonic-gate   "serial [--unit=UNIT] [--port=PORT] [--speed=SPEED] [--word=WORD] [--parity=PARITY] [--stop=STOP] [--device=DEV]",
45067c478bd9Sstevel@tonic-gate   "Initialize a serial device. UNIT is a digit that specifies which serial"
45077c478bd9Sstevel@tonic-gate   " device is used (e.g. 0 == COM1). If you need to specify the port number,"
45087c478bd9Sstevel@tonic-gate   " set it by --port. SPEED is the DTE-DTE speed. WORD is the word length,"
45097c478bd9Sstevel@tonic-gate   " PARITY is the type of parity, which is one of `no', `odd' and `even'."
45107c478bd9Sstevel@tonic-gate   " STOP is the length of stop bit(s). The option --device can be used only"
45117c478bd9Sstevel@tonic-gate   " in the grub shell, which specifies the file name of a tty device. The"
45127c478bd9Sstevel@tonic-gate   " default values are COM1, 9600, 8N1."
45137c478bd9Sstevel@tonic-gate };
45147c478bd9Sstevel@tonic-gate #endif /* SUPPORT_SERIAL */
45157c478bd9Sstevel@tonic-gate 
45167c478bd9Sstevel@tonic-gate 
45177c478bd9Sstevel@tonic-gate /* setkey */
45187c478bd9Sstevel@tonic-gate struct keysym
45197c478bd9Sstevel@tonic-gate {
45207c478bd9Sstevel@tonic-gate   char *unshifted_name;			/* the name in unshifted state */
45217c478bd9Sstevel@tonic-gate   char *shifted_name;			/* the name in shifted state */
45227c478bd9Sstevel@tonic-gate   unsigned char unshifted_ascii;	/* the ascii code in unshifted state */
45237c478bd9Sstevel@tonic-gate   unsigned char shifted_ascii;		/* the ascii code in shifted state */
45247c478bd9Sstevel@tonic-gate   unsigned char keycode;		/* keyboard scancode */
45257c478bd9Sstevel@tonic-gate };
45267c478bd9Sstevel@tonic-gate 
45277c478bd9Sstevel@tonic-gate /* The table for key symbols. If the "shifted" member of an entry is
45287c478bd9Sstevel@tonic-gate    NULL, the entry does not have shifted state.  */
45297c478bd9Sstevel@tonic-gate static struct keysym keysym_table[] =
45307c478bd9Sstevel@tonic-gate {
45317c478bd9Sstevel@tonic-gate   {"escape",		0,		0x1b,	0,	0x01},
45327c478bd9Sstevel@tonic-gate   {"1",			"exclam",	'1',	'!',	0x02},
45337c478bd9Sstevel@tonic-gate   {"2",			"at",		'2',	'@',	0x03},
45347c478bd9Sstevel@tonic-gate   {"3",			"numbersign",	'3',	'#',	0x04},
45357c478bd9Sstevel@tonic-gate   {"4",			"dollar",	'4',	'$',	0x05},
45367c478bd9Sstevel@tonic-gate   {"5",			"percent",	'5',	'%',	0x06},
45377c478bd9Sstevel@tonic-gate   {"6",			"caret",	'6',	'^',	0x07},
45387c478bd9Sstevel@tonic-gate   {"7",			"ampersand",	'7',	'&',	0x08},
45397c478bd9Sstevel@tonic-gate   {"8",			"asterisk",	'8',	'*',	0x09},
45407c478bd9Sstevel@tonic-gate   {"9",			"parenleft",	'9',	'(',	0x0a},
45417c478bd9Sstevel@tonic-gate   {"0",			"parenright",	'0',	')',	0x0b},
45427c478bd9Sstevel@tonic-gate   {"minus",		"underscore",	'-',	'_',	0x0c},
45437c478bd9Sstevel@tonic-gate   {"equal",		"plus",		'=',	'+',	0x0d},
45447c478bd9Sstevel@tonic-gate   {"backspace",		0,		'\b',	0,	0x0e},
45457c478bd9Sstevel@tonic-gate   {"tab",		0,		'\t',	0,	0x0f},
45467c478bd9Sstevel@tonic-gate   {"q",			"Q",		'q',	'Q',	0x10},
45477c478bd9Sstevel@tonic-gate   {"w",			"W",		'w',	'W',	0x11},
45487c478bd9Sstevel@tonic-gate   {"e",			"E",		'e',	'E',	0x12},
45497c478bd9Sstevel@tonic-gate   {"r",			"R",		'r',	'R',	0x13},
45507c478bd9Sstevel@tonic-gate   {"t",			"T",		't',	'T',	0x14},
45517c478bd9Sstevel@tonic-gate   {"y",			"Y",		'y',	'Y',	0x15},
45527c478bd9Sstevel@tonic-gate   {"u",			"U",		'u',	'U',	0x16},
45537c478bd9Sstevel@tonic-gate   {"i",			"I",		'i',	'I',	0x17},
45547c478bd9Sstevel@tonic-gate   {"o",			"O",		'o',	'O',	0x18},
45557c478bd9Sstevel@tonic-gate   {"p",			"P",		'p',	'P',	0x19},
45567c478bd9Sstevel@tonic-gate   {"bracketleft",	"braceleft",	'[',	'{',	0x1a},
45577c478bd9Sstevel@tonic-gate   {"bracketright",	"braceright",	']',	'}',	0x1b},
45587c478bd9Sstevel@tonic-gate   {"enter",		0,		'\n',	0,	0x1c},
45597c478bd9Sstevel@tonic-gate   {"control",		0,		0,	0,	0x1d},
45607c478bd9Sstevel@tonic-gate   {"a",			"A",		'a',	'A',	0x1e},
45617c478bd9Sstevel@tonic-gate   {"s",			"S",		's',	'S',	0x1f},
45627c478bd9Sstevel@tonic-gate   {"d",			"D",		'd',	'D',	0x20},
45637c478bd9Sstevel@tonic-gate   {"f",			"F",		'f',	'F',	0x21},
45647c478bd9Sstevel@tonic-gate   {"g",			"G",		'g',	'G',	0x22},
45657c478bd9Sstevel@tonic-gate   {"h",			"H",		'h',	'H',	0x23},
45667c478bd9Sstevel@tonic-gate   {"j",			"J",		'j',	'J',	0x24},
45677c478bd9Sstevel@tonic-gate   {"k",			"K",		'k',	'K',	0x25},
45687c478bd9Sstevel@tonic-gate   {"l",			"L",		'l',	'L',	0x26},
45697c478bd9Sstevel@tonic-gate   {"semicolon",		"colon",	';',	':',	0x27},
45707c478bd9Sstevel@tonic-gate   {"quote",		"doublequote",	'\'',	'"',	0x28},
45717c478bd9Sstevel@tonic-gate   {"backquote",		"tilde",	'`',	'~',	0x29},
45727c478bd9Sstevel@tonic-gate   {"shift",		0,		0,	0,	0x2a},
45737c478bd9Sstevel@tonic-gate   {"backslash",		"bar",		'\\',	'|',	0x2b},
45747c478bd9Sstevel@tonic-gate   {"z",			"Z",		'z',	'Z',	0x2c},
45757c478bd9Sstevel@tonic-gate   {"x",			"X",		'x',	'X',	0x2d},
45767c478bd9Sstevel@tonic-gate   {"c",			"C",		'c',	'C',	0x2e},
45777c478bd9Sstevel@tonic-gate   {"v",			"V",		'v',	'V',	0x2f},
45787c478bd9Sstevel@tonic-gate   {"b",			"B",		'b',	'B',	0x30},
45797c478bd9Sstevel@tonic-gate   {"n",			"N",		'n',	'N',	0x31},
45807c478bd9Sstevel@tonic-gate   {"m",			"M",		'm',	'M',	0x32},
45817c478bd9Sstevel@tonic-gate   {"comma",		"less",		',',	'<',	0x33},
45827c478bd9Sstevel@tonic-gate   {"period",		"greater",	'.',	'>',	0x34},
45837c478bd9Sstevel@tonic-gate   {"slash",		"question",	'/',	'?',	0x35},
45847c478bd9Sstevel@tonic-gate   {"alt",		0,		0,	0,	0x38},
45857c478bd9Sstevel@tonic-gate   {"space",		0,		' ',	0,	0x39},
45867c478bd9Sstevel@tonic-gate   {"capslock",		0,		0,	0,	0x3a},
45877c478bd9Sstevel@tonic-gate   {"F1",		0,		0,	0,	0x3b},
45887c478bd9Sstevel@tonic-gate   {"F2",		0,		0,	0,	0x3c},
45897c478bd9Sstevel@tonic-gate   {"F3",		0,		0,	0,	0x3d},
45907c478bd9Sstevel@tonic-gate   {"F4",		0,		0,	0,	0x3e},
45917c478bd9Sstevel@tonic-gate   {"F5",		0,		0,	0,	0x3f},
45927c478bd9Sstevel@tonic-gate   {"F6",		0,		0,	0,	0x40},
45937c478bd9Sstevel@tonic-gate   {"F7",		0,		0,	0,	0x41},
45947c478bd9Sstevel@tonic-gate   {"F8",		0,		0,	0,	0x42},
45957c478bd9Sstevel@tonic-gate   {"F9",		0,		0,	0,	0x43},
45967c478bd9Sstevel@tonic-gate   {"F10",		0,		0,	0,	0x44},
45977c478bd9Sstevel@tonic-gate   /* Caution: do not add NumLock here! we cannot deal with it properly.  */
45987c478bd9Sstevel@tonic-gate   {"delete",		0,		0x7f,	0,	0x53}
45997c478bd9Sstevel@tonic-gate };
46007c478bd9Sstevel@tonic-gate 
46017c478bd9Sstevel@tonic-gate static int
46027c478bd9Sstevel@tonic-gate setkey_func (char *arg, int flags)
46037c478bd9Sstevel@tonic-gate {
46047c478bd9Sstevel@tonic-gate   char *to_key, *from_key;
46057c478bd9Sstevel@tonic-gate   int to_code, from_code;
46067c478bd9Sstevel@tonic-gate   int map_in_interrupt = 0;
46077c478bd9Sstevel@tonic-gate 
46081b8adde7SWilliam Kucharski   auto int find_key_code (char *key);
46091b8adde7SWilliam Kucharski   auto int find_ascii_code (char *key);
46101b8adde7SWilliam Kucharski 
46111b8adde7SWilliam Kucharski   auto int find_key_code (char *key)
46127c478bd9Sstevel@tonic-gate     {
46137c478bd9Sstevel@tonic-gate       int i;
46147c478bd9Sstevel@tonic-gate 
46157c478bd9Sstevel@tonic-gate       for (i = 0; i < sizeof (keysym_table) / sizeof (keysym_table[0]); i++)
46167c478bd9Sstevel@tonic-gate 	{
46177c478bd9Sstevel@tonic-gate 	  if (keysym_table[i].unshifted_name &&
46187c478bd9Sstevel@tonic-gate 	      grub_strcmp (key, keysym_table[i].unshifted_name) == 0)
46197c478bd9Sstevel@tonic-gate 	    return keysym_table[i].keycode;
46207c478bd9Sstevel@tonic-gate 	  else if (keysym_table[i].shifted_name &&
46217c478bd9Sstevel@tonic-gate 		   grub_strcmp (key, keysym_table[i].shifted_name) == 0)
46227c478bd9Sstevel@tonic-gate 	    return keysym_table[i].keycode;
46237c478bd9Sstevel@tonic-gate 	}
46247c478bd9Sstevel@tonic-gate 
46257c478bd9Sstevel@tonic-gate       return 0;
46267c478bd9Sstevel@tonic-gate     }
46277c478bd9Sstevel@tonic-gate 
46281b8adde7SWilliam Kucharski   auto int find_ascii_code (char *key)
46297c478bd9Sstevel@tonic-gate     {
46307c478bd9Sstevel@tonic-gate       int i;
46317c478bd9Sstevel@tonic-gate 
46327c478bd9Sstevel@tonic-gate       for (i = 0; i < sizeof (keysym_table) / sizeof (keysym_table[0]); i++)
46337c478bd9Sstevel@tonic-gate 	{
46347c478bd9Sstevel@tonic-gate 	  if (keysym_table[i].unshifted_name &&
46357c478bd9Sstevel@tonic-gate 	      grub_strcmp (key, keysym_table[i].unshifted_name) == 0)
46367c478bd9Sstevel@tonic-gate 	    return keysym_table[i].unshifted_ascii;
46377c478bd9Sstevel@tonic-gate 	  else if (keysym_table[i].shifted_name &&
46387c478bd9Sstevel@tonic-gate 		   grub_strcmp (key, keysym_table[i].shifted_name) == 0)
46397c478bd9Sstevel@tonic-gate 	    return keysym_table[i].shifted_ascii;
46407c478bd9Sstevel@tonic-gate 	}
46417c478bd9Sstevel@tonic-gate 
46427c478bd9Sstevel@tonic-gate       return 0;
46437c478bd9Sstevel@tonic-gate     }
46447c478bd9Sstevel@tonic-gate 
46457c478bd9Sstevel@tonic-gate   to_key = arg;
46467c478bd9Sstevel@tonic-gate   from_key = skip_to (0, to_key);
46477c478bd9Sstevel@tonic-gate 
46487c478bd9Sstevel@tonic-gate   if (! *to_key)
46497c478bd9Sstevel@tonic-gate     {
46507c478bd9Sstevel@tonic-gate       /* If the user specifies no argument, reset the key mappings.  */
46517c478bd9Sstevel@tonic-gate       grub_memset (bios_key_map, 0, KEY_MAP_SIZE * sizeof (unsigned short));
46527c478bd9Sstevel@tonic-gate       grub_memset (ascii_key_map, 0, KEY_MAP_SIZE * sizeof (unsigned short));
46537c478bd9Sstevel@tonic-gate 
46547c478bd9Sstevel@tonic-gate       return 0;
46557c478bd9Sstevel@tonic-gate     }
46567c478bd9Sstevel@tonic-gate   else if (! *from_key)
46577c478bd9Sstevel@tonic-gate     {
46587c478bd9Sstevel@tonic-gate       /* The user must specify two arguments or zero argument.  */
46597c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
46607c478bd9Sstevel@tonic-gate       return 1;
46617c478bd9Sstevel@tonic-gate     }
46627c478bd9Sstevel@tonic-gate 
46637c478bd9Sstevel@tonic-gate   nul_terminate (to_key);
46647c478bd9Sstevel@tonic-gate   nul_terminate (from_key);
46657c478bd9Sstevel@tonic-gate 
46667c478bd9Sstevel@tonic-gate   to_code = find_ascii_code (to_key);
46677c478bd9Sstevel@tonic-gate   from_code = find_ascii_code (from_key);
46687c478bd9Sstevel@tonic-gate   if (! to_code || ! from_code)
46697c478bd9Sstevel@tonic-gate     {
46707c478bd9Sstevel@tonic-gate       map_in_interrupt = 1;
46717c478bd9Sstevel@tonic-gate       to_code = find_key_code (to_key);
46727c478bd9Sstevel@tonic-gate       from_code = find_key_code (from_key);
46737c478bd9Sstevel@tonic-gate       if (! to_code || ! from_code)
46747c478bd9Sstevel@tonic-gate 	{
46757c478bd9Sstevel@tonic-gate 	  errnum = ERR_BAD_ARGUMENT;
46767c478bd9Sstevel@tonic-gate 	  return 1;
46777c478bd9Sstevel@tonic-gate 	}
46787c478bd9Sstevel@tonic-gate     }
46797c478bd9Sstevel@tonic-gate 
46807c478bd9Sstevel@tonic-gate   if (map_in_interrupt)
46817c478bd9Sstevel@tonic-gate     {
46827c478bd9Sstevel@tonic-gate       int i;
46837c478bd9Sstevel@tonic-gate 
46847c478bd9Sstevel@tonic-gate       /* Find an empty slot.  */
46857c478bd9Sstevel@tonic-gate       for (i = 0; i < KEY_MAP_SIZE; i++)
46867c478bd9Sstevel@tonic-gate 	{
46877c478bd9Sstevel@tonic-gate 	  if ((bios_key_map[i] & 0xff) == from_code)
46887c478bd9Sstevel@tonic-gate 	    /* Perhaps the user wants to overwrite the map.  */
46897c478bd9Sstevel@tonic-gate 	    break;
46907c478bd9Sstevel@tonic-gate 
46917c478bd9Sstevel@tonic-gate 	  if (! bios_key_map[i])
46927c478bd9Sstevel@tonic-gate 	    break;
46937c478bd9Sstevel@tonic-gate 	}
46947c478bd9Sstevel@tonic-gate 
46957c478bd9Sstevel@tonic-gate       if (i == KEY_MAP_SIZE)
46967c478bd9Sstevel@tonic-gate 	{
46977c478bd9Sstevel@tonic-gate 	  errnum = ERR_WONT_FIT;
46987c478bd9Sstevel@tonic-gate 	  return 1;
46997c478bd9Sstevel@tonic-gate 	}
47007c478bd9Sstevel@tonic-gate 
47017c478bd9Sstevel@tonic-gate       if (to_code == from_code)
47027c478bd9Sstevel@tonic-gate 	/* If TO is equal to FROM, delete the entry.  */
47037c478bd9Sstevel@tonic-gate 	grub_memmove ((char *) &bios_key_map[i],
47047c478bd9Sstevel@tonic-gate 		      (char *) &bios_key_map[i + 1],
47057c478bd9Sstevel@tonic-gate 		      sizeof (unsigned short) * (KEY_MAP_SIZE - i));
47067c478bd9Sstevel@tonic-gate       else
47077c478bd9Sstevel@tonic-gate 	bios_key_map[i] = (to_code << 8) | from_code;
47087c478bd9Sstevel@tonic-gate 
47097c478bd9Sstevel@tonic-gate       /* Ugly but should work.  */
47107c478bd9Sstevel@tonic-gate       unset_int15_handler ();
47117c478bd9Sstevel@tonic-gate       set_int15_handler ();
47127c478bd9Sstevel@tonic-gate     }
47137c478bd9Sstevel@tonic-gate   else
47147c478bd9Sstevel@tonic-gate     {
47157c478bd9Sstevel@tonic-gate       int i;
47167c478bd9Sstevel@tonic-gate 
47177c478bd9Sstevel@tonic-gate       /* Find an empty slot.  */
47187c478bd9Sstevel@tonic-gate       for (i = 0; i < KEY_MAP_SIZE; i++)
47197c478bd9Sstevel@tonic-gate 	{
47207c478bd9Sstevel@tonic-gate 	  if ((ascii_key_map[i] & 0xff) == from_code)
47217c478bd9Sstevel@tonic-gate 	    /* Perhaps the user wants to overwrite the map.  */
47227c478bd9Sstevel@tonic-gate 	    break;
47237c478bd9Sstevel@tonic-gate 
47247c478bd9Sstevel@tonic-gate 	  if (! ascii_key_map[i])
47257c478bd9Sstevel@tonic-gate 	    break;
47267c478bd9Sstevel@tonic-gate 	}
47277c478bd9Sstevel@tonic-gate 
47287c478bd9Sstevel@tonic-gate       if (i == KEY_MAP_SIZE)
47297c478bd9Sstevel@tonic-gate 	{
47307c478bd9Sstevel@tonic-gate 	  errnum = ERR_WONT_FIT;
47317c478bd9Sstevel@tonic-gate 	  return 1;
47327c478bd9Sstevel@tonic-gate 	}
47337c478bd9Sstevel@tonic-gate 
47347c478bd9Sstevel@tonic-gate       if (to_code == from_code)
47357c478bd9Sstevel@tonic-gate 	/* If TO is equal to FROM, delete the entry.  */
47367c478bd9Sstevel@tonic-gate 	grub_memmove ((char *) &ascii_key_map[i],
47377c478bd9Sstevel@tonic-gate 		      (char *) &ascii_key_map[i + 1],
47387c478bd9Sstevel@tonic-gate 		      sizeof (unsigned short) * (KEY_MAP_SIZE - i));
47397c478bd9Sstevel@tonic-gate       else
47407c478bd9Sstevel@tonic-gate 	ascii_key_map[i] = (to_code << 8) | from_code;
47417c478bd9Sstevel@tonic-gate     }
47427c478bd9Sstevel@tonic-gate 
47437c478bd9Sstevel@tonic-gate   return 0;
47447c478bd9Sstevel@tonic-gate }
47457c478bd9Sstevel@tonic-gate 
47467c478bd9Sstevel@tonic-gate static struct builtin builtin_setkey =
47477c478bd9Sstevel@tonic-gate {
47487c478bd9Sstevel@tonic-gate   "setkey",
47497c478bd9Sstevel@tonic-gate   setkey_func,
47507c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
47517c478bd9Sstevel@tonic-gate   "setkey [TO_KEY FROM_KEY]",
47527c478bd9Sstevel@tonic-gate   "Change the keyboard map. The key FROM_KEY is mapped to the key TO_KEY."
47537c478bd9Sstevel@tonic-gate   " A key must be an alphabet, a digit, or one of these: escape, exclam,"
47547c478bd9Sstevel@tonic-gate   " at, numbersign, dollar, percent, caret, ampersand, asterisk, parenleft,"
47557c478bd9Sstevel@tonic-gate   " parenright, minus, underscore, equal, plus, backspace, tab, bracketleft,"
47567c478bd9Sstevel@tonic-gate   " braceleft, bracketright, braceright, enter, control, semicolon, colon,"
47577c478bd9Sstevel@tonic-gate   " quote, doublequote, backquote, tilde, shift, backslash, bar, comma,"
47587c478bd9Sstevel@tonic-gate   " less, period, greater, slash, question, alt, space, capslock, FX (X"
47597c478bd9Sstevel@tonic-gate   " is a digit), and delete. If no argument is specified, reset key"
47607c478bd9Sstevel@tonic-gate   " mappings."
47617c478bd9Sstevel@tonic-gate };
47627c478bd9Sstevel@tonic-gate 
47637c478bd9Sstevel@tonic-gate 
47647c478bd9Sstevel@tonic-gate /* setup */
47657c478bd9Sstevel@tonic-gate static int
47667c478bd9Sstevel@tonic-gate setup_func (char *arg, int flags)
47677c478bd9Sstevel@tonic-gate {
47687c478bd9Sstevel@tonic-gate   /* Point to the string of the installed drive/partition.  */
47697c478bd9Sstevel@tonic-gate   char *install_ptr;
47707c478bd9Sstevel@tonic-gate   /* Point to the string of the drive/parition where the GRUB images
47717c478bd9Sstevel@tonic-gate      reside.  */
47727c478bd9Sstevel@tonic-gate   char *image_ptr;
47737c478bd9Sstevel@tonic-gate   unsigned long installed_drive, installed_partition;
47747c478bd9Sstevel@tonic-gate   unsigned long image_drive, image_partition;
47757c478bd9Sstevel@tonic-gate   unsigned long tmp_drive, tmp_partition;
47767c478bd9Sstevel@tonic-gate   char stage1[64];
47777c478bd9Sstevel@tonic-gate   char stage2[64];
47787c478bd9Sstevel@tonic-gate   char config_filename[64];
47797c478bd9Sstevel@tonic-gate   char real_config_filename[64];
47807c478bd9Sstevel@tonic-gate   char cmd_arg[256];
47817c478bd9Sstevel@tonic-gate   char device[16];
47827c478bd9Sstevel@tonic-gate   char *buffer = (char *) RAW_ADDR (0x100000);
47837c478bd9Sstevel@tonic-gate   int is_force_lba = 0;
47847c478bd9Sstevel@tonic-gate   char *stage2_arg = 0;
47857c478bd9Sstevel@tonic-gate   char *prefix = 0;
47867c478bd9Sstevel@tonic-gate 
47877c478bd9Sstevel@tonic-gate   auto int check_file (char *file);
47887c478bd9Sstevel@tonic-gate   auto void sprint_device (int drive, int partition);
47897c478bd9Sstevel@tonic-gate   auto int embed_stage1_5 (char * stage1_5, int drive, int partition);
47907c478bd9Sstevel@tonic-gate 
47917c478bd9Sstevel@tonic-gate   /* Check if the file FILE exists like Autoconf.  */
47927c478bd9Sstevel@tonic-gate   int check_file (char *file)
47937c478bd9Sstevel@tonic-gate     {
47947c478bd9Sstevel@tonic-gate       int ret;
47957c478bd9Sstevel@tonic-gate 
47967c478bd9Sstevel@tonic-gate       grub_printf (" Checking if \"%s\" exists... ", file);
47977c478bd9Sstevel@tonic-gate       ret = grub_open (file);
47987c478bd9Sstevel@tonic-gate       if (ret)
47997c478bd9Sstevel@tonic-gate 	{
48007c478bd9Sstevel@tonic-gate 	  grub_close ();
48017c478bd9Sstevel@tonic-gate 	  grub_printf ("yes\n");
48027c478bd9Sstevel@tonic-gate 	}
48037c478bd9Sstevel@tonic-gate       else
48047c478bd9Sstevel@tonic-gate 	grub_printf ("no\n");
48057c478bd9Sstevel@tonic-gate 
48067c478bd9Sstevel@tonic-gate       return ret;
48077c478bd9Sstevel@tonic-gate     }
48087c478bd9Sstevel@tonic-gate 
48097c478bd9Sstevel@tonic-gate   /* Construct a device name in DEVICE.  */
48107c478bd9Sstevel@tonic-gate   void sprint_device (int drive, int partition)
48117c478bd9Sstevel@tonic-gate     {
48127c478bd9Sstevel@tonic-gate       grub_sprintf (device, "(%cd%d",
48137c478bd9Sstevel@tonic-gate 		    (drive & 0x80) ? 'h' : 'f',
48147c478bd9Sstevel@tonic-gate 		    drive & ~0x80);
48157c478bd9Sstevel@tonic-gate       if ((partition & 0xFF0000) != 0xFF0000)
48167c478bd9Sstevel@tonic-gate 	{
48177c478bd9Sstevel@tonic-gate 	  char tmp[16];
48187c478bd9Sstevel@tonic-gate 	  grub_sprintf (tmp, ",%d", (partition >> 16) & 0xFF);
48197c478bd9Sstevel@tonic-gate 	  grub_strncat (device, tmp, 256);
48207c478bd9Sstevel@tonic-gate 	}
48217c478bd9Sstevel@tonic-gate       if ((partition & 0x00FF00) != 0x00FF00)
48227c478bd9Sstevel@tonic-gate 	{
48237c478bd9Sstevel@tonic-gate 	  char tmp[16];
48247c478bd9Sstevel@tonic-gate 	  grub_sprintf (tmp, ",%c", 'a' + ((partition >> 8) & 0xFF));
48257c478bd9Sstevel@tonic-gate 	  grub_strncat (device, tmp, 256);
48267c478bd9Sstevel@tonic-gate 	}
48277c478bd9Sstevel@tonic-gate       grub_strncat (device, ")", 256);
48287c478bd9Sstevel@tonic-gate     }
48297c478bd9Sstevel@tonic-gate 
48307c478bd9Sstevel@tonic-gate   int embed_stage1_5 (char *stage1_5, int drive, int partition)
48317c478bd9Sstevel@tonic-gate     {
48327c478bd9Sstevel@tonic-gate       /* We install GRUB into the MBR, so try to embed the
48337c478bd9Sstevel@tonic-gate 	 Stage 1.5 in the sectors right after the MBR.  */
48347c478bd9Sstevel@tonic-gate       sprint_device (drive, partition);
48357c478bd9Sstevel@tonic-gate       grub_sprintf (cmd_arg, "%s %s", stage1_5, device);
48367c478bd9Sstevel@tonic-gate 
48377c478bd9Sstevel@tonic-gate       /* Notify what will be run.  */
48387c478bd9Sstevel@tonic-gate       grub_printf (" Running \"embed %s\"... ", cmd_arg);
48397c478bd9Sstevel@tonic-gate 
48407c478bd9Sstevel@tonic-gate       embed_func (cmd_arg, flags);
48417c478bd9Sstevel@tonic-gate       if (! errnum)
48427c478bd9Sstevel@tonic-gate 	{
48437c478bd9Sstevel@tonic-gate 	  /* Construct the blocklist representation.  */
48447c478bd9Sstevel@tonic-gate 	  grub_sprintf (buffer, "%s%s", device, embed_info);
48457c478bd9Sstevel@tonic-gate 	  grub_printf ("succeeded\n");
48467c478bd9Sstevel@tonic-gate 	  return 1;
48477c478bd9Sstevel@tonic-gate 	}
48487c478bd9Sstevel@tonic-gate       else
48497c478bd9Sstevel@tonic-gate 	{
48507c478bd9Sstevel@tonic-gate 	  grub_printf ("failed (this is not fatal)\n");
48517c478bd9Sstevel@tonic-gate 	  return 0;
48527c478bd9Sstevel@tonic-gate 	}
48537c478bd9Sstevel@tonic-gate     }
48547c478bd9Sstevel@tonic-gate 
48557c478bd9Sstevel@tonic-gate   struct stage1_5_map {
48567c478bd9Sstevel@tonic-gate     char *fsys;
48577c478bd9Sstevel@tonic-gate     char *name;
48587c478bd9Sstevel@tonic-gate   };
48597c478bd9Sstevel@tonic-gate   struct stage1_5_map stage1_5_map[] =
48607c478bd9Sstevel@tonic-gate   {
48617c478bd9Sstevel@tonic-gate     {"ext2fs",   "/e2fs_stage1_5"},
48627c478bd9Sstevel@tonic-gate     {"fat",      "/fat_stage1_5"},
48637c478bd9Sstevel@tonic-gate     {"ufs2",     "/ufs2_stage1_5"},
48647c478bd9Sstevel@tonic-gate     {"ffs",      "/ffs_stage1_5"},
48657c478bd9Sstevel@tonic-gate     {"iso9660",  "/iso9660_stage1_5"},
48667c478bd9Sstevel@tonic-gate     {"jfs",      "/jfs_stage1_5"},
48677c478bd9Sstevel@tonic-gate     {"minix",    "/minix_stage1_5"},
48687c478bd9Sstevel@tonic-gate     {"reiserfs", "/reiserfs_stage1_5"},
48697c478bd9Sstevel@tonic-gate     {"vstafs",   "/vstafs_stage1_5"},
48707c478bd9Sstevel@tonic-gate     {"xfs",      "/xfs_stage1_5"},
48717c478bd9Sstevel@tonic-gate     {"ufs",      "/ufs_stage1_5"}
48727c478bd9Sstevel@tonic-gate   };
48737c478bd9Sstevel@tonic-gate 
48747c478bd9Sstevel@tonic-gate   tmp_drive = saved_drive;
48757c478bd9Sstevel@tonic-gate   tmp_partition = saved_partition;
48767c478bd9Sstevel@tonic-gate 
48777c478bd9Sstevel@tonic-gate   /* Check if the user specifies --force-lba.  */
48787c478bd9Sstevel@tonic-gate   while (1)
48797c478bd9Sstevel@tonic-gate     {
48807c478bd9Sstevel@tonic-gate       if (grub_memcmp ("--force-lba", arg, sizeof ("--force-lba") - 1) == 0)
48817c478bd9Sstevel@tonic-gate 	{
48827c478bd9Sstevel@tonic-gate 	  is_force_lba = 1;
48837c478bd9Sstevel@tonic-gate 	  arg = skip_to (0, arg);
48847c478bd9Sstevel@tonic-gate 	}
48857c478bd9Sstevel@tonic-gate       else if (grub_memcmp ("--prefix=", arg, sizeof ("--prefix=") - 1) == 0)
48867c478bd9Sstevel@tonic-gate 	{
48877c478bd9Sstevel@tonic-gate 	  prefix = arg + sizeof ("--prefix=") - 1;
48887c478bd9Sstevel@tonic-gate 	  arg = skip_to (0, arg);
48897c478bd9Sstevel@tonic-gate 	  nul_terminate (prefix);
48907c478bd9Sstevel@tonic-gate 	}
48917c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
48927c478bd9Sstevel@tonic-gate       else if (grub_memcmp ("--stage2=", arg, sizeof ("--stage2=") - 1) == 0)
48937c478bd9Sstevel@tonic-gate 	{
48947c478bd9Sstevel@tonic-gate 	  stage2_arg = arg;
48957c478bd9Sstevel@tonic-gate 	  arg = skip_to (0, arg);
48967c478bd9Sstevel@tonic-gate 	  nul_terminate (stage2_arg);
48977c478bd9Sstevel@tonic-gate 	}
48987c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
48997c478bd9Sstevel@tonic-gate       else
49007c478bd9Sstevel@tonic-gate 	break;
49017c478bd9Sstevel@tonic-gate     }
49027c478bd9Sstevel@tonic-gate 
49037c478bd9Sstevel@tonic-gate   install_ptr = arg;
49047c478bd9Sstevel@tonic-gate   image_ptr = skip_to (0, install_ptr);
49057c478bd9Sstevel@tonic-gate 
49067c478bd9Sstevel@tonic-gate   /* Make sure that INSTALL_PTR is valid.  */
49077c478bd9Sstevel@tonic-gate   set_device (install_ptr);
49087c478bd9Sstevel@tonic-gate   if (errnum)
49097c478bd9Sstevel@tonic-gate     return 1;
49107c478bd9Sstevel@tonic-gate 
49117c478bd9Sstevel@tonic-gate   installed_drive = current_drive;
49127c478bd9Sstevel@tonic-gate   installed_partition = current_partition;
49137c478bd9Sstevel@tonic-gate 
49147c478bd9Sstevel@tonic-gate   /* Mount the drive pointed by IMAGE_PTR.  */
49157c478bd9Sstevel@tonic-gate   if (*image_ptr)
49167c478bd9Sstevel@tonic-gate     {
49177c478bd9Sstevel@tonic-gate       /* If the drive/partition where the images reside is specified,
49187c478bd9Sstevel@tonic-gate 	 get the drive and the partition.  */
49197c478bd9Sstevel@tonic-gate       set_device (image_ptr);
49207c478bd9Sstevel@tonic-gate       if (errnum)
49217c478bd9Sstevel@tonic-gate 	return 1;
49227c478bd9Sstevel@tonic-gate     }
49237c478bd9Sstevel@tonic-gate   else
49247c478bd9Sstevel@tonic-gate     {
49257c478bd9Sstevel@tonic-gate       /* If omitted, use SAVED_PARTITION and SAVED_DRIVE.  */
49267c478bd9Sstevel@tonic-gate       current_drive = saved_drive;
49277c478bd9Sstevel@tonic-gate       current_partition = saved_partition;
49287c478bd9Sstevel@tonic-gate     }
49297c478bd9Sstevel@tonic-gate 
49307c478bd9Sstevel@tonic-gate   image_drive = saved_drive = current_drive;
49317c478bd9Sstevel@tonic-gate   image_partition = saved_partition = current_partition;
49327c478bd9Sstevel@tonic-gate 
49337c478bd9Sstevel@tonic-gate   /* Open it.  */
49347c478bd9Sstevel@tonic-gate   if (! open_device ())
49357c478bd9Sstevel@tonic-gate     goto fail;
49367c478bd9Sstevel@tonic-gate 
49377c478bd9Sstevel@tonic-gate   /* Check if stage1 exists. If the user doesn't specify the option
49387c478bd9Sstevel@tonic-gate      `--prefix', attempt /boot/grub and /grub.  */
49397c478bd9Sstevel@tonic-gate   /* NOTE: It is dangerous to run this command without `--prefix' in the
49407c478bd9Sstevel@tonic-gate      grub shell, since that affects `--stage2'.  */
49417c478bd9Sstevel@tonic-gate   if (! prefix)
49427c478bd9Sstevel@tonic-gate     {
49437c478bd9Sstevel@tonic-gate       prefix = "/boot/grub";
49447c478bd9Sstevel@tonic-gate       grub_sprintf (stage1, "%s%s", prefix, "/stage1");
49457c478bd9Sstevel@tonic-gate       if (! check_file (stage1))
49467c478bd9Sstevel@tonic-gate 	{
49477c478bd9Sstevel@tonic-gate 	  errnum = ERR_NONE;
49487c478bd9Sstevel@tonic-gate 	  prefix = "/grub";
49497c478bd9Sstevel@tonic-gate 	  grub_sprintf (stage1, "%s%s", prefix, "/stage1");
49507c478bd9Sstevel@tonic-gate 	  if (! check_file (stage1))
49517c478bd9Sstevel@tonic-gate 	    goto fail;
49527c478bd9Sstevel@tonic-gate 	}
49537c478bd9Sstevel@tonic-gate     }
49547c478bd9Sstevel@tonic-gate   else
49557c478bd9Sstevel@tonic-gate     {
49567c478bd9Sstevel@tonic-gate       grub_sprintf (stage1, "%s%s", prefix, "/stage1");
49577c478bd9Sstevel@tonic-gate       if (! check_file (stage1))
49587c478bd9Sstevel@tonic-gate 	goto fail;
49597c478bd9Sstevel@tonic-gate     }
49607c478bd9Sstevel@tonic-gate 
49617c478bd9Sstevel@tonic-gate   /* The prefix was determined.  */
49627c478bd9Sstevel@tonic-gate   grub_sprintf (stage2, "%s%s", prefix, "/stage2");
49637c478bd9Sstevel@tonic-gate   grub_sprintf (config_filename, "%s%s", prefix, "/menu.lst");
49647c478bd9Sstevel@tonic-gate   *real_config_filename = 0;
49657c478bd9Sstevel@tonic-gate 
49667c478bd9Sstevel@tonic-gate   /* Check if stage2 exists.  */
49677c478bd9Sstevel@tonic-gate   if (! check_file (stage2))
49687c478bd9Sstevel@tonic-gate     goto fail;
49697c478bd9Sstevel@tonic-gate 
49707c478bd9Sstevel@tonic-gate   {
49717c478bd9Sstevel@tonic-gate     char *fsys = fsys_table[fsys_type].name;
49727c478bd9Sstevel@tonic-gate     int i;
49737c478bd9Sstevel@tonic-gate     int size = sizeof (stage1_5_map) / sizeof (stage1_5_map[0]);
49747c478bd9Sstevel@tonic-gate 
49757c478bd9Sstevel@tonic-gate     /* Iterate finding the same filesystem name as FSYS.  */
49767c478bd9Sstevel@tonic-gate     for (i = 0; i < size; i++)
49777c478bd9Sstevel@tonic-gate       if (grub_strcmp (fsys, stage1_5_map[i].fsys) == 0)
49787c478bd9Sstevel@tonic-gate 	{
49797c478bd9Sstevel@tonic-gate 	  /* OK, check if the Stage 1.5 exists.  */
49807c478bd9Sstevel@tonic-gate 	  char stage1_5[64];
49817c478bd9Sstevel@tonic-gate 
49827c478bd9Sstevel@tonic-gate 	  grub_sprintf (stage1_5, "%s%s", prefix, stage1_5_map[i].name);
49837c478bd9Sstevel@tonic-gate 	  if (check_file (stage1_5))
49847c478bd9Sstevel@tonic-gate 	    {
49857c478bd9Sstevel@tonic-gate 	      if (embed_stage1_5 (stage1_5,
49867c478bd9Sstevel@tonic-gate 				    installed_drive, installed_partition)
49877c478bd9Sstevel@tonic-gate 		  || embed_stage1_5 (stage1_5,
49887c478bd9Sstevel@tonic-gate 				     image_drive, image_partition))
49897c478bd9Sstevel@tonic-gate 		{
49907c478bd9Sstevel@tonic-gate 		  grub_strcpy (real_config_filename, config_filename);
49917c478bd9Sstevel@tonic-gate 		  sprint_device (image_drive, image_partition);
49927c478bd9Sstevel@tonic-gate 		  grub_sprintf (config_filename, "%s%s", device, stage2);
49937c478bd9Sstevel@tonic-gate 		  grub_strcpy (stage2, buffer);
49947c478bd9Sstevel@tonic-gate 		}
49957c478bd9Sstevel@tonic-gate 	    }
49967c478bd9Sstevel@tonic-gate 	  errnum = 0;
49977c478bd9Sstevel@tonic-gate 	  break;
49987c478bd9Sstevel@tonic-gate 	}
49997c478bd9Sstevel@tonic-gate   }
50007c478bd9Sstevel@tonic-gate 
50017c478bd9Sstevel@tonic-gate   /* Construct a string that is used by the command "install" as its
50027c478bd9Sstevel@tonic-gate      arguments.  */
50037c478bd9Sstevel@tonic-gate   sprint_device (installed_drive, installed_partition);
50047c478bd9Sstevel@tonic-gate 
50057c478bd9Sstevel@tonic-gate #if 1
50067c478bd9Sstevel@tonic-gate   /* Don't embed a drive number unnecessarily.  */
50077c478bd9Sstevel@tonic-gate   grub_sprintf (cmd_arg, "%s%s%s%s %s%s %s p %s %s",
50087c478bd9Sstevel@tonic-gate 		is_force_lba? "--force-lba " : "",
50097c478bd9Sstevel@tonic-gate 		stage2_arg? stage2_arg : "",
50107c478bd9Sstevel@tonic-gate 		stage2_arg? " " : "",
50117c478bd9Sstevel@tonic-gate 		stage1,
50127c478bd9Sstevel@tonic-gate 		(installed_drive != image_drive) ? "d " : "",
50137c478bd9Sstevel@tonic-gate 		device,
50147c478bd9Sstevel@tonic-gate 		stage2,
50157c478bd9Sstevel@tonic-gate 		config_filename,
50167c478bd9Sstevel@tonic-gate 		real_config_filename);
50177c478bd9Sstevel@tonic-gate #else /* NOT USED */
50187c478bd9Sstevel@tonic-gate   /* This code was used, because we belived some BIOSes had a problem
50197c478bd9Sstevel@tonic-gate      that they didn't pass a booting drive correctly. It turned out,
50207c478bd9Sstevel@tonic-gate      however, stage1 could trash a booting drive when checking LBA support,
50217c478bd9Sstevel@tonic-gate      because some BIOSes modified the register %dx in INT 13H, AH=48H.
50227c478bd9Sstevel@tonic-gate      So it becamed unclear whether GRUB should use a pre-defined booting
50237c478bd9Sstevel@tonic-gate      drive or not. If the problem still exists, it would be necessary to
50247c478bd9Sstevel@tonic-gate      switch back to this code.  */
50257c478bd9Sstevel@tonic-gate   grub_sprintf (cmd_arg, "%s%s%s%s d %s %s p %s %s",
50267c478bd9Sstevel@tonic-gate 		is_force_lba? "--force-lba " : "",
50277c478bd9Sstevel@tonic-gate 		stage2_arg? stage2_arg : "",
50287c478bd9Sstevel@tonic-gate 		stage2_arg? " " : "",
50297c478bd9Sstevel@tonic-gate 		stage1,
50307c478bd9Sstevel@tonic-gate 		device,
50317c478bd9Sstevel@tonic-gate 		stage2,
50327c478bd9Sstevel@tonic-gate 		config_filename,
50337c478bd9Sstevel@tonic-gate 		real_config_filename);
50347c478bd9Sstevel@tonic-gate #endif /* NOT USED */
50357c478bd9Sstevel@tonic-gate 
50367c478bd9Sstevel@tonic-gate   /* Notify what will be run.  */
50377c478bd9Sstevel@tonic-gate   grub_printf (" Running \"install %s\"... ", cmd_arg);
50387c478bd9Sstevel@tonic-gate 
50397c478bd9Sstevel@tonic-gate   /* Make sure that SAVED_DRIVE and SAVED_PARTITION are identical
50407c478bd9Sstevel@tonic-gate      with IMAGE_DRIVE and IMAGE_PARTITION, respectively.  */
50417c478bd9Sstevel@tonic-gate   saved_drive = image_drive;
50427c478bd9Sstevel@tonic-gate   saved_partition = image_partition;
50437c478bd9Sstevel@tonic-gate 
50447c478bd9Sstevel@tonic-gate   /* Run the command.  */
50457c478bd9Sstevel@tonic-gate   if (! install_func (cmd_arg, flags))
50467c478bd9Sstevel@tonic-gate     grub_printf ("succeeded\nDone.\n");
50477c478bd9Sstevel@tonic-gate   else
50487c478bd9Sstevel@tonic-gate     grub_printf ("failed\n");
50497c478bd9Sstevel@tonic-gate 
50507c478bd9Sstevel@tonic-gate  fail:
50517c478bd9Sstevel@tonic-gate   saved_drive = tmp_drive;
50527c478bd9Sstevel@tonic-gate   saved_partition = tmp_partition;
50537c478bd9Sstevel@tonic-gate   return errnum;
50547c478bd9Sstevel@tonic-gate }
50557c478bd9Sstevel@tonic-gate 
50567c478bd9Sstevel@tonic-gate static struct builtin builtin_setup =
50577c478bd9Sstevel@tonic-gate {
50587c478bd9Sstevel@tonic-gate   "setup",
50597c478bd9Sstevel@tonic-gate   setup_func,
50607c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
50617c478bd9Sstevel@tonic-gate   "setup [--prefix=DIR] [--stage2=STAGE2_FILE] [--force-lba] INSTALL_DEVICE [IMAGE_DEVICE]",
50627c478bd9Sstevel@tonic-gate   "Set up the installation of GRUB automatically. This command uses"
50637c478bd9Sstevel@tonic-gate   " the more flexible command \"install\" in the backend and installs"
50647c478bd9Sstevel@tonic-gate   " GRUB into the device INSTALL_DEVICE. If IMAGE_DEVICE is specified,"
50657c478bd9Sstevel@tonic-gate   " then find the GRUB images in the device IMAGE_DEVICE, otherwise"
50667c478bd9Sstevel@tonic-gate   " use the current \"root device\", which can be set by the command"
50677c478bd9Sstevel@tonic-gate   " \"root\". If you know that your BIOS should support LBA but GRUB"
50687c478bd9Sstevel@tonic-gate   " doesn't work in LBA mode, specify the option `--force-lba'."
50697c478bd9Sstevel@tonic-gate   " If you install GRUB under the grub shell and you cannot unmount the"
50707c478bd9Sstevel@tonic-gate   " partition where GRUB images reside, specify the option `--stage2'"
50717c478bd9Sstevel@tonic-gate   " to tell GRUB the file name under your OS."
50727c478bd9Sstevel@tonic-gate };
50737c478bd9Sstevel@tonic-gate 
50747c478bd9Sstevel@tonic-gate 
50757c478bd9Sstevel@tonic-gate #if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES) || defined(SUPPORT_GRAPHICS)
50767c478bd9Sstevel@tonic-gate /* terminal */
50777c478bd9Sstevel@tonic-gate static int
50787c478bd9Sstevel@tonic-gate terminal_func (char *arg, int flags)
50797c478bd9Sstevel@tonic-gate {
50807c478bd9Sstevel@tonic-gate   /* The index of the default terminal in TERM_TABLE.  */
50817c478bd9Sstevel@tonic-gate   int default_term = -1;
50827c478bd9Sstevel@tonic-gate   struct term_entry *prev_term = current_term;
50837c478bd9Sstevel@tonic-gate   int to = -1;
50847c478bd9Sstevel@tonic-gate   int lines = 0;
50857c478bd9Sstevel@tonic-gate   int no_message = 0;
50867c478bd9Sstevel@tonic-gate   unsigned long term_flags = 0;
50877c478bd9Sstevel@tonic-gate   /* XXX: Assume less than 32 terminals.  */
50887c478bd9Sstevel@tonic-gate   unsigned long term_bitmap = 0;
50897c478bd9Sstevel@tonic-gate 
50907c478bd9Sstevel@tonic-gate   /* Get GNU-style long options.  */
50917c478bd9Sstevel@tonic-gate   while (1)
50927c478bd9Sstevel@tonic-gate     {
50937c478bd9Sstevel@tonic-gate       if (grub_memcmp (arg, "--dumb", sizeof ("--dumb") - 1) == 0)
50947c478bd9Sstevel@tonic-gate 	term_flags |= TERM_DUMB;
50957c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--no-echo", sizeof ("--no-echo") - 1) == 0)
50967c478bd9Sstevel@tonic-gate 	/* ``--no-echo'' implies ``--no-edit''.  */
50977c478bd9Sstevel@tonic-gate 	term_flags |= (TERM_NO_ECHO | TERM_NO_EDIT);
50987c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--no-edit", sizeof ("--no-edit") - 1) == 0)
50997c478bd9Sstevel@tonic-gate 	term_flags |= TERM_NO_EDIT;
51007c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--timeout=", sizeof ("--timeout=") - 1) == 0)
51017c478bd9Sstevel@tonic-gate 	{
51027c478bd9Sstevel@tonic-gate 	  char *val = arg + sizeof ("--timeout=") - 1;
51037c478bd9Sstevel@tonic-gate 
51047c478bd9Sstevel@tonic-gate 	  if (! safe_parse_maxint (&val, &to))
51057c478bd9Sstevel@tonic-gate 	    return 1;
51067c478bd9Sstevel@tonic-gate 	}
51077c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--lines=", sizeof ("--lines=") - 1) == 0)
51087c478bd9Sstevel@tonic-gate 	{
51097c478bd9Sstevel@tonic-gate 	  char *val = arg + sizeof ("--lines=") - 1;
51107c478bd9Sstevel@tonic-gate 
51117c478bd9Sstevel@tonic-gate 	  if (! safe_parse_maxint (&val, &lines))
51127c478bd9Sstevel@tonic-gate 	    return 1;
51137c478bd9Sstevel@tonic-gate 
51147c478bd9Sstevel@tonic-gate 	  /* Probably less than four is meaningless....  */
51157c478bd9Sstevel@tonic-gate 	  if (lines < 4)
51167c478bd9Sstevel@tonic-gate 	    {
51177c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_ARGUMENT;
51187c478bd9Sstevel@tonic-gate 	      return 1;
51197c478bd9Sstevel@tonic-gate 	    }
51207c478bd9Sstevel@tonic-gate 	}
51217c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--silent", sizeof ("--silent") - 1) == 0)
51227c478bd9Sstevel@tonic-gate 	no_message = 1;
51237c478bd9Sstevel@tonic-gate       else
51247c478bd9Sstevel@tonic-gate 	break;
51257c478bd9Sstevel@tonic-gate 
51267c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
51277c478bd9Sstevel@tonic-gate     }
51287c478bd9Sstevel@tonic-gate 
51297c478bd9Sstevel@tonic-gate   /* If no argument is specified, show current setting.  */
51307c478bd9Sstevel@tonic-gate   if (! *arg)
51317c478bd9Sstevel@tonic-gate     {
51327c478bd9Sstevel@tonic-gate       grub_printf ("%s%s%s%s\n",
51337c478bd9Sstevel@tonic-gate 		   current_term->name,
51347c478bd9Sstevel@tonic-gate 		   current_term->flags & TERM_DUMB ? " (dumb)" : "",
51357c478bd9Sstevel@tonic-gate 		   current_term->flags & TERM_NO_EDIT ? " (no edit)" : "",
51367c478bd9Sstevel@tonic-gate 		   current_term->flags & TERM_NO_ECHO ? " (no echo)" : "");
51377c478bd9Sstevel@tonic-gate       return 0;
51387c478bd9Sstevel@tonic-gate     }
51397c478bd9Sstevel@tonic-gate 
51407c478bd9Sstevel@tonic-gate   while (*arg)
51417c478bd9Sstevel@tonic-gate     {
51427c478bd9Sstevel@tonic-gate       int i;
51437c478bd9Sstevel@tonic-gate       char *next = skip_to (0, arg);
51447c478bd9Sstevel@tonic-gate 
51457c478bd9Sstevel@tonic-gate       nul_terminate (arg);
51467c478bd9Sstevel@tonic-gate 
51477c478bd9Sstevel@tonic-gate       for (i = 0; term_table[i].name; i++)
51487c478bd9Sstevel@tonic-gate 	{
51497c478bd9Sstevel@tonic-gate 	  if (grub_strcmp (arg, term_table[i].name) == 0)
51507c478bd9Sstevel@tonic-gate 	    {
51517c478bd9Sstevel@tonic-gate 	      if (term_table[i].flags & TERM_NEED_INIT)
51527c478bd9Sstevel@tonic-gate 		{
51537c478bd9Sstevel@tonic-gate 		  errnum = ERR_DEV_NEED_INIT;
51547c478bd9Sstevel@tonic-gate 		  return 1;
51557c478bd9Sstevel@tonic-gate 		}
51567c478bd9Sstevel@tonic-gate 
51577c478bd9Sstevel@tonic-gate 	      if (default_term < 0)
51587c478bd9Sstevel@tonic-gate 		default_term = i;
51597c478bd9Sstevel@tonic-gate 
51607c478bd9Sstevel@tonic-gate 	      term_bitmap |= (1 << i);
51617c478bd9Sstevel@tonic-gate 	      break;
51627c478bd9Sstevel@tonic-gate 	    }
51637c478bd9Sstevel@tonic-gate 	}
51647c478bd9Sstevel@tonic-gate 
51657c478bd9Sstevel@tonic-gate       if (! term_table[i].name)
51667c478bd9Sstevel@tonic-gate 	{
51677c478bd9Sstevel@tonic-gate 	  errnum = ERR_BAD_ARGUMENT;
51687c478bd9Sstevel@tonic-gate 	  return 1;
51697c478bd9Sstevel@tonic-gate 	}
51707c478bd9Sstevel@tonic-gate 
51717c478bd9Sstevel@tonic-gate       arg = next;
51727c478bd9Sstevel@tonic-gate     }
51737c478bd9Sstevel@tonic-gate 
51747c478bd9Sstevel@tonic-gate   /* If multiple terminals are specified, wait until the user pushes any
51757c478bd9Sstevel@tonic-gate      key on one of the terminals.  */
51767c478bd9Sstevel@tonic-gate   if (term_bitmap & ~(1 << default_term))
51777c478bd9Sstevel@tonic-gate     {
51787c478bd9Sstevel@tonic-gate       int time1, time2 = -1;
51797c478bd9Sstevel@tonic-gate 
51807c478bd9Sstevel@tonic-gate       /* XXX: Disable the pager.  */
51817c478bd9Sstevel@tonic-gate       count_lines = -1;
51827c478bd9Sstevel@tonic-gate 
51837c478bd9Sstevel@tonic-gate       /* Get current time.  */
51847c478bd9Sstevel@tonic-gate       while ((time1 = getrtsecs ()) == 0xFF)
51857c478bd9Sstevel@tonic-gate 	;
51867c478bd9Sstevel@tonic-gate 
51877c478bd9Sstevel@tonic-gate       /* Wait for a key input.  */
51887c478bd9Sstevel@tonic-gate       while (to)
51897c478bd9Sstevel@tonic-gate 	{
51907c478bd9Sstevel@tonic-gate 	  int i;
51917c478bd9Sstevel@tonic-gate 
51927c478bd9Sstevel@tonic-gate 	  for (i = 0; term_table[i].name; i++)
51937c478bd9Sstevel@tonic-gate 	    {
51947c478bd9Sstevel@tonic-gate 	      if (term_bitmap & (1 << i))
51957c478bd9Sstevel@tonic-gate 		{
51967c478bd9Sstevel@tonic-gate 		  if (term_table[i].checkkey () >= 0)
51977c478bd9Sstevel@tonic-gate 		    {
51987c478bd9Sstevel@tonic-gate 		      (void) term_table[i].getkey ();
51997c478bd9Sstevel@tonic-gate 		      default_term = i;
52007c478bd9Sstevel@tonic-gate 
52017c478bd9Sstevel@tonic-gate 		      goto end;
52027c478bd9Sstevel@tonic-gate 		    }
52037c478bd9Sstevel@tonic-gate 		}
52047c478bd9Sstevel@tonic-gate 	    }
52057c478bd9Sstevel@tonic-gate 
52067c478bd9Sstevel@tonic-gate 	  /* Prompt the user, once per sec.  */
52077c478bd9Sstevel@tonic-gate 	  if ((time1 = getrtsecs ()) != time2 && time1 != 0xFF)
52087c478bd9Sstevel@tonic-gate 	    {
52097c478bd9Sstevel@tonic-gate 	      if (! no_message)
52107c478bd9Sstevel@tonic-gate 		{
52117c478bd9Sstevel@tonic-gate 		  /* Need to set CURRENT_TERM to each of selected
52127c478bd9Sstevel@tonic-gate 		     terminals.  */
52137c478bd9Sstevel@tonic-gate 		  for (i = 0; term_table[i].name; i++)
52147c478bd9Sstevel@tonic-gate 		    if (term_bitmap & (1 << i))
52157c478bd9Sstevel@tonic-gate 		      {
52167c478bd9Sstevel@tonic-gate 			current_term = term_table + i;
52177c478bd9Sstevel@tonic-gate 			grub_printf ("\rPress any key to continue.\n");
52187c478bd9Sstevel@tonic-gate 		      }
52197c478bd9Sstevel@tonic-gate 
52207c478bd9Sstevel@tonic-gate 		  /* Restore CURRENT_TERM.  */
52217c478bd9Sstevel@tonic-gate 		  current_term = prev_term;
52227c478bd9Sstevel@tonic-gate 		}
52237c478bd9Sstevel@tonic-gate 
52247c478bd9Sstevel@tonic-gate 	      time2 = time1;
52257c478bd9Sstevel@tonic-gate 	      if (to > 0)
52267c478bd9Sstevel@tonic-gate 		to--;
52277c478bd9Sstevel@tonic-gate 	    }
52287c478bd9Sstevel@tonic-gate 	}
52297c478bd9Sstevel@tonic-gate     }
52307c478bd9Sstevel@tonic-gate 
52317c478bd9Sstevel@tonic-gate  end:
52327c478bd9Sstevel@tonic-gate   current_term = term_table + default_term;
52337c478bd9Sstevel@tonic-gate   current_term->flags = term_flags;
52347c478bd9Sstevel@tonic-gate 
52357c478bd9Sstevel@tonic-gate   if (lines)
52367c478bd9Sstevel@tonic-gate     max_lines = lines;
52377c478bd9Sstevel@tonic-gate   else
52387c478bd9Sstevel@tonic-gate     max_lines = current_term->max_lines;
52397c478bd9Sstevel@tonic-gate 
52407c478bd9Sstevel@tonic-gate   /* If the interface is currently the command-line,
52417c478bd9Sstevel@tonic-gate      restart it to repaint the screen.  */
52427c478bd9Sstevel@tonic-gate   if ((current_term != prev_term) && (flags & BUILTIN_CMDLINE)){
52437c478bd9Sstevel@tonic-gate     if (prev_term->shutdown)
52447c478bd9Sstevel@tonic-gate       prev_term->shutdown();
52457c478bd9Sstevel@tonic-gate     if (current_term->startup)
52467c478bd9Sstevel@tonic-gate       current_term->startup();
52477c478bd9Sstevel@tonic-gate     grub_longjmp (restart_cmdline_env, 0);
52487c478bd9Sstevel@tonic-gate   }
52497c478bd9Sstevel@tonic-gate 
52507c478bd9Sstevel@tonic-gate   return 0;
52517c478bd9Sstevel@tonic-gate }
52527c478bd9Sstevel@tonic-gate 
52537c478bd9Sstevel@tonic-gate static struct builtin builtin_terminal =
52547c478bd9Sstevel@tonic-gate {
52557c478bd9Sstevel@tonic-gate   "terminal",
52567c478bd9Sstevel@tonic-gate   terminal_func,
52577c478bd9Sstevel@tonic-gate   BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
52587c478bd9Sstevel@tonic-gate   "terminal [--dumb] [--no-echo] [--no-edit] [--timeout=SECS] [--lines=LINES] [--silent] [console] [serial] [hercules] [graphics]",
52597c478bd9Sstevel@tonic-gate   "Select a terminal. When multiple terminals are specified, wait until"
52607c478bd9Sstevel@tonic-gate   " you push any key to continue. If both console and serial are specified,"
52617c478bd9Sstevel@tonic-gate   " the terminal to which you input a key first will be selected. If no"
52627c478bd9Sstevel@tonic-gate   " argument is specified, print current setting. The option --dumb"
52637c478bd9Sstevel@tonic-gate   " specifies that your terminal is dumb, otherwise, vt100-compatibility"
52647c478bd9Sstevel@tonic-gate   " is assumed. If you specify --no-echo, input characters won't be echoed."
52657c478bd9Sstevel@tonic-gate   " If you specify --no-edit, the BASH-like editing feature will be disabled."
52667c478bd9Sstevel@tonic-gate   " If --timeout is present, this command will wait at most for SECS"
52677c478bd9Sstevel@tonic-gate   " seconds. The option --lines specifies the maximum number of lines."
52687c478bd9Sstevel@tonic-gate   " The option --silent is used to suppress messages."
52697c478bd9Sstevel@tonic-gate };
52707c478bd9Sstevel@tonic-gate #endif /* SUPPORT_SERIAL || SUPPORT_HERCULES || SUPPORT_GRAPHICS */
52717c478bd9Sstevel@tonic-gate 
52727c478bd9Sstevel@tonic-gate 
52737c478bd9Sstevel@tonic-gate #ifdef SUPPORT_SERIAL
52747c478bd9Sstevel@tonic-gate static int
52757c478bd9Sstevel@tonic-gate terminfo_func (char *arg, int flags)
52767c478bd9Sstevel@tonic-gate {
52777c478bd9Sstevel@tonic-gate   struct terminfo term;
52787c478bd9Sstevel@tonic-gate 
52797c478bd9Sstevel@tonic-gate   if (*arg)
52807c478bd9Sstevel@tonic-gate     {
52817c478bd9Sstevel@tonic-gate       struct
52827c478bd9Sstevel@tonic-gate       {
52837c478bd9Sstevel@tonic-gate 	const char *name;
52847c478bd9Sstevel@tonic-gate 	char *var;
52857c478bd9Sstevel@tonic-gate       }
52867c478bd9Sstevel@tonic-gate       options[] =
52877c478bd9Sstevel@tonic-gate 	{
52887c478bd9Sstevel@tonic-gate 	  {"--name=", term.name},
52897c478bd9Sstevel@tonic-gate 	  {"--cursor-address=", term.cursor_address},
52907c478bd9Sstevel@tonic-gate 	  {"--clear-screen=", term.clear_screen},
52917c478bd9Sstevel@tonic-gate 	  {"--enter-standout-mode=", term.enter_standout_mode},
52927c478bd9Sstevel@tonic-gate 	  {"--exit-standout-mode=", term.exit_standout_mode}
52937c478bd9Sstevel@tonic-gate 	};
52947c478bd9Sstevel@tonic-gate 
52957c478bd9Sstevel@tonic-gate       grub_memset (&term, 0, sizeof (term));
52967c478bd9Sstevel@tonic-gate 
52977c478bd9Sstevel@tonic-gate       while (*arg)
52987c478bd9Sstevel@tonic-gate 	{
52997c478bd9Sstevel@tonic-gate 	  int i;
53007c478bd9Sstevel@tonic-gate 	  char *next = skip_to (0, arg);
53017c478bd9Sstevel@tonic-gate 
53027c478bd9Sstevel@tonic-gate 	  nul_terminate (arg);
53037c478bd9Sstevel@tonic-gate 
53047c478bd9Sstevel@tonic-gate 	  for (i = 0; i < sizeof (options) / sizeof (options[0]); i++)
53057c478bd9Sstevel@tonic-gate 	    {
53067c478bd9Sstevel@tonic-gate 	      const char *name = options[i].name;
53077c478bd9Sstevel@tonic-gate 	      int len = grub_strlen (name);
53087c478bd9Sstevel@tonic-gate 
53097c478bd9Sstevel@tonic-gate 	      if (! grub_memcmp (arg, name, len))
53107c478bd9Sstevel@tonic-gate 		{
53117c478bd9Sstevel@tonic-gate 		  grub_strcpy (options[i].var, ti_unescape_string (arg + len));
53127c478bd9Sstevel@tonic-gate 		  break;
53137c478bd9Sstevel@tonic-gate 		}
53147c478bd9Sstevel@tonic-gate 	    }
53157c478bd9Sstevel@tonic-gate 
53167c478bd9Sstevel@tonic-gate 	  if (i == sizeof (options) / sizeof (options[0]))
53177c478bd9Sstevel@tonic-gate 	    {
53187c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_ARGUMENT;
53197c478bd9Sstevel@tonic-gate 	      return errnum;
53207c478bd9Sstevel@tonic-gate 	    }
53217c478bd9Sstevel@tonic-gate 
53227c478bd9Sstevel@tonic-gate 	  arg = next;
53237c478bd9Sstevel@tonic-gate 	}
53247c478bd9Sstevel@tonic-gate 
53257c478bd9Sstevel@tonic-gate       if (term.name[0] == 0 || term.cursor_address[0] == 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       ti_set_term (&term);
53327c478bd9Sstevel@tonic-gate     }
53337c478bd9Sstevel@tonic-gate   else
53347c478bd9Sstevel@tonic-gate     {
53357c478bd9Sstevel@tonic-gate       /* No option specifies printing out current settings.  */
53367c478bd9Sstevel@tonic-gate       ti_get_term (&term);
53377c478bd9Sstevel@tonic-gate 
53387c478bd9Sstevel@tonic-gate       grub_printf ("name=%s\n",
53397c478bd9Sstevel@tonic-gate 		   ti_escape_string (term.name));
53407c478bd9Sstevel@tonic-gate       grub_printf ("cursor_address=%s\n",
53417c478bd9Sstevel@tonic-gate 		   ti_escape_string (term.cursor_address));
53427c478bd9Sstevel@tonic-gate       grub_printf ("clear_screen=%s\n",
53437c478bd9Sstevel@tonic-gate 		   ti_escape_string (term.clear_screen));
53447c478bd9Sstevel@tonic-gate       grub_printf ("enter_standout_mode=%s\n",
53457c478bd9Sstevel@tonic-gate 		   ti_escape_string (term.enter_standout_mode));
53467c478bd9Sstevel@tonic-gate       grub_printf ("exit_standout_mode=%s\n",
53477c478bd9Sstevel@tonic-gate 		   ti_escape_string (term.exit_standout_mode));
53487c478bd9Sstevel@tonic-gate     }
53497c478bd9Sstevel@tonic-gate 
53507c478bd9Sstevel@tonic-gate   return 0;
53517c478bd9Sstevel@tonic-gate }
53527c478bd9Sstevel@tonic-gate 
53537c478bd9Sstevel@tonic-gate static struct builtin builtin_terminfo =
53547c478bd9Sstevel@tonic-gate {
53557c478bd9Sstevel@tonic-gate   "terminfo",
53567c478bd9Sstevel@tonic-gate   terminfo_func,
53577c478bd9Sstevel@tonic-gate   BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
53587c478bd9Sstevel@tonic-gate   "terminfo [--name=NAME --cursor-address=SEQ [--clear-screen=SEQ]"
53597c478bd9Sstevel@tonic-gate   " [--enter-standout-mode=SEQ] [--exit-standout-mode=SEQ]]",
53607c478bd9Sstevel@tonic-gate 
53617c478bd9Sstevel@tonic-gate   "Define the capabilities of your terminal. Use this command to"
53627c478bd9Sstevel@tonic-gate   " define escape sequences, if it is not vt100-compatible."
53637c478bd9Sstevel@tonic-gate   " You may use \\e for ESC and ^X for a control character."
53647c478bd9Sstevel@tonic-gate   " If no option is specified, the current settings are printed."
53657c478bd9Sstevel@tonic-gate };
53667c478bd9Sstevel@tonic-gate #endif /* SUPPORT_SERIAL */
53677c478bd9Sstevel@tonic-gate 
53687c478bd9Sstevel@tonic-gate 
53697c478bd9Sstevel@tonic-gate /* testload */
53707c478bd9Sstevel@tonic-gate static int
53717c478bd9Sstevel@tonic-gate testload_func (char *arg, int flags)
53727c478bd9Sstevel@tonic-gate {
53737c478bd9Sstevel@tonic-gate   int i;
53747c478bd9Sstevel@tonic-gate 
53757c478bd9Sstevel@tonic-gate   kernel_type = KERNEL_TYPE_NONE;
53767c478bd9Sstevel@tonic-gate 
53777c478bd9Sstevel@tonic-gate   if (! grub_open (arg))
53787c478bd9Sstevel@tonic-gate     return 1;
53797c478bd9Sstevel@tonic-gate 
53807c478bd9Sstevel@tonic-gate   disk_read_hook = disk_read_print_func;
53817c478bd9Sstevel@tonic-gate 
53827c478bd9Sstevel@tonic-gate   /* Perform filesystem test on the specified file.  */
53837c478bd9Sstevel@tonic-gate   /* Read whole file first. */
53847c478bd9Sstevel@tonic-gate   grub_printf ("Whole file: ");
53857c478bd9Sstevel@tonic-gate 
53867c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x100000), -1);
53877c478bd9Sstevel@tonic-gate 
53887c478bd9Sstevel@tonic-gate   /* Now compare two sections of the file read differently.  */
53897c478bd9Sstevel@tonic-gate 
53907c478bd9Sstevel@tonic-gate   for (i = 0; i < 0x10ac0; i++)
53917c478bd9Sstevel@tonic-gate     {
53927c478bd9Sstevel@tonic-gate       *((unsigned char *) RAW_ADDR (0x200000 + i)) = 0;
53937c478bd9Sstevel@tonic-gate       *((unsigned char *) RAW_ADDR (0x300000 + i)) = 1;
53947c478bd9Sstevel@tonic-gate     }
53957c478bd9Sstevel@tonic-gate 
53967c478bd9Sstevel@tonic-gate   /* First partial read.  */
53977c478bd9Sstevel@tonic-gate   grub_printf ("\nPartial read 1: ");
53987c478bd9Sstevel@tonic-gate 
53997c478bd9Sstevel@tonic-gate   grub_seek (0);
54007c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x200000), 0x7);
54017c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x200007), 0x100);
54027c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x200107), 0x10);
54037c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x200117), 0x999);
54047c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x200ab0), 0x10);
54057c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x200ac0), 0x10000);
54067c478bd9Sstevel@tonic-gate 
54077c478bd9Sstevel@tonic-gate   /* Second partial read.  */
54087c478bd9Sstevel@tonic-gate   grub_printf ("\nPartial read 2: ");
54097c478bd9Sstevel@tonic-gate 
54107c478bd9Sstevel@tonic-gate   grub_seek (0);
54117c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x300000), 0x10000);
54127c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x310000), 0x10);
54137c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x310010), 0x7);
54147c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x310017), 0x10);
54157c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x310027), 0x999);
54167c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x3109c0), 0x100);
54177c478bd9Sstevel@tonic-gate 
54187c478bd9Sstevel@tonic-gate   grub_printf ("\nHeader1 = 0x%x, next = 0x%x, next = 0x%x, next = 0x%x\n",
54197c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x200000)),
54207c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x200004)),
54217c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x200008)),
54227c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x20000c)));
54237c478bd9Sstevel@tonic-gate 
54247c478bd9Sstevel@tonic-gate   grub_printf ("Header2 = 0x%x, next = 0x%x, next = 0x%x, next = 0x%x\n",
54257c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x300000)),
54267c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x300004)),
54277c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x300008)),
54287c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x30000c)));
54297c478bd9Sstevel@tonic-gate 
54307c478bd9Sstevel@tonic-gate   for (i = 0; i < 0x10ac0; i++)
54317c478bd9Sstevel@tonic-gate     if (*((unsigned char *) RAW_ADDR (0x200000 + i))
54327c478bd9Sstevel@tonic-gate 	!= *((unsigned char *) RAW_ADDR (0x300000 + i)))
54337c478bd9Sstevel@tonic-gate       break;
54347c478bd9Sstevel@tonic-gate 
54357c478bd9Sstevel@tonic-gate   grub_printf ("Max is 0x10ac0: i=0x%x, filepos=0x%x\n", i, filepos);
54367c478bd9Sstevel@tonic-gate   disk_read_hook = 0;
54377c478bd9Sstevel@tonic-gate   grub_close ();
54387c478bd9Sstevel@tonic-gate   return 0;
54397c478bd9Sstevel@tonic-gate }
54407c478bd9Sstevel@tonic-gate 
54417c478bd9Sstevel@tonic-gate static struct builtin builtin_testload =
54427c478bd9Sstevel@tonic-gate {
54437c478bd9Sstevel@tonic-gate   "testload",
54447c478bd9Sstevel@tonic-gate   testload_func,
54457c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
54467c478bd9Sstevel@tonic-gate   "testload FILE",
54477c478bd9Sstevel@tonic-gate   "Read the entire contents of FILE in several different ways and"
54487c478bd9Sstevel@tonic-gate   " compares them, to test the filesystem code. The output is somewhat"
54497c478bd9Sstevel@tonic-gate   " cryptic, but if no errors are reported and the final `i=X,"
54507c478bd9Sstevel@tonic-gate   " filepos=Y' reading has X and Y equal, then it is definitely"
54517c478bd9Sstevel@tonic-gate   " consistent, and very likely works correctly subject to a"
54527c478bd9Sstevel@tonic-gate   " consistent offset error. If this test succeeds, then a good next"
54537c478bd9Sstevel@tonic-gate   " step is to try loading a kernel."
54547c478bd9Sstevel@tonic-gate };
54557c478bd9Sstevel@tonic-gate 
54567c478bd9Sstevel@tonic-gate 
54577c478bd9Sstevel@tonic-gate /* testvbe MODE */
54587c478bd9Sstevel@tonic-gate static int
54597c478bd9Sstevel@tonic-gate testvbe_func (char *arg, int flags)
54607c478bd9Sstevel@tonic-gate {
54617c478bd9Sstevel@tonic-gate   int mode_number;
54627c478bd9Sstevel@tonic-gate   struct vbe_controller controller;
54637c478bd9Sstevel@tonic-gate   struct vbe_mode mode;
54647c478bd9Sstevel@tonic-gate 
54657c478bd9Sstevel@tonic-gate   if (! *arg)
54667c478bd9Sstevel@tonic-gate     {
54677c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
54687c478bd9Sstevel@tonic-gate       return 1;
54697c478bd9Sstevel@tonic-gate     }
54707c478bd9Sstevel@tonic-gate 
54717c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &mode_number))
54727c478bd9Sstevel@tonic-gate     return 1;
54737c478bd9Sstevel@tonic-gate 
54747c478bd9Sstevel@tonic-gate   /* Preset `VBE2'.  */
54757c478bd9Sstevel@tonic-gate   grub_memmove (controller.signature, "VBE2", 4);
54767c478bd9Sstevel@tonic-gate 
54777c478bd9Sstevel@tonic-gate   /* Detect VBE BIOS.  */
54787c478bd9Sstevel@tonic-gate   if (get_vbe_controller_info (&controller) != 0x004F)
54797c478bd9Sstevel@tonic-gate     {
54807c478bd9Sstevel@tonic-gate       grub_printf (" VBE BIOS is not present.\n");
54817c478bd9Sstevel@tonic-gate       return 0;
54827c478bd9Sstevel@tonic-gate     }
54837c478bd9Sstevel@tonic-gate 
54847c478bd9Sstevel@tonic-gate   if (controller.version < 0x0200)
54857c478bd9Sstevel@tonic-gate     {
54867c478bd9Sstevel@tonic-gate       grub_printf (" VBE version %d.%d is not supported.\n",
54877c478bd9Sstevel@tonic-gate 		   (int) (controller.version >> 8),
54887c478bd9Sstevel@tonic-gate 		   (int) (controller.version & 0xFF));
54897c478bd9Sstevel@tonic-gate       return 0;
54907c478bd9Sstevel@tonic-gate     }
54917c478bd9Sstevel@tonic-gate 
54927c478bd9Sstevel@tonic-gate   if (get_vbe_mode_info (mode_number, &mode) != 0x004F
54937c478bd9Sstevel@tonic-gate       || (mode.mode_attributes & 0x0091) != 0x0091)
54947c478bd9Sstevel@tonic-gate     {
54957c478bd9Sstevel@tonic-gate       grub_printf (" Mode 0x%x is not supported.\n", mode_number);
54967c478bd9Sstevel@tonic-gate       return 0;
54977c478bd9Sstevel@tonic-gate     }
54987c478bd9Sstevel@tonic-gate 
54997c478bd9Sstevel@tonic-gate   /* Now trip to the graphics mode.  */
55007c478bd9Sstevel@tonic-gate   if (set_vbe_mode (mode_number | (1 << 14)) != 0x004F)
55017c478bd9Sstevel@tonic-gate     {
55027c478bd9Sstevel@tonic-gate       grub_printf (" Switching to Mode 0x%x failed.\n", mode_number);
55037c478bd9Sstevel@tonic-gate       return 0;
55047c478bd9Sstevel@tonic-gate     }
55057c478bd9Sstevel@tonic-gate 
55067c478bd9Sstevel@tonic-gate   /* Draw something on the screen...  */
55077c478bd9Sstevel@tonic-gate   {
55087c478bd9Sstevel@tonic-gate     unsigned char *base_buf = (unsigned char *) mode.phys_base;
55097c478bd9Sstevel@tonic-gate     int scanline = controller.version >= 0x0300
55107c478bd9Sstevel@tonic-gate       ? mode.linear_bytes_per_scanline : mode.bytes_per_scanline;
55117c478bd9Sstevel@tonic-gate     /* FIXME: this assumes that any depth is a modulo of 8.  */
55127c478bd9Sstevel@tonic-gate     int bpp = mode.bits_per_pixel / 8;
55137c478bd9Sstevel@tonic-gate     int width = mode.x_resolution;
55147c478bd9Sstevel@tonic-gate     int height = mode.y_resolution;
55157c478bd9Sstevel@tonic-gate     int x, y;
55167c478bd9Sstevel@tonic-gate     unsigned color = 0;
55177c478bd9Sstevel@tonic-gate 
55187c478bd9Sstevel@tonic-gate     /* Iterate drawing on the screen, until the user hits any key.  */
55197c478bd9Sstevel@tonic-gate     while (checkkey () == -1)
55207c478bd9Sstevel@tonic-gate       {
55217c478bd9Sstevel@tonic-gate 	for (y = 0; y < height; y++)
55227c478bd9Sstevel@tonic-gate 	  {
55237c478bd9Sstevel@tonic-gate 	    unsigned char *line_buf = base_buf + scanline * y;
55247c478bd9Sstevel@tonic-gate 
55257c478bd9Sstevel@tonic-gate 	    for (x = 0; x < width; x++)
55267c478bd9Sstevel@tonic-gate 	      {
55277c478bd9Sstevel@tonic-gate 		unsigned char *buf = line_buf + bpp * x;
55287c478bd9Sstevel@tonic-gate 		int i;
55297c478bd9Sstevel@tonic-gate 
55307c478bd9Sstevel@tonic-gate 		for (i = 0; i < bpp; i++, buf++)
55317c478bd9Sstevel@tonic-gate 		  *buf = (color >> (i * 8)) & 0xff;
55327c478bd9Sstevel@tonic-gate 	      }
55337c478bd9Sstevel@tonic-gate 
55347c478bd9Sstevel@tonic-gate 	    color++;
55357c478bd9Sstevel@tonic-gate 	  }
55367c478bd9Sstevel@tonic-gate       }
55377c478bd9Sstevel@tonic-gate 
55387c478bd9Sstevel@tonic-gate     /* Discard the input.  */
55397c478bd9Sstevel@tonic-gate     getkey ();
55407c478bd9Sstevel@tonic-gate   }
55417c478bd9Sstevel@tonic-gate 
55427c478bd9Sstevel@tonic-gate   /* Back to the default text mode.  */
55437c478bd9Sstevel@tonic-gate   if (set_vbe_mode (0x03) != 0x004F)
55447c478bd9Sstevel@tonic-gate     {
55457c478bd9Sstevel@tonic-gate       /* Why?!  */
55467c478bd9Sstevel@tonic-gate       grub_reboot ();
55477c478bd9Sstevel@tonic-gate     }
55487c478bd9Sstevel@tonic-gate 
55497c478bd9Sstevel@tonic-gate   return 0;
55507c478bd9Sstevel@tonic-gate }
55517c478bd9Sstevel@tonic-gate 
55527c478bd9Sstevel@tonic-gate static struct builtin builtin_testvbe =
55537c478bd9Sstevel@tonic-gate {
55547c478bd9Sstevel@tonic-gate   "testvbe",
55557c478bd9Sstevel@tonic-gate   testvbe_func,
55567c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
55577c478bd9Sstevel@tonic-gate   "testvbe MODE",
55587c478bd9Sstevel@tonic-gate   "Test the VBE mode MODE. Hit any key to return."
55597c478bd9Sstevel@tonic-gate };
55607c478bd9Sstevel@tonic-gate 
55617c478bd9Sstevel@tonic-gate 
55627c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
55637c478bd9Sstevel@tonic-gate /* tftpserver */
55647c478bd9Sstevel@tonic-gate static int
55657c478bd9Sstevel@tonic-gate tftpserver_func (char *arg, int flags)
55667c478bd9Sstevel@tonic-gate {
55677c478bd9Sstevel@tonic-gate   if (! *arg || ! ifconfig (0, 0, 0, arg))
55687c478bd9Sstevel@tonic-gate     {
55697c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
55707c478bd9Sstevel@tonic-gate       return 1;
55717c478bd9Sstevel@tonic-gate     }
55727c478bd9Sstevel@tonic-gate 
55737c478bd9Sstevel@tonic-gate   print_network_configuration ();
55747c478bd9Sstevel@tonic-gate   return 0;
55757c478bd9Sstevel@tonic-gate }
55767c478bd9Sstevel@tonic-gate 
55777c478bd9Sstevel@tonic-gate static struct builtin builtin_tftpserver =
55787c478bd9Sstevel@tonic-gate {
55797c478bd9Sstevel@tonic-gate   "tftpserver",
55807c478bd9Sstevel@tonic-gate   tftpserver_func,
55817c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
55827c478bd9Sstevel@tonic-gate   "tftpserver IPADDR",
55837c478bd9Sstevel@tonic-gate   "Override the TFTP server address."
55847c478bd9Sstevel@tonic-gate };
55857c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
55867c478bd9Sstevel@tonic-gate 
55877c478bd9Sstevel@tonic-gate 
55887c478bd9Sstevel@tonic-gate /* timeout */
55897c478bd9Sstevel@tonic-gate static int
55907c478bd9Sstevel@tonic-gate timeout_func (char *arg, int flags)
55917c478bd9Sstevel@tonic-gate {
55927c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &grub_timeout))
55937c478bd9Sstevel@tonic-gate     return 1;
55947c478bd9Sstevel@tonic-gate 
55957c478bd9Sstevel@tonic-gate   return 0;
55967c478bd9Sstevel@tonic-gate }
55977c478bd9Sstevel@tonic-gate 
55987c478bd9Sstevel@tonic-gate static struct builtin builtin_timeout =
55997c478bd9Sstevel@tonic-gate {
56007c478bd9Sstevel@tonic-gate   "timeout",
56017c478bd9Sstevel@tonic-gate   timeout_func,
56027c478bd9Sstevel@tonic-gate   BUILTIN_MENU,
56037c478bd9Sstevel@tonic-gate #if 0
56047c478bd9Sstevel@tonic-gate   "timeout SEC",
56057c478bd9Sstevel@tonic-gate   "Set a timeout, in SEC seconds, before automatically booting the"
56067c478bd9Sstevel@tonic-gate   " default entry (normally the first entry defined)."
56077c478bd9Sstevel@tonic-gate #endif
56087c478bd9Sstevel@tonic-gate };
56097c478bd9Sstevel@tonic-gate 
56107c478bd9Sstevel@tonic-gate 
56117c478bd9Sstevel@tonic-gate /* title */
56127c478bd9Sstevel@tonic-gate static int
56137c478bd9Sstevel@tonic-gate title_func (char *arg, int flags)
56147c478bd9Sstevel@tonic-gate {
56157c478bd9Sstevel@tonic-gate   /* This function is not actually used at least currently.  */
56167c478bd9Sstevel@tonic-gate   return 0;
56177c478bd9Sstevel@tonic-gate }
56187c478bd9Sstevel@tonic-gate 
56197c478bd9Sstevel@tonic-gate static struct builtin builtin_title =
56207c478bd9Sstevel@tonic-gate {
56217c478bd9Sstevel@tonic-gate   "title",
56227c478bd9Sstevel@tonic-gate   title_func,
56237c478bd9Sstevel@tonic-gate   BUILTIN_TITLE,
56247c478bd9Sstevel@tonic-gate #if 0
56257c478bd9Sstevel@tonic-gate   "title [NAME ...]",
56267c478bd9Sstevel@tonic-gate   "Start a new boot entry, and set its name to the contents of the"
56277c478bd9Sstevel@tonic-gate   " rest of the line, starting with the first non-space character."
56287c478bd9Sstevel@tonic-gate #endif
56297c478bd9Sstevel@tonic-gate };
56307c478bd9Sstevel@tonic-gate 
56317c478bd9Sstevel@tonic-gate 
56327c478bd9Sstevel@tonic-gate /* unhide */
56337c478bd9Sstevel@tonic-gate static int
56347c478bd9Sstevel@tonic-gate unhide_func (char *arg, int flags)
56357c478bd9Sstevel@tonic-gate {
56367c478bd9Sstevel@tonic-gate   if (! set_device (arg))
56377c478bd9Sstevel@tonic-gate     return 1;
56387c478bd9Sstevel@tonic-gate 
56397c478bd9Sstevel@tonic-gate   if (! set_partition_hidden_flag (0))
56407c478bd9Sstevel@tonic-gate     return 1;
56417c478bd9Sstevel@tonic-gate 
56427c478bd9Sstevel@tonic-gate   return 0;
56437c478bd9Sstevel@tonic-gate }
56447c478bd9Sstevel@tonic-gate 
56457c478bd9Sstevel@tonic-gate static struct builtin builtin_unhide =
56467c478bd9Sstevel@tonic-gate {
56477c478bd9Sstevel@tonic-gate   "unhide",
56487c478bd9Sstevel@tonic-gate   unhide_func,
56497c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
56507c478bd9Sstevel@tonic-gate   "unhide PARTITION",
56517c478bd9Sstevel@tonic-gate   "Unhide PARTITION by clearing the \"hidden\" bit in its"
56527c478bd9Sstevel@tonic-gate   " partition type code."
56537c478bd9Sstevel@tonic-gate };
56547c478bd9Sstevel@tonic-gate 
56557c478bd9Sstevel@tonic-gate 
56567c478bd9Sstevel@tonic-gate /* uppermem */
56577c478bd9Sstevel@tonic-gate static int
56587c478bd9Sstevel@tonic-gate uppermem_func (char *arg, int flags)
56597c478bd9Sstevel@tonic-gate {
56607c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, (int *) &mbi.mem_upper))
56617c478bd9Sstevel@tonic-gate     return 1;
56627c478bd9Sstevel@tonic-gate 
56637c478bd9Sstevel@tonic-gate   mbi.flags &= ~MB_INFO_MEM_MAP;
56647c478bd9Sstevel@tonic-gate   return 0;
56657c478bd9Sstevel@tonic-gate }
56667c478bd9Sstevel@tonic-gate 
56677c478bd9Sstevel@tonic-gate static struct builtin builtin_uppermem =
56687c478bd9Sstevel@tonic-gate {
56697c478bd9Sstevel@tonic-gate   "uppermem",
56707c478bd9Sstevel@tonic-gate   uppermem_func,
56717c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
56727c478bd9Sstevel@tonic-gate   "uppermem KBYTES",
56737c478bd9Sstevel@tonic-gate   "Force GRUB to assume that only KBYTES kilobytes of upper memory are"
56747c478bd9Sstevel@tonic-gate   " installed.  Any system address range maps are discarded."
56757c478bd9Sstevel@tonic-gate };
56767c478bd9Sstevel@tonic-gate 
56777c478bd9Sstevel@tonic-gate 
56787c478bd9Sstevel@tonic-gate /* vbeprobe */
56797c478bd9Sstevel@tonic-gate static int
56807c478bd9Sstevel@tonic-gate vbeprobe_func (char *arg, int flags)
56817c478bd9Sstevel@tonic-gate {
56827c478bd9Sstevel@tonic-gate   struct vbe_controller controller;
56837c478bd9Sstevel@tonic-gate   unsigned short *mode_list;
56847c478bd9Sstevel@tonic-gate   int mode_number = -1;
56857c478bd9Sstevel@tonic-gate 
56867c478bd9Sstevel@tonic-gate   auto unsigned long vbe_far_ptr_to_linear (unsigned long);
56877c478bd9Sstevel@tonic-gate 
56887c478bd9Sstevel@tonic-gate   unsigned long vbe_far_ptr_to_linear (unsigned long ptr)
56897c478bd9Sstevel@tonic-gate     {
56907c478bd9Sstevel@tonic-gate       unsigned short seg = (ptr >> 16);
56917c478bd9Sstevel@tonic-gate       unsigned short off = (ptr & 0xFFFF);
56927c478bd9Sstevel@tonic-gate 
56937c478bd9Sstevel@tonic-gate       return (seg << 4) + off;
56947c478bd9Sstevel@tonic-gate     }
56957c478bd9Sstevel@tonic-gate 
56967c478bd9Sstevel@tonic-gate   if (*arg)
56977c478bd9Sstevel@tonic-gate     {
56987c478bd9Sstevel@tonic-gate       if (! safe_parse_maxint (&arg, &mode_number))
56997c478bd9Sstevel@tonic-gate 	return 1;
57007c478bd9Sstevel@tonic-gate     }
57017c478bd9Sstevel@tonic-gate 
57027c478bd9Sstevel@tonic-gate   /* Set the signature to `VBE2', to obtain VBE 3.0 information.  */
57037c478bd9Sstevel@tonic-gate   grub_memmove (controller.signature, "VBE2", 4);
57047c478bd9Sstevel@tonic-gate 
57057c478bd9Sstevel@tonic-gate   if (get_vbe_controller_info (&controller) != 0x004F)
57067c478bd9Sstevel@tonic-gate     {
57077c478bd9Sstevel@tonic-gate       grub_printf (" VBE BIOS is not present.\n");
57087c478bd9Sstevel@tonic-gate       return 0;
57097c478bd9Sstevel@tonic-gate     }
57107c478bd9Sstevel@tonic-gate 
57117c478bd9Sstevel@tonic-gate   /* Check the version.  */
57127c478bd9Sstevel@tonic-gate   if (controller.version < 0x0200)
57137c478bd9Sstevel@tonic-gate     {
57147c478bd9Sstevel@tonic-gate       grub_printf (" VBE version %d.%d is not supported.\n",
57157c478bd9Sstevel@tonic-gate 		   (int) (controller.version >> 8),
57167c478bd9Sstevel@tonic-gate 		   (int) (controller.version & 0xFF));
57177c478bd9Sstevel@tonic-gate       return 0;
57187c478bd9Sstevel@tonic-gate     }
57197c478bd9Sstevel@tonic-gate 
57207c478bd9Sstevel@tonic-gate   /* Print some information.  */
57217c478bd9Sstevel@tonic-gate   grub_printf (" VBE version %d.%d\n",
57227c478bd9Sstevel@tonic-gate 	       (int) (controller.version >> 8),
57237c478bd9Sstevel@tonic-gate 	       (int) (controller.version & 0xFF));
57247c478bd9Sstevel@tonic-gate 
57257c478bd9Sstevel@tonic-gate   /* Iterate probing modes.  */
57267c478bd9Sstevel@tonic-gate   for (mode_list
57277c478bd9Sstevel@tonic-gate 	 = (unsigned short *) vbe_far_ptr_to_linear (controller.video_mode);
57287c478bd9Sstevel@tonic-gate        *mode_list != 0xFFFF;
57297c478bd9Sstevel@tonic-gate        mode_list++)
57307c478bd9Sstevel@tonic-gate     {
57317c478bd9Sstevel@tonic-gate       struct vbe_mode mode;
57327c478bd9Sstevel@tonic-gate 
57337c478bd9Sstevel@tonic-gate       if (get_vbe_mode_info (*mode_list, &mode) != 0x004F)
57347c478bd9Sstevel@tonic-gate 	continue;
57357c478bd9Sstevel@tonic-gate 
57367c478bd9Sstevel@tonic-gate       /* Skip this, if this is not supported or linear frame buffer
57377c478bd9Sstevel@tonic-gate 	 mode is not support.  */
57387c478bd9Sstevel@tonic-gate       if ((mode.mode_attributes & 0x0081) != 0x0081)
57397c478bd9Sstevel@tonic-gate 	continue;
57407c478bd9Sstevel@tonic-gate 
57417c478bd9Sstevel@tonic-gate       if (mode_number == -1 || mode_number == *mode_list)
57427c478bd9Sstevel@tonic-gate 	{
57437c478bd9Sstevel@tonic-gate 	  char *model;
57447c478bd9Sstevel@tonic-gate 	  switch (mode.memory_model)
57457c478bd9Sstevel@tonic-gate 	    {
57467c478bd9Sstevel@tonic-gate 	    case 0x00: model = "Text"; break;
57477c478bd9Sstevel@tonic-gate 	    case 0x01: model = "CGA graphics"; break;
57487c478bd9Sstevel@tonic-gate 	    case 0x02: model = "Hercules graphics"; break;
57497c478bd9Sstevel@tonic-gate 	    case 0x03: model = "Planar"; break;
57507c478bd9Sstevel@tonic-gate 	    case 0x04: model = "Packed pixel"; break;
57517c478bd9Sstevel@tonic-gate 	    case 0x05: model = "Non-chain 4, 256 color"; break;
57527c478bd9Sstevel@tonic-gate 	    case 0x06: model = "Direct Color"; break;
57537c478bd9Sstevel@tonic-gate 	    case 0x07: model = "YUV"; break;
57547c478bd9Sstevel@tonic-gate 	    default: model = "Unknown"; break;
57557c478bd9Sstevel@tonic-gate 	    }
57567c478bd9Sstevel@tonic-gate 
57577c478bd9Sstevel@tonic-gate 	  grub_printf ("  0x%x: %s, %ux%ux%u\n",
57587c478bd9Sstevel@tonic-gate 		       (unsigned) *mode_list,
57597c478bd9Sstevel@tonic-gate 		       model,
57607c478bd9Sstevel@tonic-gate 		       (unsigned) mode.x_resolution,
57617c478bd9Sstevel@tonic-gate 		       (unsigned) mode.y_resolution,
57627c478bd9Sstevel@tonic-gate 		       (unsigned) mode.bits_per_pixel);
57637c478bd9Sstevel@tonic-gate 
57647c478bd9Sstevel@tonic-gate 	  if (mode_number != -1)
57657c478bd9Sstevel@tonic-gate 	    break;
57667c478bd9Sstevel@tonic-gate 	}
57677c478bd9Sstevel@tonic-gate     }
57687c478bd9Sstevel@tonic-gate 
57697c478bd9Sstevel@tonic-gate   if (mode_number != -1 && mode_number != *mode_list)
57707c478bd9Sstevel@tonic-gate     grub_printf ("  Mode 0x%x is not found or supported.\n", mode_number);
57717c478bd9Sstevel@tonic-gate 
57727c478bd9Sstevel@tonic-gate   return 0;
57737c478bd9Sstevel@tonic-gate }
57747c478bd9Sstevel@tonic-gate 
57757c478bd9Sstevel@tonic-gate static struct builtin builtin_vbeprobe =
57767c478bd9Sstevel@tonic-gate {
57777c478bd9Sstevel@tonic-gate   "vbeprobe",
57787c478bd9Sstevel@tonic-gate   vbeprobe_func,
57797c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
57807c478bd9Sstevel@tonic-gate   "vbeprobe [MODE]",
57817c478bd9Sstevel@tonic-gate   "Probe VBE information. If the mode number MODE is specified, show only"
57827c478bd9Sstevel@tonic-gate   " the information about only the mode."
57837c478bd9Sstevel@tonic-gate };
57847c478bd9Sstevel@tonic-gate 
57857c478bd9Sstevel@tonic-gate 
57867c478bd9Sstevel@tonic-gate /* The table of builtin commands. Sorted in dictionary order.  */
57877c478bd9Sstevel@tonic-gate struct builtin *builtin_table[] =
57887c478bd9Sstevel@tonic-gate {
57897c478bd9Sstevel@tonic-gate #ifdef SUPPORT_GRAPHICS
57907c478bd9Sstevel@tonic-gate   &builtin_background,
57917c478bd9Sstevel@tonic-gate #endif
57927c478bd9Sstevel@tonic-gate   &builtin_blocklist,
57937c478bd9Sstevel@tonic-gate   &builtin_boot,
5794b1b8ab34Slling   &builtin_bootfs,
57957c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
57967c478bd9Sstevel@tonic-gate   &builtin_bootp,
57977c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
57987c478bd9Sstevel@tonic-gate   &builtin_cat,
57997c478bd9Sstevel@tonic-gate   &builtin_chainloader,
58007c478bd9Sstevel@tonic-gate   &builtin_clear,
58017c478bd9Sstevel@tonic-gate   &builtin_cmp,
58027c478bd9Sstevel@tonic-gate   &builtin_color,
58037c478bd9Sstevel@tonic-gate   &builtin_configfile,
58047c478bd9Sstevel@tonic-gate   &builtin_debug,
58057c478bd9Sstevel@tonic-gate   &builtin_default,
58067c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
58077c478bd9Sstevel@tonic-gate   &builtin_device,
58087c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
58097c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
58107c478bd9Sstevel@tonic-gate   &builtin_dhcp,
58117c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
58127c478bd9Sstevel@tonic-gate   &builtin_displayapm,
58137c478bd9Sstevel@tonic-gate   &builtin_displaymem,
58147c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
58157c478bd9Sstevel@tonic-gate   &builtin_dump,
58167c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
58177c478bd9Sstevel@tonic-gate   &builtin_embed,
58187c478bd9Sstevel@tonic-gate   &builtin_fallback,
58197c478bd9Sstevel@tonic-gate   &builtin_find,
5820eb2bd662Svikram   &builtin_findroot,
58217c478bd9Sstevel@tonic-gate #ifdef SUPPORT_GRAPHICS
58227c478bd9Sstevel@tonic-gate   &builtin_foreground,
58237c478bd9Sstevel@tonic-gate #endif
58247c478bd9Sstevel@tonic-gate   &builtin_fstest,
58257c478bd9Sstevel@tonic-gate   &builtin_geometry,
58267c478bd9Sstevel@tonic-gate   &builtin_halt,
58277c478bd9Sstevel@tonic-gate   &builtin_help,
58287c478bd9Sstevel@tonic-gate   &builtin_hiddenmenu,
58297c478bd9Sstevel@tonic-gate   &builtin_hide,
58307c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
58317c478bd9Sstevel@tonic-gate   &builtin_ifconfig,
58327c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
58337c478bd9Sstevel@tonic-gate   &builtin_impsprobe,
58347c478bd9Sstevel@tonic-gate   &builtin_initrd,
58357c478bd9Sstevel@tonic-gate   &builtin_install,
58367c478bd9Sstevel@tonic-gate   &builtin_ioprobe,
58377c478bd9Sstevel@tonic-gate   &builtin_kernel,
5838ae115bc7Smrj   &builtin_kernel_dollar,
58397c478bd9Sstevel@tonic-gate   &builtin_lock,
58407c478bd9Sstevel@tonic-gate   &builtin_makeactive,
58417c478bd9Sstevel@tonic-gate   &builtin_map,
58427c478bd9Sstevel@tonic-gate #ifdef USE_MD5_PASSWORDS
58437c478bd9Sstevel@tonic-gate   &builtin_md5crypt,
58447c478bd9Sstevel@tonic-gate #endif /* USE_MD5_PASSWORDS */
5845342440ecSPrasad Singamsetty   &builtin_min_mem64,
58467c478bd9Sstevel@tonic-gate   &builtin_module,
5847ae115bc7Smrj   &builtin_module_dollar,
58487c478bd9Sstevel@tonic-gate   &builtin_modulenounzip,
58497c478bd9Sstevel@tonic-gate   &builtin_pager,
58507c478bd9Sstevel@tonic-gate   &builtin_partnew,
58517c478bd9Sstevel@tonic-gate   &builtin_parttype,
58527c478bd9Sstevel@tonic-gate   &builtin_password,
58537c478bd9Sstevel@tonic-gate   &builtin_pause,
58547c478bd9Sstevel@tonic-gate #if defined(RPC_DEBUG) && defined(SUPPORT_NETBOOT)
58557c478bd9Sstevel@tonic-gate   &builtin_portmap,
58567c478bd9Sstevel@tonic-gate #endif /* RPC_DEBUG && SUPPORT_NETBOOT */
58577c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
58587c478bd9Sstevel@tonic-gate   &builtin_quit,
58597c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
58607c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
58617c478bd9Sstevel@tonic-gate   &builtin_rarp,
58627c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
58637c478bd9Sstevel@tonic-gate   &builtin_read,
58647c478bd9Sstevel@tonic-gate   &builtin_reboot,
58657c478bd9Sstevel@tonic-gate   &builtin_root,
58667c478bd9Sstevel@tonic-gate   &builtin_rootnoverify,
58677c478bd9Sstevel@tonic-gate   &builtin_savedefault,
58687c478bd9Sstevel@tonic-gate #ifdef SUPPORT_SERIAL
58697c478bd9Sstevel@tonic-gate   &builtin_serial,
58707c478bd9Sstevel@tonic-gate #endif /* SUPPORT_SERIAL */
58717c478bd9Sstevel@tonic-gate   &builtin_setkey,
58727c478bd9Sstevel@tonic-gate   &builtin_setup,
58737c478bd9Sstevel@tonic-gate #ifdef SUPPORT_GRAPHICS
58747c478bd9Sstevel@tonic-gate   &builtin_splashimage,
58757c478bd9Sstevel@tonic-gate #endif /* SUPPORT_GRAPHICS */
58767c478bd9Sstevel@tonic-gate #if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES) || defined(SUPPORT_GRAPHICS)
58777c478bd9Sstevel@tonic-gate   &builtin_terminal,
58787c478bd9Sstevel@tonic-gate #endif /* SUPPORT_SERIAL || SUPPORT_HERCULES || SUPPORT_GRAPHICS */
58797c478bd9Sstevel@tonic-gate #ifdef SUPPORT_SERIAL
58807c478bd9Sstevel@tonic-gate   &builtin_terminfo,
58817c478bd9Sstevel@tonic-gate #endif /* SUPPORT_SERIAL */
58827c478bd9Sstevel@tonic-gate   &builtin_testload,
58837c478bd9Sstevel@tonic-gate   &builtin_testvbe,
58847c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
58857c478bd9Sstevel@tonic-gate   &builtin_tftpserver,
58867c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
58877c478bd9Sstevel@tonic-gate   &builtin_timeout,
58887c478bd9Sstevel@tonic-gate   &builtin_title,
58897c478bd9Sstevel@tonic-gate   &builtin_unhide,
58907c478bd9Sstevel@tonic-gate   &builtin_uppermem,
58917c478bd9Sstevel@tonic-gate   &builtin_vbeprobe,
58921fac5a60Ssetje   &builtin_verbose,
58937c478bd9Sstevel@tonic-gate   0
58947c478bd9Sstevel@tonic-gate };
5895