• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 (3 * 1024 * 1024)	/* 3MB */
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
grub_stage2(void)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 (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.  */
232 void
assign_device_name(int drive,const char * device)233 assign_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 
253 void
stop(void)254 stop (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 
265 void
grub_reboot(void)266 grub_reboot (void)
267 {
268   stop ();
269 }
270 
271 void
grub_halt(int no_apm)272 grub_halt (int no_apm)
273 {
274   stop ();
275 }
276 
277 /* calls for direct boot-loader chaining */
278 void
chain_stage1(unsigned long segment,unsigned long offset,unsigned long part_table_addr)279 chain_stage1 (unsigned long segment, unsigned long offset,
280 	      unsigned long part_table_addr)
281 {
282   stop ();
283 }
284 
285 
286 void
chain_stage2(unsigned long segment,unsigned long offset,int second_sector)287 chain_stage2 (unsigned long segment, unsigned long offset, int second_sector)
288 {
289   stop ();
290 }
291 
292 
293 /* do some funky stuff, then boot linux */
294 void
linux_boot(void)295 linux_boot (void)
296 {
297   stop ();
298 }
299 
300 
301 /* For bzImage kernels. */
302 void
big_linux_boot(void)303 big_linux_boot (void)
304 {
305   stop ();
306 }
307 
308 
309 /* booting a multiboot executable */
310 void
multi_boot(int start,int mb_info)311 multi_boot (int start, int mb_info)
312 {
313   stop ();
314 }
315 
316 /* sets it to linear or wired A20 operation */
317 void
gateA20(int linear)318 gateA20 (int linear)
319 {
320   /* Nothing to do in the simulator. */
321 }
322 
323 /* Set up the int15 handler.  */
324 void
set_int15_handler(void)325 set_int15_handler (void)
326 {
327   /* Nothing to do in the simulator.  */
328 }
329 
330 /* Restore the original int15 handler.  */
331 void
unset_int15_handler(void)332 unset_int15_handler (void)
333 {
334   /* Nothing to do in the simulator.  */
335 }
336 
337 /* The key map.  */
338 unsigned short bios_key_map[KEY_MAP_SIZE + 1];
339 unsigned short ascii_key_map[KEY_MAP_SIZE + 1];
340 
341 /* Copy MAP to the drive map and set up the int13 handler.  */
342 void
set_int13_handler(unsigned short * map)343 set_int13_handler (unsigned short *map)
344 {
345   /* Nothing to do in the simulator.  */
346 }
347 
348 int
get_code_end(void)349 get_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 */
357 int
get_memsize(int type)358 get_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  */
371 int
get_eisamemsize(void)372 get_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).  */
389 int
get_mmap_entry(struct mmar_desc * desc,int cont)390 get_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.  */
439 void
track_int13(int drive)440 track_int13 (int drive)
441 {
442   /* Nothing to do in the simulator.  */
443 }
444 
445 /* Get the ROM configuration table.  */
446 unsigned long
get_rom_config_table(void)447 get_rom_config_table (void)
448 {
449   return 0;
450 }
451 
452 /* Get APM BIOS information.  */
453 void
get_apm_info(void)454 get_apm_info (void)
455 {
456   /* Nothing to do in the simulator.  */
457 }
458 
459 /* Get VBE controller information.  */
460 int
get_vbe_controller_info(struct vbe_controller * controller)461 get_vbe_controller_info (struct vbe_controller *controller)
462 {
463   /* Always fails.  */
464   return 0;
465 }
466 
467 /* Get VBE mode information.  */
468 int
get_vbe_mode_info(int mode_number,struct vbe_mode * mode)469 get_vbe_mode_info (int mode_number, struct vbe_mode *mode)
470 {
471   /* Always fails.  */
472   return 0;
473 }
474 
475 /* Set VBE mode.  */
476 int
set_vbe_mode(int mode_number)477 set_vbe_mode (int mode_number)
478 {
479   /* Always fails.  */
480   return 0;
481 }
482 
483 /* low-level timing info */
484 int
getrtsecs(void)485 getrtsecs (void)
486 {
487   /* FIXME: exact value is not important, so just return time_t for now. */
488   return time (0);
489 }
490 
491 int
currticks(void)492 currticks (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 */
519 void
console_putchar(int c)520 console_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
608 static int save_char = ERR;
609 #endif
610 
611 static int
console_translate_key(int c)612 console_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 */
644 int
console_checkkey(void)645 console_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 */
671 int
console_getkey(void)672 console_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 */
703 int
console_getxy(void)704 console_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 
716 void
console_gotoxy(int x,int y)717 console_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 */
726 void
console_cls(void)727 console_cls (void)
728 {
729 #ifdef HAVE_LIBCURSES
730   if (use_curses)
731     clear ();
732 #endif
733 }
734 
735 void
console_setcolorstate(color_state state)736 console_setcolorstate (color_state state)
737 {
738   console_current_color =
739     (state == COLOR_STATE_HIGHLIGHT) ? A_REVERSE : A_NORMAL;
740 }
741 
742 void
console_setcolor(int normal_color,int highlight_color)743 console_setcolor (int normal_color, int highlight_color)
744 {
745   /* Nothing to do.  */
746 }
747 
748 int
console_setcursor(int on)749 console_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. */
756 int
get_diskinfo(int drive,struct geometry * geometry)757 get_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.  */
828 static int
nread(int fd,char * buf,size_t len)829 nread (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.  */
854 static int
nwrite(int fd,char * buf,size_t len)855 nwrite (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.  */
879 static void
hex_dump(void * buf,size_t size)880 hex_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 
927 int
biosdisk(int subfunc,int drive,struct geometry * geometry,int sector,int nsec,int segment)928 biosdisk (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 
1006 void
stop_floppy(void)1007 stop_floppy (void)
1008 {
1009   /* NOTUSED */
1010 }
1011 
1012 /* Fetch a key from a serial device.  */
1013 int
serial_hw_fetch(void)1014 serial_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.  */
1039 void
serial_hw_put(int c)1040 serial_hw_put (int c)
1041 {
1042   char ch = (char) c;
1043 
1044   if (nwrite (serial_fd, &ch, 1) != 1)
1045     stop ();
1046 }
1047 
1048 void
serial_hw_delay(void)1049 serial_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 
1071 static speed_t
get_termios_speed(int speed)1072 get_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.  */
1094 unsigned short
serial_hw_get_port(int unit)1095 serial_hw_get_port (int unit)
1096 {
1097   return 0;
1098 }
1099 
1100 /* Initialize a serial device. In the grub shell, PORT is unused.  */
1101 int
serial_hw_init(unsigned short port,unsigned int speed,int word_len,int parity,int stop_bit_len)1102 serial_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.  */
1225 void
serial_set_device(const char * device)1226 serial_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.  */
1235 void
hercules_putchar(int c)1236 hercules_putchar (int c)
1237 {
1238   console_putchar (c);
1239 }
1240 
1241 int
hercules_getxy(void)1242 hercules_getxy (void)
1243 {
1244   return console_getxy ();
1245 }
1246 
1247 void
hercules_gotoxy(int x,int y)1248 hercules_gotoxy (int x, int y)
1249 {
1250   console_gotoxy (x, y);
1251 }
1252 
1253 void
hercules_cls(void)1254 hercules_cls (void)
1255 {
1256   console_cls ();
1257 }
1258 
1259 void
hercules_setcolorstate(color_state state)1260 hercules_setcolorstate (color_state state)
1261 {
1262   console_setcolorstate (state);
1263 }
1264 
1265 void
hercules_setcolor(int normal_color,int highlight_color)1266 hercules_setcolor (int normal_color, int highlight_color)
1267 {
1268   console_setcolor (normal_color, highlight_color);
1269 }
1270 
1271 int
hercules_setcursor(int on)1272 hercules_setcursor (int on)
1273 {
1274   return 1;
1275 }
1276