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 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 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 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 266 grub_reboot (void) 267 { 268 stop (); 269 } 270 271 void 272 grub_halt (int no_apm) 273 { 274 stop (); 275 } 276 277 /* calls for direct boot-loader chaining */ 278 void 279 chain_stage1 (unsigned long segment, unsigned long offset, 280 unsigned long part_table_addr) 281 { 282 stop (); 283 } 284 285 286 void 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 295 linux_boot (void) 296 { 297 stop (); 298 } 299 300 301 /* For bzImage kernels. */ 302 void 303 big_linux_boot (void) 304 { 305 stop (); 306 } 307 308 309 /* booting a multiboot executable */ 310 void 311 multi_boot (int start, int mb_info) 312 { 313 stop (); 314 } 315 316 /* sets it to linear or wired A20 operation */ 317 void 318 gateA20 (int linear) 319 { 320 /* Nothing to do in the simulator. */ 321 } 322 323 /* Set up the int15 handler. */ 324 void 325 set_int15_handler (void) 326 { 327 /* Nothing to do in the simulator. */ 328 } 329 330 /* Restore the original int15 handler. */ 331 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 343 set_int13_handler (unsigned short *map) 344 { 345 /* Nothing to do in the simulator. */ 346 } 347 348 int 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 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 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 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 440 track_int13 (int drive) 441 { 442 /* Nothing to do in the simulator. */ 443 } 444 445 /* Get the ROM configuration table. */ 446 unsigned long 447 get_rom_config_table (void) 448 { 449 return 0; 450 } 451 452 /* Get APM BIOS information. */ 453 void 454 get_apm_info (void) 455 { 456 /* Nothing to do in the simulator. */ 457 } 458 459 /* Get VBE controller information. */ 460 int 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 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 477 set_vbe_mode (int mode_number) 478 { 479 /* Always fails. */ 480 return 0; 481 } 482 483 /* low-level timing info */ 484 int 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 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 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 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 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 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 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 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 727 console_cls (void) 728 { 729 #ifdef HAVE_LIBCURSES 730 if (use_curses) 731 clear (); 732 #endif 733 } 734 735 void 736 console_setcolorstate (color_state state) 737 { 738 console_current_color = 739 (state == COLOR_STATE_HIGHLIGHT) ? A_REVERSE : A_NORMAL; 740 } 741 742 void 743 console_setcolor (int normal_color, int highlight_color) 744 { 745 /* Nothing to do. */ 746 } 747 748 int 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 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 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 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 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 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 1007 stop_floppy (void) 1008 { 1009 /* NOTUSED */ 1010 } 1011 1012 /* Fetch a key from a serial device. */ 1013 int 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 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 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 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 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 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 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 1236 hercules_putchar (int c) 1237 { 1238 console_putchar (c); 1239 } 1240 1241 int 1242 hercules_getxy (void) 1243 { 1244 return console_getxy (); 1245 } 1246 1247 void 1248 hercules_gotoxy (int x, int y) 1249 { 1250 console_gotoxy (x, y); 1251 } 1252 1253 void 1254 hercules_cls (void) 1255 { 1256 console_cls (); 1257 } 1258 1259 void 1260 hercules_setcolorstate (color_state state) 1261 { 1262 console_setcolorstate (state); 1263 } 1264 1265 void 1266 hercules_setcolor (int normal_color, int highlight_color) 1267 { 1268 console_setcolor (normal_color, highlight_color); 1269 } 1270 1271 int 1272 hercules_setcursor (int on) 1273 { 1274 return 1; 1275 } 1276