5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon/* asmstub.c - a version of shared_src/asm.S that works under Unix */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon * GRUB -- GRand Unified Bootloader
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon * Copyright (C) 1999,2000,2001,2002,2004 Free Software Foundation, Inc.
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon * This program is free software; you can redistribute it and/or modify
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon * it under the terms of the GNU General Public License as published by
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon * the Free Software Foundation; either version 2 of the License, or
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon * (at your option) any later version.
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon * This program is distributed in the hope that it will be useful,
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon * but WITHOUT ANY WARRANTY; without even the implied warranty of
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon * GNU General Public License for more details.
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon * You should have received a copy of the GNU General Public License
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon * along with this program; if not, write to the Free Software
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon * Copyright 2016 Nexenta Systems, Inc.
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon/* Try to use glibc's transparant LFS support. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon/* lseek becomes synonymous with lseek64. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon/* Simulator entry point. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon# if !defined(__GLIBC__) || \
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon/* Maybe libc doesn't have large file support. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon# endif /* (GLIBC < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR < 1)) */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon# define BLKFLSBUF _IO (0x12,97) /* flush buffer cache */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon# endif /* ! BLKFLSBUF */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon#endif /* __linux__ */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon/* We want to prevent any circularararity in our stubs, as well as
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon libc name clashes. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon/* Simulated memory sizes. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon#define EXTENDED_MEMSIZE (64 * 1024 * 1024) /* 64MB */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon#define CONVENTIONAL_MEMSIZE (640 * 1024) /* 640kB */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poonchar config_file[128] = "/boot/grub/menu.lst"; /* FIXME: arbitrary */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon/* Emulation requirements. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon/* The map between BIOS drives and UNIX device file names. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon/* The jump buffer for exiting correctly. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon/* The current color for console. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon/* The file descriptor for a serial device. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon/* The file name of a serial device. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon/* The speed of a serial device. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon#endif /* SIMULATE_SLOWNESS_OF_SERIAL */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon/* The main entry point into this mess. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon /* These need to be static, because they survive our stack transitions. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon auto void doit (void);
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon /* We need a nested function so that we get a clean stack frame,
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon regardless of how the code is optimized. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon /* Make sure our stack lives in the simulated memory area. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon asm volatile ("movl %%esp, %0\n\tmovl %1, %%esp\n"
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon /* Do a setjmp here for the stop command. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon /* Actually enter the generic stage2 code. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon /* If ERRNUM is non-zero, then set STATUS to non-zero. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon /* Replace our stack before we use any local variables. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon asm volatile ("movl %0, %%esp\n" : : "r" (realstack));
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon scratch = malloc (0x100000 + EXTENDED_MEMSIZE + 15);
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon grub_scratch_mem = (char *) ((((int) scratch) >> 4) << 4);
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon /* FIXME: simulate the memory holes using mprot, if available. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon /* Initialize DISKS. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon for (i = 0; i < NUM_DISKS; i++)
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon if (! init_device_map (&device_map, device_map_file, floppy_disks))
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon /* Check some invariants. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon assert (BUFFERADDR + BUFFERLEN == SCRATCHADDR);
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon assert (FSYS_BUF + FSYS_BUFLEN == BUFFERADDR);
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon /* Get into char-at-a-time mode. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon /* Make sure that actual writing is done. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon /* Set our stack, and go for it. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon /* I don't know if this is necessary really. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon /* Close off the file descriptors we used. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon for (i = 0; i < NUM_DISKS; i ++)
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon /* In Linux, invalidate the buffer cache. In other OSes, reboot
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon is one of the solutions... */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon# warning "In your operating system, the buffer cache will not be flushed."
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon /* Release memory. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon /* Ahh... at last we're ready to return to caller. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon/* Assign DRIVE to a device name DEVICE. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poonassign_device_name (int drive, const char *device)
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon /* If DRIVE is already assigned, free it. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon /* If the old one is already opened, close it. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon /* Assign DRIVE to DEVICE. */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon /* Jump to doit. */
stop ();
unsigned long part_table_addr)
stop ();
stop ();
stop ();
stop ();
stop ();
if (! type)
return cont;
return time (0);
case DISP_UL:
c = ACS_ULCORNER;
case DISP_UR:
c = ACS_URCORNER;
case DISP_LL:
c = ACS_LLCORNER;
case DISP_LR:
c = ACS_LRCORNER;
case DISP_HORIZ:
c = ACS_HLINE;
case DISP_VERT:
c = ACS_VLINE;
case DISP_LEFT:
c = ACS_LARROW;
case DISP_RIGHT:
c = ACS_RARROW;
case DISP_UP:
c = ACS_UARROW;
case DISP_DOWN:
c = ACS_DARROW;
#ifdef HAVE_LIBCURSES
if (use_curses)
else if (isprint (c))
addch (c);
#ifdef REFRESH_IMMEDIATELY
refresh ();
putchar (c);
#ifdef HAVE_LIBCURSES
case KEY_LEFT:
case KEY_RIGHT:
case KEY_UP:
case KEY_DOWN:
case KEY_DC:
case KEY_BACKSPACE:
case KEY_HOME:
case KEY_END:
case KEY_PPAGE:
case KEY_NPAGE:
#ifdef HAVE_LIBCURSES
if (use_curses)
return save_char;
c = getch ();
if (c != ERR)
save_char = c;
return console_translate_key (c);
#ifdef HAVE_LIBCURSES
if (use_curses)
c = save_char;
return console_translate_key (c);
c = getch ();
c = getchar ();
stop ();
return console_translate_key (c);
#ifdef HAVE_LIBCURSES
if (use_curses)
#ifdef HAVE_LIBCURSES
if (use_curses)
move (y, x);
#ifdef HAVE_LIBCURSES
if (use_curses)
clear ();
if (! devname)
if (verbose)
if (! read_only)
#ifdef __linux__
while (len)
if (ret <= 0)
return ret;
return size;
while (len)
if (ret <= 0)
return ret;
return size;
while (size > 0)
count++;
ptr++;
size--;
column++;
column = 0;
return BIOSDISK_ERROR_GEOMETRY;
switch (subfunc)
case BIOSDISK_READ:
#ifdef __linux__
nsec--;
case BIOSDISK_WRITE:
if (verbose)
if (! read_only)
stop ();
stop ();
#ifdef SIMULATE_SLOWNESS_OF_SERIAL
if (delta < 0)
static speed_t
switch (speed)
#ifdef B57600
#ifdef B115200
return B0;
if (! serial_device)
if (serial_fd >= 0)
#if defined(O_SYNC)
| O_SYNC
| O_FSYNC
if (serial_fd < 0)
goto fail;
#if defined(__sun)
goto fail;
switch (word_len)
case UART_5BITS_WORD:
case UART_6BITS_WORD:
case UART_7BITS_WORD:
case UART_8BITS_WORD:
goto fail;
switch (parity)
case UART_NO_PARITY:
case UART_ODD_PARITY:
case UART_EVEN_PARITY:
goto fail;
switch (stop_bit_len)
case UART_1_STOP_BIT:
case UART_2_STOP_BITS:
goto fail;
goto fail;
#ifdef SIMULATE_SLOWNESS_OF_SERIAL
fail:
if (serial_device)
console_putchar (c);
return console_getxy ();
console_gotoxy (x, y);
console_cls ();