📄 asmstub.c
字号:
/* asmstub.c - a version of shared_src/asm.S that works under Unix *//* * GRUB -- GRand Unified Bootloader * Copyright (C) 1999,2000,2001,2002,2004 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//* Try to use glibc's transparant LFS support. */#define _LARGEFILE_SOURCE 1/* lseek becomes synonymous with lseek64. */#define _FILE_OFFSET_BITS 64/* Simulator entry point. */int grub_stage2 (void);#include <stdlib.h>#include <string.h>#include <ctype.h>#include <assert.h>#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <time.h>#include <errno.h>#include <string.h>#include <unistd.h>#include <setjmp.h>#include <sys/time.h>#include <termios.h>#include <signal.h>#ifdef __linux__# include <sys/ioctl.h> /* ioctl */# if !defined(__GLIBC__) || \ ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))/* Maybe libc doesn't have large file support. */# include <linux/unistd.h> /* _llseek */# endif /* (GLIBC < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR < 1)) */# ifndef BLKFLSBUF# define BLKFLSBUF _IO (0x12,97) /* flush buffer cache */# endif /* ! BLKFLSBUF */#endif /* __linux__ *//* We want to prevent any circularararity in our stubs, as well as libc name clashes. */#define WITHOUT_LIBC_STUBS 1#include <shared.h>#include <device.h>#include <serial.h>#include <term.h>/* Simulated memory sizes. */#define EXTENDED_MEMSIZE (3 * 1024 * 1024) /* 3MB */#define CONVENTIONAL_MEMSIZE (640 * 1024) /* 640kB */unsigned long install_partition = 0x20000;unsigned long boot_drive = 0;int saved_entryno = 0;char version_string[] = VERSION;char config_file[128] = "/boot/grub/menu.lst"; /* FIXME: arbitrary */unsigned long linux_text_len = 0;char *linux_data_tmp_addr = 0;char *linux_data_real_addr = 0;unsigned short io_map[IO_MAP_SIZE];struct apm_info apm_bios_info;/* Emulation requirements. */char *grub_scratch_mem = 0;struct geometry *disks = 0;/* The map between BIOS drives and UNIX device file names. */char **device_map = 0;/* The jump buffer for exiting correctly. */static jmp_buf env_for_exit;/* The current color for console. */static int console_current_color = A_NORMAL;/* The file descriptor for a serial device. */static int serial_fd = -1;/* The file name of a serial device. */static char *serial_device = 0;#ifdef SIMULATE_SLOWNESS_OF_SERIAL/* The speed of a serial device. */static unsigned int serial_speed;#endif /* SIMULATE_SLOWNESS_OF_SERIAL *//* The main entry point into this mess. */intgrub_stage2 (void){ /* These need to be static, because they survive our stack transitions. */ static int status = 0; static char *realstack; char *scratch, *simstack; int i; /* We need a nested function so that we get a clean stack frame, regardless of how the code is optimized. */ static volatile void doit () { /* Make sure our stack lives in the simulated memory area. */ asm volatile ("movl %%esp, %0\n\tmovl %1, %%esp\n" : "=&r" (realstack) : "r" (simstack)); /* Do a setjmp here for the stop command. */ if (! setjmp (env_for_exit)) { /* Actually enter the generic stage2 code. */ status = 0; init_bios_info (); } else { /* If ERRNUM is non-zero, then set STATUS to non-zero. */ if (errnum) status = 1; } /* Replace our stack before we use any local variables. */ asm volatile ("movl %0, %%esp\n" : : "r" (realstack)); } assert (grub_scratch_mem == 0); scratch = malloc (0x100000 + EXTENDED_MEMSIZE + 15); assert (scratch); grub_scratch_mem = (char *) ((((int) scratch) >> 4) << 4); /* FIXME: simulate the memory holes using mprot, if available. */ assert (disks == 0); disks = malloc (NUM_DISKS * sizeof (*disks)); assert (disks); /* Initialize DISKS. */ for (i = 0; i < NUM_DISKS; i++) disks[i].flags = -1; if (! init_device_map (&device_map, device_map_file, floppy_disks)) return 1; /* Check some invariants. */ assert ((SCRATCHSEG << 4) == SCRATCHADDR); assert ((BUFFERSEG << 4) == BUFFERADDR); assert (BUFFERADDR + BUFFERLEN == SCRATCHADDR); assert (FSYS_BUF % 16 == 0); assert (FSYS_BUF + FSYS_BUFLEN == BUFFERADDR);#ifdef HAVE_LIBCURSES /* Get into char-at-a-time mode. */ if (use_curses) { initscr (); cbreak (); noecho (); nonl (); scrollok (stdscr, TRUE); keypad (stdscr, TRUE); wtimeout (stdscr, 100); signal (SIGWINCH, SIG_IGN); }#endif /* Make sure that actual writing is done. */ sync (); /* Set our stack, and go for it. */ simstack = (char *) PROTSTACKINIT; doit (); /* I don't know if this is necessary really. */ sync ();#ifdef HAVE_LIBCURSES if (use_curses) endwin ();#endif /* Close off the file descriptors we used. */ for (i = 0; i < NUM_DISKS; i ++) if (disks[i].flags != -1) {#ifdef __linux__ /* In Linux, invalidate the buffer cache. In other OSes, reboot is one of the solutions... */ ioctl (disks[i].flags, BLKFLSBUF, 0);#else# warning "In your operating system, the buffer cache will not be flushed."#endif close (disks[i].flags); } if (serial_fd >= 0) close (serial_fd); /* Release memory. */ restore_device_map (device_map); device_map = 0; free (disks); disks = 0; free (scratch); grub_scratch_mem = 0; if (serial_device) free (serial_device); serial_device = 0; /* Ahh... at last we're ready to return to caller. */ return status;}/* Assign DRIVE to a device name DEVICE. */voidassign_device_name (int drive, const char *device){ /* If DRIVE is already assigned, free it. */ if (device_map[drive]) free (device_map[drive]); /* If the old one is already opened, close it. */ if (disks[drive].flags != -1) { close (disks[drive].flags); disks[drive].flags = -1; } /* Assign DRIVE to DEVICE. */ if (! device) device_map[drive] = 0; else device_map[drive] = strdup (device);}voidstop (void){#ifdef HAVE_LIBCURSES if (use_curses) endwin ();#endif /* Jump to doit. */ longjmp (env_for_exit, 1);}voidgrub_reboot (void){ stop ();}voidgrub_halt (int no_apm){ stop ();}/* calls for direct boot-loader chaining */voidchain_stage1 (unsigned long segment, unsigned long offset, unsigned long part_table_addr){ stop ();}voidchain_stage2 (unsigned long segment, unsigned long offset, int second_sector){ stop ();}/* do some funky stuff, then boot linux */voidlinux_boot (void){ stop ();}/* For bzImage kernels. */voidbig_linux_boot (void){ stop ();}/* booting a multiboot executable */voidmulti_boot (int start, int mb_info){ stop ();}/* sets it to linear or wired A20 operation */voidgateA20 (int linear){ /* Nothing to do in the simulator. */}/* Set up the int15 handler. */voidset_int15_handler (void){ /* Nothing to do in the simulator. */}/* Restore the original int15 handler. */voidunset_int15_handler (void){ /* Nothing to do in the simulator. */}/* The key map. */unsigned short bios_key_map[KEY_MAP_SIZE + 1];unsigned short ascii_key_map[KEY_MAP_SIZE + 1];/* Copy MAP to the drive map and set up the int13 handler. */voidset_int13_handler (unsigned short *map){ /* Nothing to do in the simulator. */}intget_code_end (void){ /* Just return a little area for simulation. */ return BOOTSEC_LOCATION + (60 * 1024);}/* memory probe routines */intget_memsize (int type){ if (! type) return CONVENTIONAL_MEMSIZE >> 10; else return EXTENDED_MEMSIZE >> 10;}/* get_eisamemsize() : return packed EISA memory map, lower 16 bits is * memory between 1M and 16M in 1K parts, upper 16 bits is * memory above 16M in 64K parts. If error, return -1. */intget_eisamemsize (void){ return (EXTENDED_MEMSIZE >> 10);}#define MMAR_DESC_TYPE_AVAILABLE 1 /* available to OS */#define MMAR_DESC_TYPE_RESERVED 2 /* not available */#define MMAR_DESC_TYPE_ACPI_RECLAIM 3 /* usable by OS after reading ACPI */#define MMAR_DESC_TYPE_ACPI_NVS 4 /* required to save between NVS sessions */#define MMAR_DESC_LENGTH 20/* Fetch the next entry in the memory map and return the continuation value. DESC is a pointer to the descriptor buffer, and CONT is the previous continuation value (0 to get the first entry in the map). */intget_mmap_entry (struct mmar_desc *desc, int cont){ /* Record the memory map statically. */ static struct mmar_desc desc_table[] = { /* The conventional memory. */ { MMAR_DESC_LENGTH, 0, CONVENTIONAL_MEMSIZE, MMAR_DESC_TYPE_AVAILABLE }, /* BIOS RAM and ROM (such as video memory). */ { MMAR_DESC_LENGTH, CONVENTIONAL_MEMSIZE, 0x100000 - CONVENTIONAL_MEMSIZE, MMAR_DESC_TYPE_RESERVED }, /* The extended memory. */ { MMAR_DESC_LENGTH, 0x100000, EXTENDED_MEMSIZE, MMAR_DESC_TYPE_AVAILABLE } }; int num = sizeof (desc_table) / sizeof (*desc_table); if (cont < 0 || cont >= num) { /* Should not happen. */ desc->desc_len = 0; } else { /* Copy the entry. */ *desc = desc_table[cont++]; /* If the next entry exists, return the index. */ if (cont < num) return cont; } return 0;}/* Track the int13 handler. */voidtrack_int13 (int drive){ /* Nothing to do in the simulator. */}/* Get the ROM configuration table. */unsigned longget_rom_config_table (void){ return 0;}/* Get APM BIOS information. */voidget_apm_info (void){ /* Nothing to do in the simulator. */}/* Get VBE controller information. */intget_vbe_controller_info (struct vbe_controller *controller){ /* Always fails. */ return 0;}/* Get VBE mode information. */intget_vbe_mode_info (int mode_number, struct vbe_mode *mode){ /* Always fails. */ return 0;}/* Set VBE mode. */intset_vbe_mode (int mode_number){ /* Always fails. */ return 0;}/* low-level timing info */intgetrtsecs (void){ /* FIXME: exact value is not important, so just return time_t for now. */ return time (0);}intcurrticks (void){ struct timeval tv; long csecs; int ticks_per_csec, ticks_per_usec; /* Note: 18.2 ticks/sec. */ /* Get current time. */ gettimeofday (&tv, 0); /* Compute centiseconds. */ csecs = tv.tv_sec / 10; /* Ticks per centisecond. */ ticks_per_csec = csecs * 182; /* Ticks per microsecond. */ ticks_per_usec = (((tv.tv_sec - csecs * 10) * 1000000 + tv.tv_usec) * 182 / 10000000); /* Sum them. */ return ticks_per_csec + ticks_per_usec;}/* displays an ASCII character. IBM displays will translate some characters to special graphical ones */voidconsole_putchar (int c){ /* Curses doesn't have VGA fonts. */ switch (c) { case DISP_UL: c = ACS_ULCORNER; break; case DISP_UR: c = ACS_URCORNER; break; case DISP_LL: c = ACS_LLCORNER; break; case DISP_LR: c = ACS_LRCORNER; break; case DISP_HORIZ: c = ACS_HLINE; break; case DISP_VERT: c = ACS_VLINE; break; case DISP_LEFT: c = ACS_LARROW; break; case DISP_RIGHT: c = ACS_RARROW; break; case DISP_UP: c = ACS_UARROW; break; case DISP_DOWN: c = ACS_DARROW; break; default: break; }#ifdef HAVE_LIBCURSES if (use_curses) { /* In ncurses, a newline is treated badly, so we emulate it in our own way. */ if (c == '\n') { int x, y; getyx (stdscr, y, x); if (y + 1 == LINES) scroll (stdscr); else move (y + 1, x); } else if (isprint (c)) { int x, y; getyx (stdscr, y, x); if (x + 1 == COLS) { console_putchar ('\r'); console_putchar ('\n'); } addch (c | console_current_color); } else { addch (c); } #ifdef REFRESH_IMMEDIATELY refresh ();#endif } else#endif { /* CR is not used in Unix. */ if (c != '\r') putchar (c); }}/* The store for ungetch simulation. This is necessary, because ncurses-1.9.9g is still used in the world and its ungetch is completely broken. */#ifdef HAVE_LIBCURSESstatic int save_char = ERR;#endifstatic intconsole_translate_key (int c){ switch (c) { case KEY_LEFT: return 2; case KEY_RIGHT: return 6; case KEY_UP: return 16; case KEY_DOWN: return 14; case KEY_DC: return 4; case KEY_BACKSPACE: return 8; case KEY_HOME: return 1; case KEY_END: return 5; case KEY_PPAGE: return 7; case KEY_NPAGE: return 3; default: break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -