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