1 /* asmstub.c - a version of shared_src/asm.S that works under Unix */
   2 /*
   3  *  GRUB  --  GRand Unified Bootloader
   4  *  Copyright (C) 1999,2000,2001,2002,2004  Free Software Foundation, Inc.
   5  *
   6  *  This program is free software; you can redistribute it and/or modify
   7  *  it under the terms of the GNU General Public License as published by
   8  *  the Free Software Foundation; either version 2 of the License, or
   9  *  (at your option) any later version.
  10  *
  11  *  This program is distributed in the hope that it will be useful,
  12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14  *  GNU General Public License for more details.
  15  *
  16  *  You should have received a copy of the GNU General Public License
  17  *  along with this program; if not, write to the Free Software
  18  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19  */
  20 
  21 /* Try to use glibc's transparant LFS support. */
  22 #define _LARGEFILE_SOURCE       1
  23 /* lseek becomes synonymous with lseek64.  */
  24 #define _FILE_OFFSET_BITS       64
  25 
  26 /* Simulator entry point. */
  27 int grub_stage2 (void);
  28 
  29 #include <stdlib.h>
  30 #include <string.h>
  31 #include <ctype.h>
  32 #include <assert.h>
  33 #include <stdio.h>
  34 #include <sys/types.h>
  35 #include <sys/stat.h>
  36 #include <fcntl.h>
  37 #include <time.h>
  38 #include <errno.h>
  39 #include <string.h>
  40 #include <unistd.h>
  41 #include <setjmp.h>
  42 #include <sys/time.h>
  43 #include <termios.h>
  44 #include <signal.h>
  45 
  46 #ifdef __linux__
  47 # include <sys/ioctl.h>           /* ioctl */
  48 # if !defined(__GLIBC__) || \
  49         ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
  50 /* Maybe libc doesn't have large file support.  */
  51 #  include <linux/unistd.h>       /* _llseek */
  52 # endif /* (GLIBC < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR < 1)) */
  53 # ifndef BLKFLSBUF
  54 #  define BLKFLSBUF     _IO (0x12,97)   /* flush buffer cache */
  55 # endif /* ! BLKFLSBUF */
  56 #endif /* __linux__ */
  57 
  58 /* We want to prevent any circularararity in our stubs, as well as
  59    libc name clashes. */
  60 #define WITHOUT_LIBC_STUBS 1
  61 #include <shared.h>
  62 #include <device.h>
  63 #include <serial.h>
  64 #include <term.h>
  65 
  66 /* Simulated memory sizes. */
  67 #define EXTENDED_MEMSIZE (64 * 1024 * 1024)     /* 64MB */
  68 #define CONVENTIONAL_MEMSIZE (640 * 1024)       /* 640kB */
  69 
  70 unsigned long install_partition = 0x20000;
  71 unsigned long boot_drive = 0;
  72 int saved_entryno = 0;
  73 char version_string[] = VERSION;
  74 char config_file[128] = "/boot/grub/menu.lst"; /* FIXME: arbitrary */
  75 unsigned long linux_text_len = 0;
  76 char *linux_data_tmp_addr = 0;
  77 char *linux_data_real_addr = 0;
  78 unsigned short io_map[IO_MAP_SIZE];
  79 struct apm_info apm_bios_info;
  80 
  81 /* Emulation requirements. */
  82 char *grub_scratch_mem = 0;
  83 
  84 struct geometry *disks = 0;
  85 
  86 /* The map between BIOS drives and UNIX device file names.  */
  87 char **device_map = 0;
  88 
  89 /* The jump buffer for exiting correctly.  */
  90 static jmp_buf env_for_exit;
  91 
  92 /* The current color for console.  */
  93 int console_current_color = A_NORMAL;
  94 
  95 /* The file descriptor for a serial device.  */
  96 static int serial_fd = -1;
  97 
  98 /* The file name of a serial device.  */
  99 static char *serial_device = 0;
 100 
 101 #ifdef SIMULATE_SLOWNESS_OF_SERIAL
 102 /* The speed of a serial device.  */
 103 static unsigned int serial_speed;
 104 #endif /* SIMULATE_SLOWNESS_OF_SERIAL */
 105 
 106 /* The main entry point into this mess. */
 107 int
 108 grub_stage2 (void)
 109 {
 110   /* These need to be static, because they survive our stack transitions. */
 111   static int status = 0;
 112   static char *realstack;
 113   char *scratch, *simstack;
 114   int i;
 115 
 116   auto void doit (void);
 117 
 118   /* We need a nested function so that we get a clean stack frame,
 119      regardless of how the code is optimized. */
 120   void doit ()
 121     {
 122       /* Make sure our stack lives in the simulated memory area. */
 123       asm volatile ("movl %%esp, %0\n\tmovl %1, %%esp\n"
 124                     : "=&r" (realstack) : "r" (simstack));
 125 
 126       /* Do a setjmp here for the stop command.  */
 127       if (! setjmp (env_for_exit))
 128         {
 129           /* Actually enter the generic stage2 code.  */
 130           status = 0;
 131           init_bios_info ();
 132         }
 133       else
 134         {
 135           /* If ERRNUM is non-zero, then set STATUS to non-zero.  */
 136           if (errnum)
 137             status = 1;
 138         }
 139 
 140       /* Replace our stack before we use any local variables. */
 141       asm volatile ("movl %0, %%esp\n" : : "r" (realstack));
 142     }
 143 
 144   assert (grub_scratch_mem == 0);
 145   scratch = malloc (0x100000 + EXTENDED_MEMSIZE + 15);
 146   assert (scratch);
 147   grub_scratch_mem = (char *) ((((int) scratch) >> 4) << 4);
 148 
 149   /* FIXME: simulate the memory holes using mprot, if available. */
 150 
 151   assert (disks == 0);
 152   disks = malloc (NUM_DISKS * sizeof (*disks));
 153   assert (disks);
 154   /* Initialize DISKS.  */
 155   for (i = 0; i < NUM_DISKS; i++)
 156     disks[i].flags = -1;
 157 
 158   if (! init_device_map (&device_map, device_map_file, floppy_disks))
 159     return 1;
 160   
 161   /* Check some invariants. */
 162   assert ((SCRATCHSEG << 4) == SCRATCHADDR);
 163   assert ((BUFFERSEG << 4) == BUFFERADDR);
 164   assert (BUFFERADDR + BUFFERLEN == SCRATCHADDR);
 165   assert (FSYS_BUF % 16 == 0);
 166   assert (FSYS_BUF + FSYS_BUFLEN == BUFFERADDR);
 167 
 168 #ifdef HAVE_LIBCURSES
 169   /* Get into char-at-a-time mode. */
 170   if (use_curses)
 171     {
 172       initscr ();
 173       cbreak ();
 174       noecho ();
 175       nonl ();
 176       scrollok (stdscr, TRUE);
 177       keypad (stdscr, TRUE);
 178       wtimeout (stdscr, 100);
 179       signal (SIGWINCH, SIG_IGN);
 180     }
 181 #endif
 182 
 183   /* Make sure that actual writing is done.  */
 184   sync ();
 185 
 186   /* Set our stack, and go for it. */
 187   simstack = (char *) PROTSTACKINIT;
 188   doit ();
 189 
 190   /* I don't know if this is necessary really.  */
 191   sync ();
 192 
 193 #ifdef HAVE_LIBCURSES
 194   if (use_curses)
 195     endwin ();
 196 #endif
 197 
 198   /* Close off the file descriptors we used. */
 199   for (i = 0; i < NUM_DISKS; i ++)
 200     if (disks[i].flags != -1)
 201       {
 202 #ifdef __linux__
 203         /* In Linux, invalidate the buffer cache. In other OSes, reboot
 204            is one of the solutions...  */
 205         ioctl (disks[i].flags, BLKFLSBUF, 0);
 206 #elif defined(__sun)
 207         /* FIXME */
 208 #else
 209 # warning "In your operating system, the buffer cache will not be flushed."
 210 #endif
 211         close (disks[i].flags);
 212       }
 213 
 214   if (serial_fd >= 0)
 215     close (serial_fd);
 216   
 217   /* Release memory. */
 218   restore_device_map (device_map);
 219   device_map = 0;
 220   free (disks);
 221   disks = 0;
 222   free (scratch);
 223   grub_scratch_mem = 0;
 224 
 225   if (serial_device)
 226     free (serial_device);
 227   serial_device = 0;
 228   
 229   /* Ahh... at last we're ready to return to caller. */
 230   return status;
 231 }
 232 
 233 /* Assign DRIVE to a device name DEVICE.  */
 234 void
 235 assign_device_name (int drive, const char *device)
 236 {
 237   /* If DRIVE is already assigned, free it.  */
 238   if (device_map[drive])
 239     free (device_map[drive]);
 240 
 241   /* If the old one is already opened, close it.  */
 242   if (disks[drive].flags != -1)
 243     {
 244       close (disks[drive].flags);
 245       disks[drive].flags = -1;
 246     }
 247 
 248   /* Assign DRIVE to DEVICE.  */
 249   if (! device)
 250     device_map[drive] = 0;
 251   else
 252     device_map[drive] = strdup (device);
 253 }
 254 
 255 void
 256 stop (void)
 257 {
 258 #ifdef HAVE_LIBCURSES
 259   if (use_curses)
 260     endwin ();
 261 #endif
 262 
 263   /* Jump to doit.  */
 264   longjmp (env_for_exit, 1);
 265 }
 266 
 267 void
 268 grub_reboot (void)
 269 {
 270   stop ();
 271 }
 272 
 273 void
 274 grub_halt (int no_apm)
 275 {
 276   stop ();
 277 }
 278 
 279 /* calls for direct boot-loader chaining */
 280 void
 281 chain_stage1 (unsigned long segment, unsigned long offset,
 282               unsigned long part_table_addr)
 283 {
 284   stop ();
 285 }
 286 
 287 
 288 void
 289 chain_stage2 (unsigned long segment, unsigned long offset, int second_sector)
 290 {
 291   stop ();
 292 }
 293 
 294 
 295 /* do some funky stuff, then boot linux */
 296 void
 297 linux_boot (void)
 298 {
 299   stop ();
 300 }
 301 
 302 
 303 /* For bzImage kernels. */
 304 void
 305 big_linux_boot (void)
 306 {
 307   stop ();
 308 }
 309 
 310 
 311 /* booting a multiboot executable */
 312 void
 313 multi_boot (int start, int mb_info)
 314 {
 315   stop ();
 316 }
 317 
 318 /* sets it to linear or wired A20 operation */
 319 void
 320 gateA20 (int linear)
 321 {
 322   /* Nothing to do in the simulator. */
 323 }
 324 
 325 /* Set up the int15 handler.  */
 326 void
 327 set_int15_handler (void)
 328 {
 329   /* Nothing to do in the simulator.  */
 330 }
 331 
 332 /* Restore the original int15 handler.  */
 333 void
 334 unset_int15_handler (void)
 335 {
 336   /* Nothing to do in the simulator.  */
 337 }
 338 
 339 /* The key map.  */
 340 unsigned short bios_key_map[KEY_MAP_SIZE + 1];
 341 unsigned short ascii_key_map[KEY_MAP_SIZE + 1];
 342 
 343 /* Copy MAP to the drive map and set up the int13 handler.  */
 344 void
 345 set_int13_handler (unsigned short *map)
 346 {
 347   /* Nothing to do in the simulator.  */
 348 }
 349 
 350 int
 351 get_code_end (void)
 352 {
 353   /* Just return a little area for simulation. */
 354   return BOOTSEC_LOCATION + (60 * 1024);
 355 }
 356 
 357 
 358 /* memory probe routines */
 359 int
 360 get_memsize (int type)
 361 {
 362   if (! type)
 363     return CONVENTIONAL_MEMSIZE >> 10;
 364   else
 365     return EXTENDED_MEMSIZE >> 10;
 366 }
 367 
 368 
 369 /* get_eisamemsize() :  return packed EISA memory map, lower 16 bits is
 370  *              memory between 1M and 16M in 1K parts, upper 16 bits is
 371  *              memory above 16M in 64K parts.  If error, return -1.
 372  */
 373 int
 374 get_eisamemsize (void)
 375 {
 376   return (EXTENDED_MEMSIZE >> 10);
 377 }
 378 
 379 
 380 #define MMAR_DESC_TYPE_AVAILABLE 1 /* available to OS */
 381 #define MMAR_DESC_TYPE_RESERVED 2 /* not available */
 382 #define MMAR_DESC_TYPE_ACPI_RECLAIM 3 /* usable by OS after reading ACPI */
 383 #define MMAR_DESC_TYPE_ACPI_NVS 4 /* required to save between NVS sessions */
 384 
 385 #define MMAR_DESC_LENGTH        20
 386 
 387 /* Fetch the next entry in the memory map and return the continuation
 388    value.  DESC is a pointer to the descriptor buffer, and CONT is the
 389    previous continuation value (0 to get the first entry in the
 390    map).  */
 391 int
 392 get_mmap_entry (struct mmar_desc *desc, int cont)
 393 {
 394   /* Record the memory map statically.  */
 395   static struct mmar_desc desc_table[] =
 396   {
 397     /* The conventional memory.  */
 398     {
 399       MMAR_DESC_LENGTH,
 400       0,
 401       CONVENTIONAL_MEMSIZE,
 402       MMAR_DESC_TYPE_AVAILABLE
 403     },
 404     /* BIOS RAM and ROM (such as video memory).  */
 405     {
 406       MMAR_DESC_LENGTH,
 407       CONVENTIONAL_MEMSIZE,
 408       0x100000 - CONVENTIONAL_MEMSIZE,
 409       MMAR_DESC_TYPE_RESERVED
 410     },
 411     /* The extended memory.  */
 412     {
 413       MMAR_DESC_LENGTH,
 414       0x100000,
 415       EXTENDED_MEMSIZE,
 416       MMAR_DESC_TYPE_AVAILABLE
 417     }
 418   };
 419   
 420   int num = sizeof (desc_table) / sizeof (*desc_table);
 421 
 422   if (cont < 0 || cont >= num)
 423     {
 424       /* Should not happen.  */
 425       desc->desc_len = 0;
 426     }
 427   else
 428     {
 429       /* Copy the entry.  */
 430       *desc = desc_table[cont++];
 431 
 432       /* If the next entry exists, return the index.  */
 433       if (cont < num)
 434         return cont;
 435     }
 436   
 437   return 0;
 438 }
 439 
 440 /* Track the int13 handler.  */
 441 void
 442 track_int13 (int drive)
 443 {
 444   /* Nothing to do in the simulator.  */
 445 }
 446 
 447 /* Get the ROM configuration table.  */
 448 unsigned long
 449 get_rom_config_table (void)
 450 {
 451   return 0;
 452 }
 453 
 454 /* Get APM BIOS information.  */
 455 void
 456 get_apm_info (void)
 457 {
 458   /* Nothing to do in the simulator.  */
 459 }
 460 
 461 /* Get VBE controller information.  */
 462 int
 463 get_vbe_controller_info (struct vbe_controller *controller)
 464 {
 465   /* Always fails.  */
 466   return 0;
 467 }
 468 
 469 /* Get VBE mode information.  */
 470 int
 471 get_vbe_mode_info (int mode_number, struct vbe_mode *mode)
 472 {
 473   /* Always fails.  */
 474   return 0;
 475 }
 476 
 477 /* Set VBE mode.  */
 478 int
 479 set_vbe_mode (int mode_number)
 480 {
 481   /* Always fails.  */
 482   return 0;
 483 }
 484 
 485 /* low-level timing info */
 486 int
 487 getrtsecs (void)
 488 {
 489   /* FIXME: exact value is not important, so just return time_t for now. */
 490   return time (0);
 491 }
 492 
 493 int
 494 currticks (void)
 495 {
 496   struct timeval tv;
 497   long csecs;
 498   int ticks_per_csec, ticks_per_usec;
 499 
 500   /* Note: 18.2 ticks/sec.  */
 501 
 502   /* Get current time.  */
 503   gettimeofday (&tv, 0);
 504 
 505   /* Compute centiseconds.  */
 506   csecs = tv.tv_sec / 10;
 507 
 508   /* Ticks per centisecond.  */
 509   ticks_per_csec = csecs * 182;
 510 
 511   /* Ticks per microsecond.  */
 512   ticks_per_usec = (((tv.tv_sec - csecs * 10) * 1000000 + tv.tv_usec)
 513                     * 182 / 10000000);
 514 
 515   /* Sum them.  */
 516   return ticks_per_csec + ticks_per_usec;
 517 }
 518 
 519 /* displays an ASCII character.  IBM displays will translate some
 520    characters to special graphical ones */
 521 void
 522 console_putchar (int c)
 523 {
 524   /* Curses doesn't have VGA fonts.  */
 525   switch (c)
 526     {
 527     case DISP_UL:
 528       c = ACS_ULCORNER;
 529       break;
 530     case DISP_UR:
 531       c = ACS_URCORNER;
 532       break;
 533     case DISP_LL:
 534       c = ACS_LLCORNER;
 535       break;
 536     case DISP_LR:
 537       c = ACS_LRCORNER;
 538       break;
 539     case DISP_HORIZ:
 540       c = ACS_HLINE;
 541       break;
 542     case DISP_VERT:
 543       c = ACS_VLINE;
 544       break;
 545     case DISP_LEFT:
 546       c = ACS_LARROW;
 547       break;
 548     case DISP_RIGHT:
 549       c = ACS_RARROW;
 550       break;
 551     case DISP_UP:
 552       c = ACS_UARROW;
 553       break;
 554     case DISP_DOWN:
 555       c = ACS_DARROW;
 556       break;
 557     default:
 558       break;
 559     }
 560 
 561 #ifdef HAVE_LIBCURSES
 562   if (use_curses)
 563     {
 564       /* In ncurses, a newline is treated badly, so we emulate it in our
 565          own way.  */
 566       if (c == '\n')
 567         {
 568           int x, y;
 569 
 570           getyx (stdscr, y, x);
 571           if (y + 1 == LINES)
 572             scroll (stdscr);
 573           else
 574             move (y + 1, x);
 575         }
 576       else if (isprint (c))
 577         {
 578           int x, y;
 579 
 580           getyx (stdscr, y, x);
 581           if (x + 1 == COLS)
 582             {
 583               console_putchar ('\r');
 584               console_putchar ('\n');
 585             }
 586           addch (c | console_current_color);
 587         }
 588       else
 589         {
 590           addch (c);
 591         }
 592       
 593 #ifdef REFRESH_IMMEDIATELY
 594       refresh ();
 595 #endif
 596     }
 597   else
 598 #endif
 599     {
 600       /* CR is not used in Unix.  */
 601       if (c != '\r')
 602         putchar (c);
 603     }
 604 }
 605 
 606 /* The store for ungetch simulation. This is necessary, because
 607    ncurses-1.9.9g is still used in the world and its ungetch is
 608    completely broken.  */
 609 #ifdef HAVE_LIBCURSES
 610 static int save_char = ERR;
 611 #endif
 612 
 613 static int
 614 console_translate_key (int c)
 615 {
 616   switch (c)
 617     {
 618     case KEY_LEFT:
 619       return 2;
 620     case KEY_RIGHT:
 621       return 6;
 622     case KEY_UP:
 623       return 16;
 624     case KEY_DOWN:
 625       return 14;
 626     case KEY_DC:
 627       return 4;
 628     case KEY_BACKSPACE:
 629       return 8;
 630     case KEY_HOME:
 631       return 1;
 632     case KEY_END:
 633       return 5;
 634     case KEY_PPAGE:
 635       return 7;
 636     case KEY_NPAGE:
 637       return 3;
 638     default:
 639       break;
 640     }
 641 
 642   return c;
 643 }
 644 
 645 /* like 'getkey', but doesn't wait, returns -1 if nothing available */
 646 int
 647 console_checkkey (void)
 648 {
 649 #ifdef HAVE_LIBCURSES
 650   if (use_curses)
 651     {
 652       int c;
 653 
 654       /* Check for SAVE_CHAR. This should not be true, because this
 655          means checkkey is called twice continuously.  */
 656       if (save_char != ERR)
 657         return save_char;
 658 
 659       c = getch ();
 660       /* If C is not ERR, then put it back in the input queue.  */
 661       if (c != ERR)
 662         save_char = c;
 663       return console_translate_key (c);
 664     }
 665 #endif
 666 
 667   /* Just pretend they hit the space bar, then read the real key when
 668      they call getkey. */
 669   return ' ';
 670 }
 671 
 672 /* returns packed BIOS/ASCII code */
 673 int
 674 console_getkey (void)
 675 {
 676   int c;
 677 
 678 #ifdef HAVE_LIBCURSES
 679   if (use_curses)
 680     {
 681       /* If checkkey has already got a character, then return it.  */
 682       if (save_char != ERR)
 683         {
 684           c = save_char;
 685           save_char = ERR;
 686           return console_translate_key (c);
 687         }
 688 
 689       wtimeout (stdscr, -1);
 690       c = getch ();
 691       wtimeout (stdscr, 100);
 692     }
 693   else
 694 #endif
 695     c = getchar ();
 696 
 697   /* Quit if we get EOF. */
 698   if (c == -1)
 699     stop ();
 700   
 701   return console_translate_key (c);
 702 }
 703 
 704 /* returns packed values, LSB+1 is x, LSB is y */
 705 int
 706 console_getxy (void)
 707 {
 708   int y, x;
 709 #ifdef HAVE_LIBCURSES
 710   if (use_curses)
 711     getyx (stdscr, y, x);
 712   else
 713 #endif
 714   y = x = 0;
 715   return (x << 8) | (y & 0xff);
 716 }
 717 
 718 void
 719 console_gotoxy (int x, int y)
 720 {
 721 #ifdef HAVE_LIBCURSES
 722   if (use_curses)
 723     move (y, x);
 724 #endif
 725 }
 726 
 727 /* low-level character I/O */
 728 void
 729 console_cls (void)
 730 {
 731 #ifdef HAVE_LIBCURSES
 732   if (use_curses)
 733     clear ();
 734 #endif
 735 }
 736 
 737 void
 738 console_setcolorstate (color_state state)
 739 {
 740   console_current_color = 
 741     (state == COLOR_STATE_HIGHLIGHT) ? A_REVERSE : A_NORMAL;
 742 }
 743 
 744 void
 745 console_setcolor (int normal_color, int highlight_color)
 746 {
 747   /* Nothing to do.  */
 748 }
 749 
 750 int
 751 console_setcursor (int on)
 752 {
 753   return 1;
 754 }
 755 
 756 /* Low-level disk I/O.  Our stubbed version just returns a file
 757    descriptor, not the actual geometry. */
 758 int
 759 get_diskinfo (int drive, struct geometry *geometry)
 760 {
 761   /* FIXME: this function is truly horrid.  We try opening the device,
 762      then severely abuse the GEOMETRY->flags field to pass a file
 763      descriptor to biosdisk.  Thank God nobody's looking at this comment,
 764      or my reputation would be ruined. --Gord */
 765 
 766   /* See if we have a cached device. */
 767   if (disks[drive].flags == -1)
 768     {
 769       /* The unpartitioned device name: /dev/XdX */
 770       char *devname = device_map[drive];
 771       char buf[512];
 772 
 773       if (! devname)
 774         return -1;
 775 
 776       if (verbose)
 777         grub_printf ("Attempt to open drive 0x%x (%s)\n",
 778                      drive, devname);
 779 
 780       /* Open read/write, or read-only if that failed. */
 781       if (! read_only)
 782         disks[drive].flags = open (devname, O_RDWR);
 783 
 784       if (disks[drive].flags == -1)
 785         {
 786           if (read_only || errno == EACCES || errno == EROFS || errno == EPERM)
 787             {
 788               disks[drive].flags = open (devname, O_RDONLY);
 789               if (disks[drive].flags == -1)
 790                 {
 791                   assign_device_name (drive, 0);
 792                   return -1;
 793                 }
 794             }
 795           else
 796             {
 797               assign_device_name (drive, 0);
 798               return -1;
 799             }
 800         }
 801 
 802       /* Attempt to read the first sector.  */
 803       if (read (disks[drive].flags, buf, 512) != 512)
 804         {
 805           close (disks[drive].flags);
 806           disks[drive].flags = -1;
 807           assign_device_name (drive, 0);
 808           return -1;
 809         }
 810 
 811       if (disks[drive].flags != -1)
 812         get_drive_geometry (&disks[drive], device_map, drive);
 813     }
 814 
 815   if (disks[drive].flags == -1)
 816     return -1;
 817 
 818 #ifdef __linux__
 819   /* In Linux, invalidate the buffer cache, so that left overs
 820      from other program in the cache are flushed and seen by us */
 821   ioctl (disks[drive].flags, BLKFLSBUF, 0);
 822 #endif
 823 
 824   *geometry = disks[drive];
 825   return 0;
 826 }
 827 
 828 /* Read LEN bytes from FD in BUF. Return less than or equal to zero if an
 829    error occurs, otherwise return LEN.  */
 830 static int
 831 nread (int fd, char *buf, size_t len)
 832 {
 833   int size = len;
 834 
 835   while (len)
 836     {
 837       int ret = read (fd, buf, len);
 838 
 839       if (ret <= 0)
 840         {
 841           if (errno == EINTR)
 842             continue;
 843           else
 844             return ret;
 845         }
 846 
 847       len -= ret;
 848       buf += ret;
 849     }
 850 
 851   return size;
 852 }
 853 
 854 /* Write LEN bytes from BUF to FD. Return less than or equal to zero if an
 855    error occurs, otherwise return LEN.  */
 856 static int
 857 nwrite (int fd, char *buf, size_t len)
 858 {
 859   int size = len;
 860 
 861   while (len)
 862     {
 863       int ret = write (fd, buf, len);
 864 
 865       if (ret <= 0)
 866         {
 867           if (errno == EINTR)
 868             continue;
 869           else
 870             return ret;
 871         }
 872 
 873       len -= ret;
 874       buf += ret;
 875     }
 876 
 877   return size;
 878 }
 879 
 880 /* Dump BUF in the format of hexadecimal numbers.  */
 881 static void
 882 hex_dump (void *buf, size_t size)
 883 {
 884   /* FIXME: How to determine which length is readable?  */
 885 #define MAX_COLUMN      70
 886 
 887   /* use unsigned char for numerical computations */
 888   unsigned char *ptr = buf;
 889   /* count the width of the line */
 890   int column = 0;
 891   /* how many bytes written */
 892   int count = 0;
 893 
 894   while (size > 0)
 895     {
 896       /* high 4 bits */
 897       int hi = *ptr >> 4;
 898       /* low 4 bits */
 899       int low = *ptr & 0xf;
 900 
 901       /* grub_printf does not handle prefix number, such as %2x, so
 902          format the number by hand...  */
 903       grub_printf ("%x%x", hi, low);
 904       column += 2;
 905       count++;
 906       ptr++;
 907       size--;
 908 
 909       /* Insert space or newline with the interval 4 bytes.  */
 910       if (size != 0 && (count % 4) == 0)
 911         {
 912           if (column < MAX_COLUMN)
 913             {
 914               grub_printf (" ");
 915               column++;
 916             }
 917           else
 918             {
 919               grub_printf ("\n");
 920               column = 0;
 921             }
 922         }
 923     }
 924 
 925   /* Add a newline at the end for readability.  */
 926   grub_printf ("\n");
 927 }
 928 
 929 int
 930 biosdisk (int subfunc, int drive, struct geometry *geometry,
 931           unsigned int sector, int nsec, int segment)
 932 {
 933   char *buf;
 934   int fd = geometry->flags;
 935 
 936   /* Get the file pointer from the geometry, and make sure it matches. */
 937   if (fd == -1 || fd != disks[drive].flags)
 938     return BIOSDISK_ERROR_GEOMETRY;
 939 
 940   /* Seek to the specified location. */
 941 #if defined(__linux__) && (!defined(__GLIBC__) || \
 942         ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))))
 943   /* Maybe libc doesn't have large file support.  */
 944   {
 945     loff_t offset, result;
 946     static int _llseek (uint filedes, ulong hi, ulong lo,
 947                         loff_t *res, uint wh);
 948     _syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo,
 949                loff_t *, res, uint, wh);
 950 
 951     offset = (loff_t) sector * (loff_t) SECTOR_SIZE;
 952     if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET))
 953       return -1;
 954   }
 955 #else
 956   {
 957     off_t offset = (off_t) sector * (off_t) SECTOR_SIZE;
 958 
 959     if (lseek (fd, offset, SEEK_SET) != offset)
 960       return -1;
 961   }
 962 #endif
 963 
 964   buf = (char *) (segment << 4);
 965 
 966   switch (subfunc)
 967     {
 968     case BIOSDISK_READ:
 969 #ifdef __linux__
 970       if (sector == 0 && nsec > 1)
 971         {
 972           /* Work around a bug in linux's ez remapping.  Linux remaps all
 973              sectors that are read together with the MBR in one read.  It
 974              should only remap the MBR, so we split the read in two 
 975              parts. -jochen  */
 976           if (nread (fd, buf, SECTOR_SIZE) != SECTOR_SIZE)
 977             return -1;
 978           buf += SECTOR_SIZE;
 979           nsec--;
 980         }
 981 #endif
 982       if (nread (fd, buf, nsec * SECTOR_SIZE) != nsec * SECTOR_SIZE)
 983         return -1;
 984       break;
 985 
 986     case BIOSDISK_WRITE:
 987       if (verbose)
 988         {
 989           grub_printf ("Write %d sectors starting from %u sector"
 990                        " to drive 0x%x (%s)\n",
 991                        nsec, sector, drive, device_map[drive]);
 992           hex_dump (buf, nsec * SECTOR_SIZE);
 993         }
 994       if (! read_only)
 995         if (nwrite (fd, buf, nsec * SECTOR_SIZE) != nsec * SECTOR_SIZE)
 996           return -1;
 997       break;
 998 
 999     default:
1000       grub_printf ("unknown subfunc %d\n", subfunc);
1001       break;
1002     }
1003 
1004   return 0;
1005 }
1006 
1007 
1008 void
1009 stop_floppy (void)
1010 {
1011   /* NOTUSED */
1012 }
1013 
1014 /* Fetch a key from a serial device.  */
1015 int
1016 serial_hw_fetch (void)
1017 {
1018   fd_set fds;
1019   struct timeval to;
1020   char c;
1021 
1022   /* Wait only for the serial device.  */
1023   FD_ZERO (&fds);
1024   FD_SET (serial_fd, &fds);
1025 
1026   to.tv_sec = 0;
1027   to.tv_usec = 0;
1028   
1029   if (select (serial_fd + 1, &fds, 0, 0, &to) > 0)
1030     {
1031       if (nread (serial_fd, &c, 1) != 1)
1032         stop ();
1033 
1034       return c;
1035     }
1036   
1037   return -1;
1038 }
1039 
1040 /* Put a character to a serial device.  */
1041 void
1042 serial_hw_put (int c)
1043 {
1044   char ch = (char) c;
1045   
1046   if (nwrite (serial_fd, &ch, 1) != 1)
1047     stop ();
1048 }
1049 
1050 void
1051 serial_hw_delay (void)
1052 {
1053 #ifdef SIMULATE_SLOWNESS_OF_SERIAL
1054   struct timeval otv, tv;
1055 
1056   gettimeofday (&otv, 0);
1057 
1058   while (1)
1059     {
1060       long delta;
1061       
1062       gettimeofday (&tv, 0);
1063       delta = tv.tv_usec - otv.tv_usec;
1064       if (delta < 0)
1065         delta += 1000000;
1066       
1067       if (delta >= 1000000 / (serial_speed >> 3))
1068         break;
1069     }
1070 #endif /* SIMULATE_SLOWNESS_OF_SERIAL */
1071 }
1072 
1073 static speed_t
1074 get_termios_speed (int speed)
1075 {
1076   switch (speed)
1077     {
1078     case 2400: return B2400;
1079     case 4800: return B4800;
1080     case 9600: return B9600;
1081     case 19200: return B19200;
1082     case 38400: return B38400;
1083 #ifdef B57600
1084     case 57600: return B57600;
1085 #endif
1086 #ifdef B115200      
1087     case 115200: return B115200;
1088 #endif
1089     }
1090 
1091   return B0;
1092 }
1093 
1094 /* Get the port number of the unit UNIT. In the grub shell, this doesn't
1095    make sense.  */
1096 unsigned short
1097 serial_hw_get_port (int unit)
1098 {
1099   return 0;
1100 }
1101 
1102 /* Initialize a serial device. In the grub shell, PORT is unused.  */
1103 int
1104 serial_hw_init (unsigned short port, unsigned int speed,
1105                 int word_len, int parity, int stop_bit_len)
1106 {
1107   struct termios termios;
1108   speed_t termios_speed;
1109   int i;
1110   
1111   /* Check if the file name is specified.  */
1112   if (! serial_device)
1113     return 0;
1114 
1115   /* If a serial device is already opened, close it first.  */
1116   if (serial_fd >= 0)
1117     close (serial_fd);
1118   
1119   /* Open the device file.  */
1120   serial_fd = open (serial_device,
1121                     O_RDWR | O_NOCTTY
1122 #if defined(O_SYNC)
1123                     /* O_SYNC is used in Linux (and some others?).  */
1124                     | O_SYNC
1125 #elif defined(O_FSYNC)
1126                     /* O_FSYNC is used in FreeBSD.  */
1127                     | O_FSYNC
1128 #endif
1129                     );
1130   if (serial_fd < 0)
1131     return 0;
1132 
1133   /* Get the termios parameters.  */
1134   if (tcgetattr (serial_fd, &termios))
1135     goto fail;
1136 
1137   /* Raw mode.  */
1138   cfmakeraw (&termios);
1139 
1140   /* Set the speed.  */
1141   termios_speed = get_termios_speed (speed);
1142   if (termios_speed == B0)
1143     goto fail;
1144   
1145   cfsetispeed (&termios, termios_speed);
1146   cfsetospeed (&termios, termios_speed);
1147 
1148   /* Set the word length.  */
1149   termios.c_cflag &= ~CSIZE;
1150   switch (word_len)
1151     {
1152     case UART_5BITS_WORD:
1153       termios.c_cflag |= CS5;
1154       break;
1155     case UART_6BITS_WORD:
1156       termios.c_cflag |= CS6;
1157       break;
1158     case UART_7BITS_WORD:
1159       termios.c_cflag |= CS7;
1160       break;
1161     case UART_8BITS_WORD:
1162       termios.c_cflag |= CS8;
1163       break;
1164     default:
1165       goto fail;
1166     }
1167 
1168   /* Set the parity.  */
1169   switch (parity)
1170     {
1171     case UART_NO_PARITY:
1172       termios.c_cflag &= ~PARENB;
1173       break;
1174     case UART_ODD_PARITY:
1175       termios.c_cflag |= PARENB;
1176       termios.c_cflag |= PARODD;
1177       break;
1178     case UART_EVEN_PARITY:
1179       termios.c_cflag |= PARENB;
1180       termios.c_cflag &= ~PARODD;
1181       break;
1182     default:
1183       goto fail;
1184     }
1185 
1186   /* Set the length of stop bit.  */
1187   switch (stop_bit_len)
1188     {
1189     case UART_1_STOP_BIT:
1190       termios.c_cflag &= ~CSTOPB;
1191       break;
1192     case UART_2_STOP_BITS:
1193       termios.c_cflag |= CSTOPB;
1194       break;
1195     default:
1196       goto fail;
1197     }
1198 
1199   /* Set the parameters.  */
1200   if (tcsetattr (serial_fd, TCSANOW, &termios))
1201     goto fail;
1202 
1203 #ifdef SIMULATE_SLOWNESS_OF_SERIAL
1204   serial_speed = speed;
1205 #endif /* SIMUATE_SLOWNESS_OF_SERIAL */
1206 
1207   /* Get rid of the flag TERM_NEED_INIT from the serial terminal.  */
1208   for (i = 0; term_table[i].name; i++)
1209     {
1210       if (strcmp (term_table[i].name, "serial") == 0)
1211         {
1212           term_table[i].flags &= ~(TERM_NEED_INIT);
1213           break;
1214         }
1215     }
1216   
1217   return 1;
1218 
1219  fail:
1220   close (serial_fd);
1221   serial_fd = -1;
1222   return 0;
1223 }
1224 
1225 /* Set the file name of a serial device (or a pty device). This is a
1226    function specific to the grub shell.  */
1227 void
1228 serial_set_device (const char *device)
1229 {
1230   if (serial_device)
1231     free (serial_device);
1232   
1233   serial_device = strdup (device);
1234 }
1235 
1236 /* There is no difference between console and hercules in the grub shell.  */
1237 void
1238 hercules_putchar (int c)
1239 {
1240   console_putchar (c);
1241 }
1242 
1243 int
1244 hercules_getxy (void)
1245 {
1246   return console_getxy ();
1247 }
1248 
1249 void
1250 hercules_gotoxy (int x, int y)
1251 {
1252   console_gotoxy (x, y);
1253 }
1254 
1255 void
1256 hercules_cls (void)
1257 {
1258   console_cls ();
1259 }
1260 
1261 void
1262 hercules_setcolorstate (color_state state)
1263 {
1264   console_setcolorstate (state);
1265 }
1266 
1267 void
1268 hercules_setcolor (int normal_color, int highlight_color)
1269 {
1270   console_setcolor (normal_color, highlight_color);
1271 }
1272 
1273 int
1274 hercules_setcursor (int on)
1275 {
1276   return 1;
1277 }
1278 
1279 uint32_t amd64_cpuid_supported(void)
1280 {
1281   /* Nothing to do in the simulator. */
1282         return (1);
1283 }
1284 
1285 void amd64_cpuid_insn(uint32_t i, void * r)
1286 {
1287   /* Nothing to do in the simulator. */
1288 }
1289 
1290 void amd64_rdmsr(uint32_t i, uint64_t * p)
1291 {
1292   /* Nothing to do in the simulator. */
1293 }
1294 
1295 void amd64_wrmsr(uint32_t i, const uint64_t * p)
1296 {
1297   /* Nothing to do in the simulator. */
1298 }
1299 
1300 int get_target_operating_mode(void)
1301 {
1302   /* Nothing to do in the simulator. */
1303         return (1);
1304 }