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