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