1
/* asmstub.c - a version of shared_src/asm.S that works under Unix */
3
* GRUB -- GRand Unified Bootloader
4
* Copyright (C) 1999,2000,2001,2002,2004 Free Software Foundation, Inc.
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.
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.
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.
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
26
/* Simulator entry point. */
27
int grub_stage2 (void);
34
#include <sys/types.h>
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)) */
54
# define BLKFLSBUF _IO (0x12,97) /* flush buffer cache */
55
# endif /* ! BLKFLSBUF */
56
#endif /* __linux__ */
58
/* We want to prevent any circularararity in our stubs, as well as
60
#define WITHOUT_LIBC_STUBS 1
66
/* Simulated memory sizes. */
67
#define EXTENDED_MEMSIZE (3 * 1024 * 1024) /* 3MB */
68
#define CONVENTIONAL_MEMSIZE (640 * 1024) /* 640kB */
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
struct apm_info apm_bios_info;
80
/* Emulation requirements. */
81
char *grub_scratch_mem = 0;
83
struct geometry *disks = 0;
85
/* The map between BIOS drives and UNIX device file names. */
86
char **device_map = 0;
88
/* The jump buffer for exiting correctly. */
89
static jmp_buf env_for_exit;
91
/* The current color for console. */
92
int console_current_color = A_NORMAL;
94
/* The file descriptor for a serial device. */
95
static int serial_fd = -1;
97
/* The file name of a serial device. */
98
static char *serial_device = 0;
100
#ifdef SIMULATE_SLOWNESS_OF_SERIAL
101
/* The speed of a serial device. */
102
static unsigned int serial_speed;
103
#endif /* SIMULATE_SLOWNESS_OF_SERIAL */
105
/* The main entry point into this mess. */
109
/* These need to be static, because they survive our stack transitions. */
110
static int status = 0;
111
static char *realstack;
112
char *scratch, *simstack;
115
auto void doit (void);
117
/* We need a nested function so that we get a clean stack frame,
118
regardless of how the code is optimized. */
121
/* Make sure our stack lives in the simulated memory area. */
122
asm volatile ("movl %%esp, %0\n\tmovl %1, %%esp\n"
123
: "=&r" (realstack) : "r" (simstack));
125
/* Do a setjmp here for the stop command. */
126
if (! setjmp (env_for_exit))
128
/* Actually enter the generic stage2 code. */
135
/* If ERRNUM is non-zero, then set STATUS to non-zero. */
140
/* Replace our stack before we use any local variables. */
141
asm volatile ("movl %0, %%esp\n" : : "r" (realstack));
144
assert (grub_scratch_mem == 0);
145
scratch = malloc (0x100000 + EXTENDED_MEMSIZE + 15);
147
grub_scratch_mem = (char *) ((((int) scratch) >> 4) << 4);
149
/* FIXME: simulate the memory holes using mprot, if available. */
152
disks = malloc (NUM_DISKS * sizeof (*disks));
154
/* Initialize DISKS. */
155
for (i = 0; i < NUM_DISKS; i++)
158
if (! init_device_map (&device_map, device_map_file, floppy_disks))
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);
168
#ifdef HAVE_LIBCURSES
169
/* Get into char-at-a-time mode. */
176
scrollok (stdscr, TRUE);
177
keypad (stdscr, TRUE);
178
wtimeout (stdscr, 100);
179
signal (SIGWINCH, SIG_IGN);
183
/* Make sure that actual writing is done. */
186
/* Set our stack, and go for it. */
187
simstack = (char *) PROTSTACKINIT;
190
/* I don't know if this is necessary really. */
193
#ifdef HAVE_LIBCURSES
198
/* Close off the file descriptors we used. */
199
for (i = 0; i < NUM_DISKS; i ++)
200
if (disks[i].flags != -1)
203
/* In Linux, invalidate the buffer cache. In other OSes, reboot
204
is one of the solutions... */
205
ioctl (disks[i].flags, BLKFLSBUF, 0);
207
# warning "In your operating system, the buffer cache will not be flushed."
209
close (disks[i].flags);
215
/* Release memory. */
216
restore_device_map (device_map);
221
grub_scratch_mem = 0;
224
free (serial_device);
227
/* Ahh... at last we're ready to return to caller. */
231
/* Assign DRIVE to a device name DEVICE. */
233
assign_device_name (int drive, const char *device)
235
/* If DRIVE is already assigned, free it. */
236
if (device_map[drive])
237
free (device_map[drive]);
239
/* If the old one is already opened, close it. */
240
if (disks[drive].flags != -1)
242
close (disks[drive].flags);
243
disks[drive].flags = -1;
246
/* Assign DRIVE to DEVICE. */
248
device_map[drive] = 0;
250
device_map[drive] = strdup (device);
256
#ifdef HAVE_LIBCURSES
262
longjmp (env_for_exit, 1);
272
grub_halt (int no_apm)
277
/* calls for direct boot-loader chaining */
279
chain_stage1 (unsigned long segment, unsigned long offset,
280
unsigned long part_table_addr)
287
chain_stage2 (unsigned long segment, unsigned long offset, int second_sector)
293
/* do some funky stuff, then boot linux */
301
/* For bzImage kernels. */
303
big_linux_boot (void)
309
/* booting a multiboot executable */
311
multi_boot (int start, int mb_info)
317
/* sets it to linear or wired A20 operation */
321
/* Nothing to do in the simulator. */
324
/* Set up the int15 handler. */
326
set_int15_handler (void)
328
/* Nothing to do in the simulator. */
331
/* Restore the original int15 handler. */
333
unset_int15_handler (void)
335
/* Nothing to do in the simulator. */
340
unsigned short bios_key_map[KEY_MAP_SIZE + 1];
341
unsigned short ascii_key_map[KEY_MAP_SIZE + 1];
346
/* Just return a little area for simulation. */
347
return BOOTSEC_LOCATION + (60 * 1024);
351
/* memory probe routines */
353
get_memsize (int type)
356
return CONVENTIONAL_MEMSIZE >> 10;
358
return EXTENDED_MEMSIZE >> 10;
362
/* get_eisamemsize() : return packed EISA memory map, lower 16 bits is
363
* memory between 1M and 16M in 1K parts, upper 16 bits is
364
* memory above 16M in 64K parts. If error, return -1.
367
get_eisamemsize (void)
369
return (EXTENDED_MEMSIZE >> 10);
373
#define MMAR_DESC_TYPE_AVAILABLE 1 /* available to OS */
374
#define MMAR_DESC_TYPE_RESERVED 2 /* not available */
375
#define MMAR_DESC_TYPE_ACPI_RECLAIM 3 /* usable by OS after reading ACPI */
376
#define MMAR_DESC_TYPE_ACPI_NVS 4 /* required to save between NVS sessions */
378
#define MMAR_DESC_LENGTH 20
380
/* Fetch the next entry in the memory map and return the continuation
381
value. DESC is a pointer to the descriptor buffer, and CONT is the
382
previous continuation value (0 to get the first entry in the
385
get_mmap_entry (struct mmar_desc *desc, int cont)
387
/* Record the memory map statically. */
388
static struct mmar_desc desc_table[] =
390
/* The conventional memory. */
394
CONVENTIONAL_MEMSIZE,
395
MMAR_DESC_TYPE_AVAILABLE
397
/* BIOS RAM and ROM (such as video memory). */
400
CONVENTIONAL_MEMSIZE,
401
0x100000 - CONVENTIONAL_MEMSIZE,
402
MMAR_DESC_TYPE_RESERVED
404
/* The extended memory. */
409
MMAR_DESC_TYPE_AVAILABLE
413
int num = sizeof (desc_table) / sizeof (*desc_table);
415
if (cont < 0 || cont >= num)
417
/* Should not happen. */
422
/* Copy the entry. */
423
*desc = desc_table[cont++];
425
/* If the next entry exists, return the index. */
433
/* Track the int13 handler. */
435
track_int13 (int drive)
437
/* Nothing to do in the simulator. */
440
/* Get the ROM configuration table. */
442
get_rom_config_table (void)
447
///* Get APM BIOS information. */
449
//get_apm_info (void)
451
// /* Nothing to do in the simulator. */
454
/* Get VBE controller information. */
456
get_vbe_controller_info (struct vbe_controller *controller)
462
/* Get VBE mode information. */
464
get_vbe_mode_info (int mode_number, struct vbe_mode *mode)
472
set_vbe_mode (int mode_number)
478
/* low-level timing info */
482
/* FIXME: exact value is not important, so just return time_t for now. */
491
int ticks_per_csec, ticks_per_usec;
493
/* Note: 18.2 ticks/sec. */
495
/* Get current time. */
496
gettimeofday (&tv, 0);
498
/* Compute centiseconds. */
499
csecs = tv.tv_sec / 10;
501
/* Ticks per centisecond. */
502
ticks_per_csec = csecs * 182;
504
/* Ticks per microsecond. */
505
ticks_per_usec = (((tv.tv_sec - csecs * 10) * 1000000 + tv.tv_usec)
509
return ticks_per_csec + ticks_per_usec;
512
/* displays an ASCII character. IBM displays will translate some
513
characters to special graphical ones */
515
console_putchar (int c)
518
/* Curses doesn't have VGA fonts. */
556
#ifdef HAVE_LIBCURSES
560
/* In ncurses, a newline is treated badly, so we emulate it in our
562
/*if (((unsigned char)c) == '\n')
566
getyx (stdscr, y, x);
572
else*/ if ((unsigned char)c >= ' ' /*isprint ((unsigned char)c)*/)
576
// getyx (stdscr, y, x);
577
// if (x + 1 == COLS || (x + 1 > COLS - 2 && (unsigned char)c >= 0xc0))
579
// //console_putchar ('\r');
580
// //console_putchar ('\n');
584
addch (((unsigned char)c) | console_current_color);
590
addch ((unsigned char)c | console_current_color);
593
#ifdef REFRESH_IMMEDIATELY
600
/* CR is not used in Unix. */
602
putchar ((unsigned char)c);
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;
615
console_translate_key (int c)
647
/* like 'getkey', but doesn't wait, returns -1 if nothing available */
649
console_checkkey (void)
651
#ifdef HAVE_LIBCURSES
656
// /* Check for SAVE_CHAR. This should not be true, because this
657
// means checkkey is called twice continuously. */
658
// if (save_char != ERR)
661
wtimeout (stdscr, 0); /* returns ERR if no input is waiting */
663
wtimeout (stdscr, 100);
664
// /* If C is not ERR, then put it back in the input queue. */
670
return c; //console_translate_key (c);
674
/* Just pretend they hit the space bar, then read the real key when
679
/* returns packed BIOS/ASCII code */
681
console_getkey (void)
685
#ifdef HAVE_LIBCURSES
688
// /* If checkkey has already got a character, then return it. */
689
// if (save_char != ERR)
693
// return console_translate_key (c);
696
wtimeout (stdscr, -1); /* waits indefinitely for input */
698
wtimeout (stdscr, 100);
704
/* Quit if we get EOF. */
708
return c; //console_translate_key (c);
711
/* returns packed values, LSB+1 is x, LSB is y */
716
#ifdef HAVE_LIBCURSES
718
getyx (stdscr, y, x);
722
return (x << 8) | (y & 0xff);
726
console_gotoxy (int x, int y)
728
#ifdef HAVE_LIBCURSES
734
/* low-level character I/O */
738
#ifdef HAVE_LIBCURSES
745
console_setcolorstate (color_state state)
747
console_current_color =
748
(state == COLOR_STATE_HIGHLIGHT) ? A_REVERSE : A_NORMAL;
752
console_setcolor (int normal_color, int highlight_color)
758
console_setcursor (int on)
763
/* Low-level disk I/O. Our stubbed version just returns a file
764
descriptor, not the actual geometry. */
766
get_diskinfo (int drive, struct geometry *geometry)
768
/* FIXME: this function is truly horrid. We try opening the device,
769
then severely abuse the GEOMETRY->flags field to pass a file
770
descriptor to biosdisk. Thank God nobody's looking at this comment,
771
or my reputation would be ruined. --Gord */
773
/* See if we have a cached device. */
774
if (disks[drive].flags == -1)
776
/* The unpartitioned device name: /dev/XdX */
777
char *devname = device_map[drive];
784
grub_printf ("Attempt to open drive 0x%x (%s)\n",
787
/* Open read/write, or read-only if that failed. */
789
disks[drive].flags = open (devname, O_RDWR);
791
if (disks[drive].flags == -1)
793
if (read_only || errno == EACCES || errno == EROFS || errno == EPERM)
795
disks[drive].flags = open (devname, O_RDONLY);
796
if (disks[drive].flags == -1)
798
assign_device_name (drive, 0);
804
assign_device_name (drive, 0);
809
/* Attempt to read the first sector. */
810
if (read (disks[drive].flags, buf, 512) != 512)
812
close (disks[drive].flags);
813
disks[drive].flags = -1;
814
assign_device_name (drive, 0);
818
if (disks[drive].flags != -1)
819
get_drive_geometry (&disks[drive], device_map, drive);
822
if (disks[drive].flags == -1)
826
/* In Linux, invalidate the buffer cache, so that left overs
827
from other program in the cache are flushed and seen by us */
828
ioctl (disks[drive].flags, BLKFLSBUF, 0);
831
*geometry = disks[drive];
835
/* Read LEN bytes from FD in BUF. Return less than or equal to zero if an
836
error occurs, otherwise return LEN. */
838
nread (int fd, char *buf, size_t len)
844
int ret = read (fd, buf, len);
861
/* Write LEN bytes from BUF to FD. Return less than or equal to zero if an
862
error occurs, otherwise return LEN. */
864
nwrite (int fd, char *buf, size_t len)
870
int ret = write (fd, buf, len);
887
/* Dump BUF in the format of hexadecimal numbers. */
889
hex_dump (void *buf, size_t size)
891
/* FIXME: How to determine which length is readable? */
892
#define MAX_COLUMN 70
894
/* use unsigned char for numerical computations */
895
unsigned char *ptr = buf;
896
/* count the width of the line */
898
/* how many bytes written */
906
int low = *ptr & 0xf;
908
/* grub_printf does not handle prefix number, such as %2x, so
909
format the number by hand... */
910
grub_printf ("%x%x", hi, low);
916
/* Insert space or newline with the interval 4 bytes. */
917
if (size != 0 && (count % 4) == 0)
919
if (column < MAX_COLUMN)
932
/* Add a newline at the end for readability. */
937
biosdisk (int subfunc, int drive, struct geometry *geometry,
938
int sector, int nsec, int segment)
941
int fd = geometry->flags;
943
/* Get the file pointer from the geometry, and make sure it matches. */
944
if (fd == -1 || fd != disks[drive].flags)
945
return BIOSDISK_ERROR_GEOMETRY;
947
/* Seek to the specified location. */
948
#if defined(__linux__) && (!defined(__GLIBC__) || \
949
((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))))
950
/* Maybe libc doesn't have large file support. */
952
loff_t offset, result;
953
static int _llseek (uint filedes, ulong hi, ulong lo,
954
loff_t *res, uint wh);
955
_syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo,
956
loff_t *, res, uint, wh);
958
offset = (loff_t) sector * (loff_t) SECTOR_SIZE;
959
if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET))
964
off_t offset = (off_t) sector * (off_t) SECTOR_SIZE;
966
if (lseek (fd, offset, SEEK_SET) != offset)
971
buf = (char *) (segment << 4);
977
if (sector == 0 && nsec > 1)
979
/* Work around a bug in linux's ez remapping. Linux remaps all
980
sectors that are read together with the MBR in one read. It
981
should only remap the MBR, so we split the read in two
983
if (nread (fd, buf, SECTOR_SIZE) != SECTOR_SIZE)
989
if (nread (fd, buf, nsec * SECTOR_SIZE) != nsec * SECTOR_SIZE)
996
grub_printf ("Write %d sectors starting from %d sector"
997
" to drive 0x%x (%s)\n",
998
nsec, sector, drive, device_map[drive]);
999
hex_dump (buf, nsec * SECTOR_SIZE);
1002
if (nwrite (fd, buf, nsec * SECTOR_SIZE) != nsec * SECTOR_SIZE)
1007
grub_printf ("unknown subfunc %d\n", subfunc);
1021
/* Fetch a key from a serial device. */
1023
serial_hw_fetch (void)
1029
/* Wait only for the serial device. */
1031
FD_SET (serial_fd, &fds);
1036
if (select (serial_fd + 1, &fds, 0, 0, &to) > 0)
1038
if (nread (serial_fd, &c, 1) != 1)
1047
/* Put a character to a serial device. */
1049
serial_hw_put (int c)
1053
if (nwrite (serial_fd, &ch, 1) != 1)
1058
serial_hw_delay (void)
1060
#ifdef SIMULATE_SLOWNESS_OF_SERIAL
1061
struct timeval otv, tv;
1063
gettimeofday (&otv, 0);
1069
gettimeofday (&tv, 0);
1070
delta = tv.tv_usec - otv.tv_usec;
1074
if (delta >= 1000000 / (serial_speed >> 3))
1077
#endif /* SIMULATE_SLOWNESS_OF_SERIAL */
1081
get_termios_speed (int speed)
1085
case 2400: return B2400;
1086
case 4800: return B4800;
1087
case 9600: return B9600;
1088
case 19200: return B19200;
1089
case 38400: return B38400;
1091
case 57600: return B57600;
1094
case 115200: return B115200;
1101
/* Get the port number of the unit UNIT. In the grub shell, this doesn't
1104
serial_hw_get_port (int unit)
1109
/* Initialize a serial device. In the grub shell, PORT is unused. */
1111
serial_hw_init (unsigned short port, unsigned int speed,
1112
int word_len, int parity, int stop_bit_len)
1114
struct termios termios;
1115
speed_t termios_speed;
1118
/* Check if the file name is specified. */
1119
if (! serial_device)
1122
/* If a serial device is already opened, close it first. */
1126
/* Open the device file. */
1127
serial_fd = open (serial_device,
1130
/* O_SYNC is used in Linux (and some others?). */
1132
#elif defined(O_FSYNC)
1133
/* O_FSYNC is used in FreeBSD. */
1140
/* Get the termios parameters. */
1141
if (tcgetattr (serial_fd, &termios))
1145
cfmakeraw (&termios);
1147
/* Set the speed. */
1148
termios_speed = get_termios_speed (speed);
1149
if (termios_speed == B0)
1152
cfsetispeed (&termios, termios_speed);
1153
cfsetospeed (&termios, termios_speed);
1155
/* Set the word length. */
1156
termios.c_cflag &= ~CSIZE;
1159
case UART_5BITS_WORD:
1160
termios.c_cflag |= CS5;
1162
case UART_6BITS_WORD:
1163
termios.c_cflag |= CS6;
1165
case UART_7BITS_WORD:
1166
termios.c_cflag |= CS7;
1168
case UART_8BITS_WORD:
1169
termios.c_cflag |= CS8;
1175
/* Set the parity. */
1178
case UART_NO_PARITY:
1179
termios.c_cflag &= ~PARENB;
1181
case UART_ODD_PARITY:
1182
termios.c_cflag |= PARENB;
1183
termios.c_cflag |= PARODD;
1185
case UART_EVEN_PARITY:
1186
termios.c_cflag |= PARENB;
1187
termios.c_cflag &= ~PARODD;
1193
/* Set the length of stop bit. */
1194
switch (stop_bit_len)
1196
case UART_1_STOP_BIT:
1197
termios.c_cflag &= ~CSTOPB;
1199
case UART_2_STOP_BITS:
1200
termios.c_cflag |= CSTOPB;
1206
/* Set the parameters. */
1207
if (tcsetattr (serial_fd, TCSANOW, &termios))
1210
#ifdef SIMULATE_SLOWNESS_OF_SERIAL
1211
serial_speed = speed;
1212
#endif /* SIMUATE_SLOWNESS_OF_SERIAL */
1214
/* Get rid of the flag TERM_NEED_INIT from the serial terminal. */
1215
for (i = 0; term_table[i].name; i++)
1217
if (strcmp (term_table[i].name, "serial") == 0)
1219
term_table[i].flags &= ~(TERM_NEED_INIT);
1232
/* Set the file name of a serial device (or a pty device). This is a
1233
function specific to the grub shell. */
1235
serial_set_device (const char *device)
1238
free (serial_device);
1240
serial_device = strdup (device);
1243
/* There is no difference between console and hercules in the grub shell. */
1245
hercules_putchar (int c)
1247
console_putchar (c);
1251
hercules_getxy (void)
1253
return console_getxy ();
1257
hercules_gotoxy (int x, int y)
1259
console_gotoxy (x, y);
1269
hercules_setcolorstate (color_state state)
1271
console_setcolorstate (state);
1275
hercules_setcolor (int normal_color, int highlight_color)
1277
console_setcolor (normal_color, highlight_color);
1281
hercules_setcursor (int on)