xref: /titanic_41/usr/src/grub/grub-0.97/grub/asmstub.c (revision 6a634c9dca3093f3922e4b7ab826d7bdf17bf78e)
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
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 ()
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
assign_device_name(int drive,const char * device)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
stop(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
grub_reboot(void)268 grub_reboot (void)
269 {
270   stop ();
271 }
272 
273 void
grub_halt(int no_apm)274 grub_halt (int no_apm)
275 {
276   stop ();
277 }
278 
279 /* calls for direct boot-loader chaining */
280 void
chain_stage1(unsigned long segment,unsigned long offset,unsigned long part_table_addr)281 chain_stage1 (unsigned long segment, unsigned long offset,
282 	      unsigned long part_table_addr)
283 {
284   stop ();
285 }
286 
287 
288 void
chain_stage2(unsigned long segment,unsigned long offset,int second_sector)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
linux_boot(void)297 linux_boot (void)
298 {
299   stop ();
300 }
301 
302 
303 /* For bzImage kernels. */
304 void
big_linux_boot(void)305 big_linux_boot (void)
306 {
307   stop ();
308 }
309 
310 
311 /* booting a multiboot executable */
312 void
multi_boot(int start,int mb_info)313 multi_boot (int start, int mb_info)
314 {
315   stop ();
316 }
317 
318 /* sets it to linear or wired A20 operation */
319 void
gateA20(int linear)320 gateA20 (int linear)
321 {
322   /* Nothing to do in the simulator. */
323 }
324 
325 /* Set up the int15 handler.  */
326 void
set_int15_handler(void)327 set_int15_handler (void)
328 {
329   /* Nothing to do in the simulator.  */
330 }
331 
332 /* Restore the original int15 handler.  */
333 void
unset_int15_handler(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
set_int13_handler(unsigned short * map)345 set_int13_handler (unsigned short *map)
346 {
347   /* Nothing to do in the simulator.  */
348 }
349 
350 int
get_code_end(void)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
get_memsize(int type)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
get_eisamemsize(void)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
get_mmap_entry(struct mmar_desc * desc,int cont)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
track_int13(int drive)442 track_int13 (int drive)
443 {
444   /* Nothing to do in the simulator.  */
445 }
446 
447 /* Get the ROM configuration table.  */
448 unsigned long
get_rom_config_table(void)449 get_rom_config_table (void)
450 {
451   return 0;
452 }
453 
454 /* Get APM BIOS information.  */
455 void
get_apm_info(void)456 get_apm_info (void)
457 {
458   /* Nothing to do in the simulator.  */
459 }
460 
461 /* Get VBE controller information.  */
462 int
get_vbe_controller_info(struct vbe_controller * controller)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
get_vbe_mode_info(int mode_number,struct vbe_mode * mode)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
set_vbe_mode(int mode_number)479 set_vbe_mode (int mode_number)
480 {
481   /* Always fails.  */
482   return 0;
483 }
484 
485 /* low-level timing info */
486 int
getrtsecs(void)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
currticks(void)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
console_putchar(int c)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
console_translate_key(int c)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
console_checkkey(void)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
console_getkey(void)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
console_getxy(void)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
console_gotoxy(int x,int y)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
console_cls(void)729 console_cls (void)
730 {
731 #ifdef HAVE_LIBCURSES
732   if (use_curses)
733     clear ();
734 #endif
735 }
736 
737 void
console_setcolorstate(color_state state)738 console_setcolorstate (color_state state)
739 {
740   console_current_color =
741     (state == COLOR_STATE_HIGHLIGHT) ? A_REVERSE : A_NORMAL;
742 }
743 
744 void
console_setcolor(int normal_color,int highlight_color)745 console_setcolor (int normal_color, int highlight_color)
746 {
747   /* Nothing to do.  */
748 }
749 
750 int
console_setcursor(int on)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
get_diskinfo(int drive,struct geometry * geometry)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
nread(int fd,char * buf,size_t len)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
nwrite(int fd,char * buf,size_t len)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
hex_dump(void * buf,size_t size)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
biosdisk(int subfunc,int drive,struct geometry * geometry,unsigned int sector,int nsec,int segment)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
stop_floppy(void)1009 stop_floppy (void)
1010 {
1011   /* NOTUSED */
1012 }
1013 
1014 /* Fetch a key from a serial device.  */
1015 int
serial_hw_fetch(void)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
serial_hw_put(int c)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
serial_hw_delay(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
get_termios_speed(int speed)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
serial_hw_get_port(int unit)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
serial_hw_init(unsigned short port,unsigned int speed,int word_len,int parity,int stop_bit_len)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 #if defined(__sun)
1139   termios.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
1140   termios.c_oflag &= ~OPOST;
1141   termios.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
1142   termios.c_cflag &= ~(CSIZE|PARENB);
1143   termios.c_cflag |= CS8;
1144 #else
1145   cfmakeraw (&termios);
1146 #endif
1147 
1148   /* Set the speed.  */
1149   termios_speed = get_termios_speed (speed);
1150   if (termios_speed == B0)
1151     goto fail;
1152 
1153   cfsetispeed (&termios, termios_speed);
1154   cfsetospeed (&termios, termios_speed);
1155 
1156   /* Set the word length.  */
1157   termios.c_cflag &= ~CSIZE;
1158   switch (word_len)
1159     {
1160     case UART_5BITS_WORD:
1161       termios.c_cflag |= CS5;
1162       break;
1163     case UART_6BITS_WORD:
1164       termios.c_cflag |= CS6;
1165       break;
1166     case UART_7BITS_WORD:
1167       termios.c_cflag |= CS7;
1168       break;
1169     case UART_8BITS_WORD:
1170       termios.c_cflag |= CS8;
1171       break;
1172     default:
1173       goto fail;
1174     }
1175 
1176   /* Set the parity.  */
1177   switch (parity)
1178     {
1179     case UART_NO_PARITY:
1180       termios.c_cflag &= ~PARENB;
1181       break;
1182     case UART_ODD_PARITY:
1183       termios.c_cflag |= PARENB;
1184       termios.c_cflag |= PARODD;
1185       break;
1186     case UART_EVEN_PARITY:
1187       termios.c_cflag |= PARENB;
1188       termios.c_cflag &= ~PARODD;
1189       break;
1190     default:
1191       goto fail;
1192     }
1193 
1194   /* Set the length of stop bit.  */
1195   switch (stop_bit_len)
1196     {
1197     case UART_1_STOP_BIT:
1198       termios.c_cflag &= ~CSTOPB;
1199       break;
1200     case UART_2_STOP_BITS:
1201       termios.c_cflag |= CSTOPB;
1202       break;
1203     default:
1204       goto fail;
1205     }
1206 
1207   /* Set the parameters.  */
1208   if (tcsetattr (serial_fd, TCSANOW, &termios))
1209     goto fail;
1210 
1211 #ifdef SIMULATE_SLOWNESS_OF_SERIAL
1212   serial_speed = speed;
1213 #endif /* SIMUATE_SLOWNESS_OF_SERIAL */
1214 
1215   /* Get rid of the flag TERM_NEED_INIT from the serial terminal.  */
1216   for (i = 0; term_table[i].name; i++)
1217     {
1218       if (strcmp (term_table[i].name, "serial") == 0)
1219 	{
1220 	  term_table[i].flags &= ~(TERM_NEED_INIT);
1221 	  break;
1222 	}
1223     }
1224 
1225   return 1;
1226 
1227  fail:
1228   close (serial_fd);
1229   serial_fd = -1;
1230   return 0;
1231 }
1232 
1233 /* Set the file name of a serial device (or a pty device). This is a
1234    function specific to the grub shell.  */
1235 void
serial_set_device(const char * device)1236 serial_set_device (const char *device)
1237 {
1238   if (serial_device)
1239     free (serial_device);
1240 
1241   serial_device = strdup (device);
1242 }
1243 
1244 /* There is no difference between console and hercules in the grub shell.  */
1245 void
hercules_putchar(int c)1246 hercules_putchar (int c)
1247 {
1248   console_putchar (c);
1249 }
1250 
1251 int
hercules_getxy(void)1252 hercules_getxy (void)
1253 {
1254   return console_getxy ();
1255 }
1256 
1257 void
hercules_gotoxy(int x,int y)1258 hercules_gotoxy (int x, int y)
1259 {
1260   console_gotoxy (x, y);
1261 }
1262 
1263 void
hercules_cls(void)1264 hercules_cls (void)
1265 {
1266   console_cls ();
1267 }
1268 
1269 void
hercules_setcolorstate(color_state state)1270 hercules_setcolorstate (color_state state)
1271 {
1272   console_setcolorstate (state);
1273 }
1274 
1275 void
hercules_setcolor(int normal_color,int highlight_color)1276 hercules_setcolor (int normal_color, int highlight_color)
1277 {
1278   console_setcolor (normal_color, highlight_color);
1279 }
1280 
1281 int
hercules_setcursor(int on)1282 hercules_setcursor (int on)
1283 {
1284   return 1;
1285 }
1286 
amd64_cpuid_supported(void)1287 uint32_t amd64_cpuid_supported(void)
1288 {
1289   /* Nothing to do in the simulator. */
1290 	return (1);
1291 }
1292 
amd64_cpuid_insn(uint32_t i,void * r)1293 void amd64_cpuid_insn(uint32_t i, void * r)
1294 {
1295   /* Nothing to do in the simulator. */
1296 }
1297 
amd64_rdmsr(uint32_t i,uint64_t * p)1298 void amd64_rdmsr(uint32_t i, uint64_t * p)
1299 {
1300   /* Nothing to do in the simulator. */
1301 }
1302 
amd64_wrmsr(uint32_t i,const uint64_t * p)1303 void amd64_wrmsr(uint32_t i, const uint64_t * p)
1304 {
1305   /* Nothing to do in the simulator. */
1306 }
1307 
get_target_operating_mode(void)1308 int get_target_operating_mode(void)
1309 {
1310   /* Nothing to do in the simulator. */
1311 	return (1);
1312 }
1313