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