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