#include <shared.h>
#include <term.h>
#ifdef SUPPORT_HERCULES
# include <hercules.h>
#endif
#ifdef SUPPORT_SERIAL
# include <serial.h>
#endif
#ifndef STAGE1_5
struct term_entry term_table[] =
{
{
"console",
0,
24,
console_putchar,
console_checkkey,
console_getkey,
console_getxy,
console_gotoxy,
console_cls,
console_setcolorstate,
console_setcolor,
console_setcursor,
0,
0
},
#ifdef SUPPORT_SERIAL
{
"serial",
TERM_NEED_INIT,
24,
serial_putchar,
serial_checkkey,
serial_getkey,
serial_getxy,
serial_gotoxy,
serial_cls,
serial_setcolorstate,
0,
0,
0,
0
},
{
"composite",
TERM_NEED_INIT,
24,
composite_putchar,
composite_checkkey,
composite_getkey,
serial_getxy,
composite_gotoxy,
composite_cls,
composite_setcolorstate,
console_setcolor,
console_setcursor,
0,
0
},
#endif
#ifdef SUPPORT_HERCULES
{
"hercules",
0,
24,
hercules_putchar,
console_checkkey,
console_getkey,
hercules_getxy,
hercules_gotoxy,
hercules_cls,
hercules_setcolorstate,
hercules_setcolor,
hercules_setcursor,
0,
0
},
#endif
#ifdef SUPPORT_GRAPHICS
{ "graphics",
TERM_NEED_INIT,
30,
graphics_putchar,
console_checkkey,
console_getkey,
graphics_getxy,
graphics_gotoxy,
graphics_cls,
graphics_setcolorstate,
graphics_setcolor,
graphics_setcursor,
graphics_init,
graphics_end
},
#endif
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
struct term_entry *current_term = term_table;
int max_lines = 24;
int count_lines = -1;
int use_pager = 1;
#endif
void
print_error (void)
{
if (errnum > ERR_NONE && errnum < MAX_ERR_NUM)
#ifndef STAGE1_5
printf ("\nError %u: %s\n", errnum, err_list[errnum]);
#else
printf ("Error %u\n", errnum);
#endif
}
char *
convert_to_ascii (char *buf, int c, unsigned long long num)
{
unsigned long mult = 10;
char *ptr = buf;
#ifndef STAGE1_5
if (c == 'x' || c == 'X')
mult = 16;
if ((num & 0x8000000000000000uLL) && c == 'd')
{
num = (~num) + 1;
*(ptr++) = '-';
buf++;
}
#endif
do
{
int dig = num % mult;
*(ptr++) = ((dig > 9) ? dig + 'a' - 10 : '0' + dig);
}
while (num /= mult);
{
char *ptr1 = ptr - 1;
char *ptr2 = buf;
while (ptr1 > ptr2)
{
int tmp = *ptr1;
*ptr1 = *ptr2;
*ptr2 = tmp;
ptr1--;
ptr2++;
}
}
return ptr;
}
void
grub_putstr (const char *str)
{
while (*str)
grub_putchar (*str++);
}
static void
grub_vprintf (const char *format, int *dataptr)
{
char c, str[21];
int lflag;
unsigned long long val;
while ((c = *(format++)) != 0)
{
lflag = 0;
if (c != '%')
grub_putchar (c);
else
while ((c = *(format++)) != 0) {
switch (c)
{
case 'l':
lflag++;
continue;
#ifndef STAGE1_5
case 'd':
case 'x':
case 'X':
#endif
case 'u':
if (lflag == 2) {
val = *(unsigned long long *)dataptr;
dataptr += 2;
} else {
if (c == 'd')
val = (long long)*(long *)dataptr++;
else
val = *(unsigned long *)dataptr++;
}
*convert_to_ascii (str, c, val) = 0;
grub_putstr (str);
break;
#ifndef STAGE1_5
case 'c':
grub_putchar ((*(dataptr++)) & 0xff);
break;
case 's':
grub_putstr ((char *) *(dataptr++));
break;
#endif
default:
grub_putchar (c);
}
break;
}
}
}
#ifndef STAGE1_5
void
init_page (void)
{
cls ();
grub_printf ("\n GNU GRUB version %s (%dK lower / %dK upper memory)\n\n",
version_string, mbi.mem_lower, mbi.mem_upper);
}
static int num_history = 0;
static char *
get_history (int no)
{
if (no < 0 || no >= num_history)
return 0;
return (char *) HISTORY_BUF + MAX_CMDLINE * no;
}
static void
add_history (const char *cmdline, int no)
{
grub_memmove ((char *) HISTORY_BUF + MAX_CMDLINE * (no + 1),
(char *) HISTORY_BUF + MAX_CMDLINE * no,
MAX_CMDLINE * (num_history - no));
grub_strcpy ((char *) HISTORY_BUF + MAX_CMDLINE * no, cmdline);
if (num_history < HISTORY_SIZE)
num_history++;
}
static int
real_get_cmdline (char *prompt, char *cmdline, int maxlen,
int echo_char, int readline)
{
#define CMDLINE_WIDTH 78
#define CMDLINE_MARGIN 10
int xpos, lpos, c, section;
int plen;
int llen;
int history = -1;
char *buf = (char *) CMDLINE_BUF;
char *kill_buf = (char *) KILL_BUF;
auto void cl_refresh (int full, int len);
auto void cl_backward (int count);
auto void cl_forward (int count);
auto void cl_insert (const char *str);
auto void cl_delete (int count);
auto void cl_init (void);
void cl_backward (int count)
{
lpos -= count;
if (section == 1 && plen + lpos < CMDLINE_WIDTH)
cl_refresh (1, 0);
else if (xpos - count < 1)
cl_refresh (1, 0);
else
{
xpos -= count;
if (current_term->flags & TERM_DUMB)
{
int i;
for (i = 0; i < count; i++)
grub_putchar ('\b');
}
else
gotoxy (xpos, getxy () & 0xFF);
}
}
void cl_forward (int count)
{
lpos += count;
if (xpos + count >= CMDLINE_WIDTH)
cl_refresh (1, 0);
else
{
xpos += count;
if (current_term->flags & TERM_DUMB)
{
int i;
for (i = lpos - count; i < lpos; i++)
{
if (! echo_char)
grub_putchar (buf[i]);
else
grub_putchar (echo_char);
}
}
else
gotoxy (xpos, getxy () & 0xFF);
}
}
void cl_refresh (int full, int len)
{
int i;
int start;
int pos = xpos;
if (full)
{
if (lpos + plen < CMDLINE_WIDTH)
section = 0;
else
section = ((lpos + plen - CMDLINE_WIDTH)
/ (CMDLINE_WIDTH - 1 - CMDLINE_MARGIN) + 1);
len = CMDLINE_WIDTH;
pos = 0;
grub_putchar ('\r');
if (section == 0)
{
grub_printf ("%s", prompt);
len -= plen;
pos += plen;
}
else
{
grub_putchar ('<');
len--;
pos++;
}
}
if (section == 0)
{
int offset = 0;
if (! full)
offset = xpos - plen;
start = 0;
xpos = lpos + plen;
start += offset;
}
else
{
int offset = 0;
if (! full)
offset = xpos - 1;
start = ((section - 1) * (CMDLINE_WIDTH - 1 - CMDLINE_MARGIN)
+ CMDLINE_WIDTH - plen - CMDLINE_MARGIN);
xpos = lpos + 1 - start;
start += offset;
}
for (i = start; i < start + len && i < llen; i++)
{
if (! echo_char)
grub_putchar (buf[i]);
else
grub_putchar (echo_char);
pos++;
}
for (; i < start + len; i++)
{
grub_putchar (' ');
pos++;
}
if (pos == CMDLINE_WIDTH)
{
if (start + len < llen)
grub_putchar ('>');
else
grub_putchar (' ');
pos++;
}
if (current_term->flags & TERM_DUMB)
{
for (i = 0; i < pos - xpos; i++)
grub_putchar ('\b');
}
else
gotoxy (xpos, getxy () & 0xFF);
}
void cl_init (void)
{
grub_putchar ('\n');
cl_refresh (1, 0);
}
void cl_insert (const char *str)
{
int l = grub_strlen (str);
if (llen + l < maxlen)
{
if (lpos == llen)
grub_memmove (buf + lpos, str, l + 1);
else
{
grub_memmove (buf + lpos + l, buf + lpos, llen - lpos + 1);
grub_memmove (buf + lpos, str, l);
}
llen += l;
lpos += l;
if (xpos + l >= CMDLINE_WIDTH)
cl_refresh (1, 0);
else if (xpos + l + llen - lpos > CMDLINE_WIDTH)
cl_refresh (0, CMDLINE_WIDTH - xpos);
else
cl_refresh (0, l + llen - lpos);
}
}
void cl_delete (int count)
{
grub_memmove (buf + lpos, buf + lpos + count, llen - count + 1);
llen -= count;
if (xpos + llen + count - lpos > CMDLINE_WIDTH)
cl_refresh (0, CMDLINE_WIDTH - xpos);
else
cl_refresh (0, llen + count - lpos);
}
plen = grub_strlen (prompt);
llen = grub_strlen (cmdline);
if (maxlen > MAX_CMDLINE)
{
maxlen = MAX_CMDLINE;
if (llen >= MAX_CMDLINE)
{
llen = MAX_CMDLINE - 1;
cmdline[MAX_CMDLINE] = 0;
}
}
lpos = llen;
grub_strcpy (buf, cmdline);
cl_init ();
while ((c = ASCII_CHAR (getkey ())) != '\n' && c != '\r')
{
if (readline)
{
switch (c)
{
case 9:
{
int i;
int pos = 0;
int ret;
char *completion_buffer = (char *) COMPLETION_BUF;
int equal_pos = -1;
int is_filename;
while (buf[pos] == ' ')
pos++;
while (buf[pos] && buf[pos] != '=' && buf[pos] != ' ')
pos++;
is_filename = (lpos > pos);
for (i = pos; buf[i] && buf[i] != ' '; i++)
if (buf[i] == '=')
{
equal_pos = i;
buf[i] = ' ';
break;
}
for (i = lpos; i > 0 && buf[i - 1] != ' '; i--)
;
buf_drive = -1;
grub_memmove (completion_buffer, buf + i, lpos - i);
completion_buffer[lpos - i] = 0;
ret = print_completions (is_filename, 1);
errnum = ERR_NONE;
if (ret >= 0)
{
cl_insert (completion_buffer + lpos - i);
if (ret > 0)
{
grub_putchar ('\n');
print_completions (is_filename, 0);
errnum = ERR_NONE;
}
}
if (equal_pos >= 0)
buf[equal_pos] = '=';
if (ret)
cl_init ();
}
break;
case 1:
cl_backward (lpos);
break;
case 5:
cl_forward (llen - lpos);
break;
case 6:
if (lpos < llen)
cl_forward (1);
break;
case 2:
if (lpos > 0)
cl_backward (1);
break;
case 21:
if (lpos == 0)
break;
grub_memmove (kill_buf, buf, lpos);
kill_buf[lpos] = 0;
{
int count = lpos;
cl_backward (lpos);
cl_delete (count);
}
break;
case 11:
if (lpos == llen)
break;
grub_memmove (kill_buf, buf + lpos, llen - lpos + 1);
cl_delete (llen - lpos);
break;
case 25:
cl_insert (kill_buf);
break;
case 16:
{
char *p;
if (history < 0)
grub_strcpy (cmdline, buf);
else if (grub_strcmp (get_history (history), buf) != 0)
add_history (buf, history);
history++;
p = get_history (history);
if (! p)
{
history--;
break;
}
grub_strcpy (buf, p);
llen = grub_strlen (buf);
lpos = llen;
cl_refresh (1, 0);
}
break;
case 14:
{
char *p;
if (history < 0)
{
break;
}
else if (grub_strcmp (get_history (history), buf) != 0)
add_history (buf, history);
history--;
p = get_history (history);
if (! p)
p = cmdline;
grub_strcpy (buf, p);
llen = grub_strlen (buf);
lpos = llen;
cl_refresh (1, 0);
}
break;
}
}
switch (c)
{
case 27:
return 1;
case 4:
if (lpos == llen)
break;
cl_delete (1);
break;
case 8:
# ifdef GRUB_UTIL
case 127:
# endif
if (lpos > 0)
{
cl_backward (1);
cl_delete (1);
}
break;
default:
if (c >= ' ' && c <= '~')
{
char str[2];
str[0] = c;
str[1] = 0;
cl_insert (str);
}
}
}
grub_putchar ('\n');
lpos = 0;
if (! echo_char)
while (buf[lpos] == ' ')
lpos++;
grub_memmove (cmdline, buf + lpos, llen - lpos + 1);
if (readline && lpos < llen)
add_history (cmdline, 0);
return 0;
}
int
get_cmdline (char *prompt, char *cmdline, int maxlen,
int echo_char, int readline)
{
int old_cursor;
int ret;
old_cursor = setcursor (1);
if (current_term->flags & (TERM_NO_ECHO | TERM_NO_EDIT))
{
char *p = cmdline;
int c;
if (maxlen > MAX_CMDLINE)
maxlen = MAX_CMDLINE;
grub_printf ("%s", prompt);
while ((c = ASCII_CHAR (getkey ())) != '\n' && c != '\r')
{
if (c == 27)
{
setcursor (old_cursor);
return 1;
}
if (c >= ' ' && c <= '~')
{
if (! (current_term->flags & TERM_NO_ECHO))
grub_putchar (c);
if (c != ' ' || p != cmdline)
*p++ = c;
}
}
*p = 0;
if (! (current_term->flags & TERM_NO_ECHO))
grub_putchar ('\n');
setcursor (old_cursor);
return 0;
}
ret = real_get_cmdline (prompt, cmdline, maxlen, echo_char, readline);
setcursor (old_cursor);
return ret;
}
int
safe_parse_maxint (char **str_ptr, int *myint_ptr)
{
char *ptr = *str_ptr;
int myint = 0;
int mult = 10, found = 0;
if (*ptr == '0' && tolower (*(ptr + 1)) == 'x')
{
ptr += 2;
mult = 16;
}
while (1)
{
unsigned int digit;
digit = tolower (*ptr) - '0';
if (digit > 9)
{
digit -= 'a' - '0';
if (mult == 10 || digit > 5)
break;
digit += 10;
}
found = 1;
if (myint > ((MAXINT - digit) / mult))
{
errnum = ERR_NUMBER_OVERFLOW;
return 0;
}
myint = (myint * mult) + digit;
ptr++;
}
if (!found)
{
errnum = ERR_NUMBER_PARSING;
return 0;
}
*str_ptr = ptr;
*myint_ptr = myint;
return 1;
}
#endif
#if !defined(STAGE1_5) || defined(FSYS_ZFS)
static int
grub_vsprintf (char *buffer, const char *format, int *dataptr)
{
char c, *ptr, str[16];
char *bp = buffer;
int len = 0;
int lflag;
unsigned long long val;
while ((c = *format++) != 0)
{
lflag = 0;
if (c != '%') {
if (buffer)
*bp++ = c;
len++;
} else {
while (c = *(format++)) {
switch (c)
{
case 'l':
lflag++;
continue;
case 'd': case 'u': case 'x':
if (lflag == 2) {
val = *(unsigned long long *)dataptr;
dataptr += 2;
} else {
if (c == 'd')
val = (long long)*(long *)dataptr++;
else
val = *(unsigned long *)dataptr++;
}
*convert_to_ascii (str, c, val) = 0;
ptr = str;
while (*ptr) {
if (buffer)
*bp++ = *(ptr++);
else
ptr++;
len++;
}
break;
case 'c':
if (buffer)
*bp++ = (*(dataptr++))&0xff;
else
dataptr++;
len++;
break;
case 's':
ptr = (char *) (*(dataptr++));
while ((c = *ptr++) != 0) {
if (buffer)
*bp++ = c;
len++;
}
break;
}
break;
}
}
}
*bp = 0;
return (len);
}
int
grub_sprintf (char *buffer, const char *format, ...)
{
int *dataptr = (int *) &format;
dataptr++;
return (grub_vsprintf (buffer, format, dataptr));
}
#endif
void
noisy_printf (const char *format,...)
{
int *dataptr = (int *) &format;
dataptr++;
grub_vprintf(format, dataptr);
}
void
grub_printf (const char *format,...)
{
int len;
int *dataptr = (int *) &format;
dataptr++;
#ifndef STAGE1_5
if (silent.status != SILENT)
#endif
grub_vprintf(format, dataptr);
#ifndef STAGE1_5
else {
len = grub_vsprintf(NULL, format, dataptr);
if (silent.buffer_start - silent.buffer + len + 1 >=
SCREENBUF) {
silent.buffer_start = silent.buffer;
silent.looped = 1;
}
if (len < SCREENBUF)
silent.buffer_start +=
grub_vsprintf(silent.buffer_start, format, dataptr);
}
#endif
}
#if !defined(STAGE1_5) || defined(FSYS_FAT)
int
grub_tolower (int c)
{
if (c >= 'A' && c <= 'Z')
return (c + ('a' - 'A'));
return c;
}
#endif
int
grub_isspace (int c)
{
switch (c)
{
case ' ':
case '\t':
case '\r':
case '\n':
return 1;
default:
break;
}
return 0;
}
#if !defined(STAGE1_5) || defined(FSYS_ISO9660)
int
grub_memcmp (const char *s1, const char *s2, int n)
{
while (n)
{
if (*s1 < *s2)
return -1;
else if (*s1 > *s2)
return 1;
s1++;
s2++;
n--;
}
return 0;
}
#endif
#ifndef STAGE1_5
int
grub_strncat (char *s1, const char *s2, int n)
{
int i = -1;
while (++i < n && s1[i] != 0);
while (i < n && (s1[i++] = *(s2++)) != 0);
if (i >= n) {
s1[n - 1] = 0;
return 0;
}
s1[i] = 0;
return 1;
}
#endif
#if !defined(STAGE1_5) || defined(FSYS_VSTAFS) || defined(FSYS_ZFS)
int
grub_strcmp (const char *s1, const char *s2)
{
while (*s1 || *s2)
{
if (*s1 < *s2)
return -1;
else if (*s1 > *s2)
return 1;
s1 ++;
s2 ++;
}
return 0;
}
int
grub_strncmp(const char *s1, const char *s2, int n)
{
if (s1 == s2)
return (0);
n++;
while (--n != 0 && *s1 == *s2++)
if (*s1++ == '\0')
return (0);
return ((n == 0) ? 0 : *(unsigned char *)s1 - *(unsigned char *)--s2);
}
#endif
#ifndef STAGE1_5
int
getkey (void)
{
return current_term->getkey ();
}
int
checkkey (void)
{
return current_term->checkkey ();
}
#endif
void
grub_putchar (int c)
{
if (c == '\n')
grub_putchar ('\r');
#ifndef STAGE1_5
else if (c == '\t' && current_term->getxy)
{
int n;
n = 8 - ((current_term->getxy () >> 8) & 3);
while (n--)
grub_putchar (' ');
return;
}
#endif
#ifdef STAGE1_5
console_putchar (c);
#else
if (c == '\n')
{
if (count_lines >= 0)
{
count_lines++;
if (count_lines >= max_lines - 2)
{
int tmp;
count_lines = -1;
grub_printf("\n");
if (current_term->setcolorstate)
current_term->setcolorstate (COLOR_STATE_HIGHLIGHT);
grub_printf ("[Hit return to continue]");
if (current_term->setcolorstate)
current_term->setcolorstate (COLOR_STATE_NORMAL);
do
{
tmp = ASCII_CHAR (getkey ());
}
while (tmp != '\n' && tmp != '\r');
grub_printf ("\r \r");
count_lines = 0;
return;
}
}
}
current_term->putchar (c);
#endif
}
#ifndef STAGE1_5
void
gotoxy (int x, int y)
{
current_term->gotoxy (x, y);
}
int
getxy (void)
{
return current_term->getxy ();
}
void
cls (void)
{
if (current_term->flags & TERM_DUMB)
grub_putchar ('\n');
else
current_term->cls ();
}
int
setcursor (int on)
{
if (current_term->setcursor)
return current_term->setcursor (on);
return 1;
}
#endif
int
substring (const char *s1, const char *s2)
{
while (*s1 == *s2)
{
if (! *(s1++))
return 0;
s2 ++;
}
if (*s1 == 0)
return -1;
return 1;
}
#if !defined(STAGE1_5) || defined(FSYS_ZFS)
char *
grub_strstr (const char *s1, const char *s2)
{
while (*s1)
{
const char *ptr, *tmp;
ptr = s1;
tmp = s2;
while (*tmp && *ptr == *tmp)
ptr++, tmp++;
if (tmp > s2 && ! *tmp)
return (char *) s1;
s1++;
}
return 0;
}
int
grub_strlen (const char *str)
{
int len = 0;
while (*str++)
len++;
return len;
}
#endif
#ifndef STAGE1_5
int
nul_terminate (char *str)
{
int ch;
while (*str && ! grub_isspace (*str))
str++;
ch = *str;
*str = 0;
return ch;
}
char *
grub_strchr (char *str, char c)
{
for (; *str && (*str != c); str++);
return (*str ? str : NULL);
}
#endif
int
memcheck (unsigned long addr, unsigned long len)
{
int local_errnum = 0;
#ifdef GRUB_UTIL
auto unsigned long start_addr (void);
auto unsigned long end_addr (void);
auto unsigned long start_addr (void)
{
int ret;
# if defined(HAVE_START_SYMBOL)
asm volatile ("movl $start, %0" : "=a" (ret));
# elif defined(HAVE_USCORE_START_SYMBOL)
asm volatile ("movl $_start, %0" : "=a" (ret));
# endif
return ret;
}
auto unsigned long end_addr (void)
{
int ret;
# if defined(HAVE_END_SYMBOL)
asm volatile ("movl $end, %0" : "=a" (ret));
# elif defined(HAVE_USCORE_END_SYMBOL)
asm volatile ("movl $_end, %0" : "=a" (ret));
# endif
return ret;
}
if (start_addr () <= addr && end_addr () > addr + len)
return ! local_errnum;
#endif
if ((addr < RAW_ADDR (0x1000))
|| (addr < RAW_ADDR (0x100000)
&& RAW_ADDR (mbi.mem_lower * 1024) < (addr + len))
|| (addr >= RAW_ADDR (0x100000)
&& RAW_ADDR (mbi.mem_upper * 1024) < ((addr - 0x100000) + len)))
local_errnum = ERR_WONT_FIT;
if (errnum == 0)
errnum = local_errnum;
return ! local_errnum;
}
void
grub_memcpy(void *dest, const void *src, int len)
{
int i;
register char *d = (char*)dest, *s = (char*)src;
for (i = 0; i < len; i++)
d[i] = s[i];
}
void *
grub_memmove (void *to, const void *from, int len)
{
if (memcheck ((int) to, len))
{
int d0, d1, d2;
if (to < from)
{
asm volatile ("cld\n\t"
"rep\n\t"
"movsb"
: "=&c" (d0), "=&S" (d1), "=&D" (d2)
: "0" (len),"1" (from),"2" (to)
: "memory");
}
else
{
asm volatile ("std\n\t"
"rep\n\t"
"movsb\n\t"
"cld"
: "=&c" (d0), "=&S" (d1), "=&D" (d2)
: "0" (len),
"1" (len - 1 + (const char *) from),
"2" (len - 1 + (char *) to)
: "memory");
}
return to;
}
return NULL;
}
void *
grub_memset (void *start, int c, int len)
{
char *p = start;
if (memcheck ((int) start, len))
{
while (len -- > 0)
*p ++ = c;
}
return errnum ? NULL : start;
}
#ifndef STAGE1_5
char *
grub_strcpy (char *dest, const char *src)
{
grub_memmove (dest, src, grub_strlen (src) + 1);
return dest;
}
#endif
#ifndef GRUB_UTIL
# undef memcpy
void *memcpy (void *dest, const void *src, int n) __attribute__ ((alias ("grub_memmove")));
#endif