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