Initial revision

This commit is contained in:
erich 1996-09-18 02:15:52 +00:00
commit f397c4797c
25 changed files with 9215 additions and 0 deletions

1580
shared_src/asm.S Normal file

File diff suppressed because it is too large Load diff

540
shared_src/boot.c Normal file
View file

@ -0,0 +1,540 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1996 Erich Boleyn <erich@uruk.org>
*
* 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.
*/
#define _BOOT_C
#include "shared.h"
#include "freebsd.h"
#include "imgact_aout.h"
#include "i386-elf.h"
char *cur_cmdline;
static int cur_addr;
entry_func entry_addr;
static struct mod_list mll[99];
/*
* The next two functions, 'load_image' and 'load_module', are the building
* blocks of the multiboot loader component. They handle essentially all
* of the gory details of loading in a bootable image and the modules.
*/
int
load_image(void)
{
int len, i, exec_type, align_4k = 1, type = 0;
unsigned long flags = 0, text_len, data_len, bss_len;
char *str, *str2;
union {
struct multiboot_header *mb;
struct exec *aout;
Elf32_Ehdr *elf;
} pu;
/* presuming that MULTIBOOT_SEARCH is large enough to encompass an
executable header */
unsigned char buffer[MULTIBOOT_SEARCH];
/* sets the header pointer to point to the beginning of the
buffer by default */
pu.aout = (struct exec *) buffer;
if (!open(cur_cmdline))
return 0;
if (!(len = read((int)buffer, MULTIBOOT_SEARCH)) || len < 32)
{
if (!errnum)
errnum = ERR_EXEC_FORMAT;
return 0;
}
for (i = 0; i < len; i++)
{
if (MULTIBOOT_FOUND((int)(buffer+i), len-i))
{
flags = ((struct multiboot_header *) (buffer+i))->flags;
if (flags & MULTIBOOT_UNSUPPORTED)
{
errnum = ERR_BOOT_FEATURES;
return 0;
}
type = 'm';
str2 = "Multiboot";
break;
}
}
/* ELF loading only supported if kernel using multiboot */
if (type == 'm' && len > sizeof(Elf32_Ehdr)
&& BOOTABLE_I386_ELF((*((Elf32_Ehdr *)buffer))))
{
entry_addr = (entry_func) pu.elf->e_entry;
if (((int)entry_addr) < 0x100000)
errnum = ERR_BELOW_1MB;
/* don't want to deal with ELF program header at some random
place in the file -- this generally won't happen */
if (pu.elf->e_phoff == 0 || pu.elf->e_phnum == 0
|| ((pu.elf->e_phoff + (pu.elf->e_phentsize * pu.elf->e_phnum))
>= len))
errnum = ERR_EXEC_FORMAT;
exec_type = 0;
str = "elf";
}
else if (flags & MULTIBOOT_AOUT_KLUDGE)
{
pu.mb = (struct multiboot_header *) (buffer+i);
entry_addr = (entry_func) pu.mb->entry_addr;
cur_addr = pu.mb->load_addr;
/* first offset into file */
filepos = i - (pu.mb->header_addr - cur_addr);
text_len = pu.mb->load_end_addr - cur_addr;
data_len = 0;
bss_len = pu.mb->bss_end_addr - pu.mb->load_end_addr;
if (pu.mb->header_addr < pu.mb->load_addr
|| pu.mb->load_end_addr <= pu.mb->load_addr
|| pu.mb->bss_end_addr < pu.mb->load_end_addr
|| (pu.mb->header_addr - pu.mb->load_addr) > i)
errnum = ERR_EXEC_FORMAT;
if (cur_addr < 0x100000)
errnum = ERR_BELOW_1MB;
pu.aout = (struct exec *) buffer;
exec_type = 2;
str = "kludge";
}
else if (len > sizeof(struct exec) && !N_BADMAG((*(pu.aout))))
{
entry_addr = (entry_func) pu.aout->a_entry;
if (!type)
{
/*
* If it doesn't have a Multiboot header, then presume
* it is either a FreeBSD or NetBSD executable. If so,
* then use a magic number of normal ordering, ZMAGIC to
* determine if it is FreeBSD.
*
* This is all because freebsd and netbsd seem to require
* masking out some address bits... differently for each
* one... plus of course we need to know which booting
* method to use.
*/
if (buffer[0] == 0xb && buffer[1] == 1)
{
type = 'f';
entry_addr = (entry_func) (((int)entry_addr) & 0xFFFFFF);
str2 = "FreeBSD";
}
else
{
type = 'n';
entry_addr = (entry_func) (((int)entry_addr) & 0xF00000);
if (N_GETMAGIC((*(pu.aout))) != NMAGIC)
align_4k = 0;
str2 = "NetBSD";
}
}
cur_addr = (int) entry_addr;
/* first offset into file */
filepos = N_TXTOFF((*(pu.aout)));
text_len = pu.aout->a_text;
data_len = pu.aout->a_data;
bss_len = pu.aout->a_bss;
if (cur_addr < 0x100000)
errnum = ERR_BELOW_1MB;
exec_type = 1;
str = "a.out";
}
else if ((*((unsigned short *) (buffer+BOOTSEC_SIG_OFFSET))
== BOOTSEC_SIGNATURE)
&& ((data_len
= (((long)*((unsigned char *)
(buffer+LINUX_SETUP_LEN_OFFSET))) << 9))
<= LINUX_SETUP_MAXLEN)
&& ((text_len
= (((long)*((unsigned short *)
(buffer+LINUX_KERNEL_LEN_OFFSET))) << 4))
<= LINUX_KERNEL_MAXLEN)
&& (data_len+text_len+SECTOR_SIZE) <= ((filemax+15)&0xFFFFFFF0))
{
printf(" Loading: [format=Linux-piggyback, setup=0x%x, size=0x%x]\n",
data_len, text_len);
if (mbi.mem_lower >= 608)
{
bcopy(buffer, (char *)LINUX_SETUP, data_len+SECTOR_SIZE);
/* copy command-line plus memory hack to staging area */
{
char *src = cur_cmdline;
char *dest = (char *) (CL_MY_LOCATION+4);
bcopy("mem=", (char *)CL_MY_LOCATION, 4);
*((unsigned short *) CL_OFFSET) = CL_MY_LOCATION-CL_BASE_ADDR;
*((unsigned short *) CL_MAGIC_ADDR) = CL_MAGIC;
dest = convert_to_ascii(dest, 'u', (mbi.mem_upper+0x400));
*(dest++) = 'K';
*(dest++) = ' ';
while (*src && *src != ' ')
src++;
while (((int)dest) < CL_MY_END_ADDR && (*(dest++) = *(src++)));
*dest = 0;
}
/* offset into file */
filepos = data_len+SECTOR_SIZE;
if (read(LINUX_STAGING_AREA, text_len) >= (text_len-16))
return 'l';
else if (!errnum)
errnum = ERR_EXEC_FORMAT;
}
else
errnum = ERR_WONT_FIT;
}
else /* no recognizable format */
errnum = ERR_EXEC_FORMAT;
/* return if error */
if (errnum)
return 0;
/* fill the multiboot info structure */
mbi.cmdline = (int)cur_cmdline;
mbi.mods_count = 0;
mbi.mods_addr = 0;
mbi.boot_device = (saved_drive << 24) | saved_partition;
mbi.flags &= ~(MB_INFO_MODS | MB_INFO_AOUT_SYMS | MB_INFO_ELF_SHDR);
mbi.syms.a.tabsize = 0;
mbi.syms.a.strsize = 0;
mbi.syms.a.addr = 0;
mbi.syms.a.pad = 0;
printf(" Loading: [format=%s-%s", str2, str);
str = "";
if (exec_type) /* can be loaded like a.out */
{
if (flags & MULTIBOOT_AOUT_KLUDGE)
str = "-and-data";
printf(", loadaddr=0x%x, text%s=0x%x", cur_addr, str, text_len);
/* read text, then read data */
if (read(cur_addr, text_len) == text_len)
{
cur_addr += text_len;
if (!(flags & MULTIBOOT_AOUT_KLUDGE))
{
/* we have to align to a 4K boundary */
if (align_4k)
cur_addr = (cur_addr + 0xFFF) & 0xFFFFF000;
else
printf(", C");
printf(", data=0x%x", data_len);
if (read(cur_addr, data_len) != data_len && !errnum)
errnum = ERR_EXEC_FORMAT;
cur_addr += data_len;
}
if (!errnum)
{
bzero((char*)cur_addr, bss_len);
cur_addr += bss_len;
printf(", bss=0x%x", str, bss_len);
}
}
else if (!errnum)
errnum = ERR_EXEC_FORMAT;
if (!errnum && pu.aout->a_syms
&& pu.aout->a_syms < (filemax - filepos))
{
int symtab_err, orig_addr = cur_addr;
/* we should align to a 4K boundary here for good measure */
cur_addr = (cur_addr + 0xFFF) & 0xFFFFF000;
mbi.syms.a.addr = cur_addr;
*(((int *)cur_addr)++) = pu.aout->a_syms;
printf(", symtab=0x%x", pu.aout->a_syms);
if (read(cur_addr, pu.aout->a_syms) == pu.aout->a_syms)
{
cur_addr += pu.aout->a_syms;
mbi.syms.a.tabsize = pu.aout->a_syms;
if (read((int)(&i), sizeof(int)) == sizeof(int))
{
*(((int *)cur_addr)++) = i;
mbi.syms.a.strsize = i;
i -= sizeof(int);
printf(", strtab=0x%x", i);
symtab_err = (read(cur_addr, i) != i);
cur_addr += i;
}
else
symtab_err = 1;
}
else
symtab_err = 1;
if (symtab_err)
{
printf("(bad)");
cur_addr = orig_addr;
mbi.syms.a.tabsize = 0;
mbi.syms.a.strsize = 0;
mbi.syms.a.addr = 0;
}
else
mbi.flags |= MB_INFO_AOUT_SYMS;
}
}
else /* ELF executable */
{
int loaded = 0, memaddr, memsiz, filesiz;
Elf32_Phdr *phdr;
/* reset this to zero for now */
cur_addr = 0;
/* scan for program segments */
for (i = 0; i < pu.elf->e_phnum; i++)
{
phdr = (Elf32_Phdr *)
(pu.elf->e_phoff + ((int)buffer)
+ (pu.elf->e_phentsize * i));
if (phdr->p_type == PT_LOAD)
{
/* offset into file */
filepos = phdr->p_offset;
filesiz = phdr->p_filesz;
memaddr = phdr->p_vaddr;
memsiz = phdr->p_memsz;
if (memaddr < 0x100000)
errnum = ERR_BELOW_1MB;
/* make sure we only load what we're supposed to! */
if (filesiz > memsiz)
filesiz = memsiz;
/* mark memory as used */
if (cur_addr < memaddr+memsiz)
cur_addr = memaddr+memsiz;
printf(", <0x%x:0x%x:0x%x>", str, memaddr, filesiz,
memsiz-filesiz);
/* increment number of segments */
loaded++;
/* load the segment */
if (memcheck(memaddr, memsiz)
&& read(memaddr, filesiz) == filesiz)
{
if (memsiz > filesiz)
bzero((char *)(memaddr+filesiz), memsiz-filesiz);
}
else
break;
}
}
if (!errnum)
{
if (!loaded)
errnum = ERR_EXEC_FORMAT;
else
{
/* XXX load symbols */
}
}
}
if (!errnum)
printf(", entry=0x%x]\n", str, (int)entry_addr);
else
{
putchar('\n');
type = 0;
}
return type;
}
int
load_module(void)
{
int len;
/* if we are supposed to load on 4K boundaries */
cur_addr = (cur_addr + 0xFFF) & 0xFFFFF000;
if (!open(cur_cmdline) || !(len = read(cur_addr, -1)))
return 0;
/* these two simply need to be set if any modules are loaded at all */
mbi.flags |= MB_INFO_MODS;
mbi.mods_addr = (int)mll;
mll[mbi.mods_count].cmdline = (int)cur_cmdline;
mll[mbi.mods_count].mod_start = cur_addr;
cur_addr += len;
mll[mbi.mods_count].mod_end = cur_addr;
mll[mbi.mods_count].pad = 0;
/* increment number of modules included */
mbi.mods_count++;
return 1;
}
/*
* All "*_boot" commands depend on the images being loaded into memory
* correctly, the variables in this file being set up correctly, and
* the root partition being set in the 'saved_drive' and 'saved_partition'
* variables.
*/
void
bsd_boot(int type, int bootdev)
{
char *str;
int clval = 0, i;
struct bootinfo bi;
while (*(++cur_cmdline) && *cur_cmdline != ' ');
str = cur_cmdline;
while (*str)
{
if (*str == '-')
{
while(*str && *str != ' ')
{
if (*str == 'C')
clval |= RB_CDROM;
if (*str == 'a')
clval |= RB_ASKNAME;
if (*str == 'b')
clval |= RB_HALT;
if (*str == 'c')
clval |= RB_CONFIG;
if (*str == 'd')
clval |= RB_KDB;
if (*str == 'h')
clval |= RB_SERIAL;
if (*str == 'r')
clval |= RB_DFLTROOT;
if (*str == 's')
clval |= RB_SINGLE;
if (*str == 'v')
clval |= RB_VERBOSE;
str++;
}
continue;
}
str++;
}
if (type == 'f')
{
clval |= RB_BOOTINFO;
bi.bi_version = BOOTINFO_VERSION;
*cur_cmdline = 0;
while ((--cur_cmdline) > (char *)(mbi.cmdline) && *cur_cmdline != '/');
if (*cur_cmdline == '/')
bi.bi_kernelname = cur_cmdline+1;
else
bi.bi_kernelname = 0;
bi.bi_nfs_diskless = 0;
bi.bi_n_bios_used = 0; /* this field is apparently unused */
for(i = 0; i < N_BIOS_GEOM; i++)
bi.bi_bios_geom[i] = get_diskinfo(i + 0x80);
bi.bi_size = sizeof(struct bootinfo);
bi.bi_memsizes_valid = 1;
bi.bi_basemem = mbi.mem_lower;
bi.bi_extmem = mbi.mem_upper;
bi.bi_symtab = mbi.syms.a.addr;
bi.bi_esymtab = mbi.syms.a.addr + 4
+ mbi.syms.a.tabsize + mbi.syms.a.strsize;
/* call entry point */
(*entry_addr)(clval, bootdev, 0, 0, 0, ((int)(&bi)));
}
else
{
/*
* We now pass the various bootstrap parameters to the loaded
* image via the argument list.
*
* This is the official list:
*
* arg0 = 8 (magic)
* arg1 = boot flags
* arg2 = boot device
* arg3 = start of symbol table (0 if not loaded)
* arg4 = end of symbol table (0 if not loaded)
* arg5 = transfer address from image
* arg6 = transfer address for next image pointer
* arg7 = conventional memory size (640)
* arg8 = extended memory size (8196)
*
* ...in actuality, we just pass the parameters used by the kernel.
*/
/* call entry point */
(*entry_addr)(clval, bootdev, 0,
(mbi.syms.a.addr + 4
+ mbi.syms.a.tabsize + mbi.syms.a.strsize),
mbi.mem_upper, mbi.mem_lower);
}
}

611
shared_src/char_io.c Normal file
View file

@ -0,0 +1,611 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1996 Erich Boleyn <erich@uruk.org>
*
* 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.
*/
#define _CHAR_IO_C
#include "shared.h"
#ifndef NO_FANCY_STUFF
int
getkey(void)
{
buf_drive = -1;
return asm_getkey();
}
#endif /* NO_FANCY_STUFF */
void
print_error(void)
{
if (errnum > ERR_NONE && errnum < MAX_ERR_NUM)
#ifndef NO_FANCY_STUFF
/* printf("\7\n %s\n", err_list[errnum]); */
printf("\n %s\n", err_list[errnum]);
#else /* NO_FANCY_STUFF */
printf("Error: %d\n", errnum);
#endif /* NO_FANCY_STUFF */
errnum = ERR_NONE;
}
char *
convert_to_ascii(char *buf, int c, ...)
{
unsigned long num = *((&c) + 1), mult = 10;
char *ptr = buf;
if (c == 'x')
mult = 16;
if ((num & 0x80000000uL) && c == 'd')
{
num = (~num)+1;
*(ptr++) = '-';
buf++;
}
do
{
int dig = num % mult;
*(ptr++) = ( (dig > 9) ? dig + 'a' - 10 : '0' + dig );
}
while (num /= mult);
/* reorder to correct direction!! */
{
char *ptr1 = ptr-1;
char *ptr2 = buf;
while (ptr1 > ptr2)
{
int c = *ptr1;
*ptr1 = *ptr2;
*ptr2 = c;
ptr1--;
ptr2++;
}
}
return ptr;
}
void
printf(char *format, ... )
{
int *dataptr = (int *) &format;
char c, *ptr, str[16];
dataptr++;
while (c = *(format++))
{
if (c != '%')
putchar(c);
else
switch (c = *(format++))
{
case 'd': case 'u': case 'x':
*convert_to_ascii(str, c, *((unsigned long *) dataptr++)) = 0;
ptr = str;
while (*ptr)
putchar(*(ptr++));
break;
case 'c': putchar((*(dataptr++))&0xff); break;
case 's':
ptr = (char *)(*(dataptr++));
while (c = *(ptr++))
putchar(c);
break;
}
}
}
#ifndef NO_FANCY_STUFF
void
init_page(void)
{
cls();
printf("\n GRUB version %s (%dK lower / %dK upper memory)\n\n",
version_string, mbi.mem_lower, mbi.mem_upper);
}
/* don't use this with a maxlen greater than 1600 or so! the problem
is that it depends on the whole thing fitting on the screen at once,
and the whole screen is about 2000 characters, minus the prompt...
so want to leave space for an error line, etc.
maxlen should be at least 1, and we shouldn't have a NULL prompt or
cmdline... the cmdline must be a valid string at the start */
int
get_cmdline(char *prompt, char *commands, char *cmdline, int maxlen)
{
int ystart, yend, xend, lpos, c;
int plen = 0;
int llen = 0;
/* nested function definition for code simplicity XXX GCC only, I think */
void cl_print(char *str)
{
while (*str != 0)
{
putchar(*(str++));
if (++xend > 78)
{
xend = 0;
putchar(' ');
if (yend == (getxy() & 0xFF))
ystart--;
else
yend++;
}
}
}
/* nested function definition for code simplicity XXX GCC only, I think */
void cl_setcpos(void)
{
yend = ((lpos+plen) / 79) + ystart;
xend = ((lpos+plen) % 79);
gotoxy(xend, yend);
}
/* nested function definition for initial command-line printing */
void cl_init()
{
/* distinguish us from other lines and error messages! */
putchar('\n');
/* print full line and set position here */
ystart = (getxy() & 0xFF);
yend = ystart;
xend = 0;
cl_print(prompt);
cl_print(cmdline);
cl_setcpos();
}
/* nested function definition for erasing to the end of the line */
void cl_kill_to_end()
{
int i;
cmdline[lpos] = 0;
for (i = lpos; i <= llen; i++)
{
if (i && ((i + plen) % 79) == 0)
putchar(' ');
putchar(' ');
}
llen = lpos;
cl_setcpos();
}
while (prompt[plen])
plen++;
while (cmdline[llen])
llen++;
/* XXX limiting maxlen to 1600 */
if (maxlen > 1600)
{
maxlen = 1600;
if (llen > 1599)
{
llen = 1599;
cmdline[1600] = 0;
}
}
lpos = llen;
cl_init();
while (ASCII_CHAR(c = getkey()) != '\n' && ASCII_CHAR(c) != '\r')
{
switch (c)
{
case KEY_LEFT:
c = 2;
break;
case KEY_RIGHT:
c = 6;
break;
case KEY_HOME:
c = 1;
break;
case KEY_END:
c = 5;
break;
case KEY_DELETE:
c = 8;
default:
}
c = ASCII_CHAR(c);
switch (c)
{
case 27: /* ESC immediately return 1*/
return 1;
case 9: /* TAB lists completions */
{
int i, j = 0, llen_old = llen;
while (cmdline[j] && cmdline[j] != '=')
j++;
/* since the command line cannot have a '\n', we're OK to use c */
c = cmdline[lpos];
cl_kill_to_end();
/* goto part after line here */
yend = ((llen+plen) / 79) + ystart;
gotoxy(0, yend); putchar('\n');
if (lpos > j)
{
for (i = lpos; i > 0 && cmdline[i-1] != ' '; i--);
if (i <= j)
i = j+1;
/* print possible completions */
print_completions(cmdline+i);
}
else if (commands)
printf(commands);
else
break;
/* restore command-line */
cmdline[lpos] = c;
llen = llen_old;
cl_init();
}
break;
case 1: /* C-a go to beginning of line */
lpos = 0;
cl_setcpos();
break;
case 5: /* C-e go to end of line */
lpos = llen;
cl_setcpos();
break;
case 6: /* C-f forward one character */
if (lpos < llen)
{
lpos++;
cl_setcpos();
}
break;
case 2: /* C-b backward one character */
if (lpos > 0)
{
lpos--;
cl_setcpos();
}
break;
case 4: /* C-d delete character under cursor */
if (lpos == llen)
break;
lpos++;
/* fallthrough is on purpose! */
case 8: /* C-h backspace */
if (lpos > 0)
{
int i;
for (i = lpos-1; i < llen; i++)
cmdline[i] = cmdline[i+1];
i = lpos;
lpos = llen - 1;
cl_setcpos();
putchar(' ');
lpos = i - 1; /* restore lpos and decrement */
llen--;
cl_setcpos();
if (lpos != llen)
{
cl_print(cmdline+lpos);
cl_setcpos();
}
}
break;
case 21: /* C-u kill to beginning of line */
if (lpos == 0)
break;
{
int i;
for (i = 0; i < (llen-lpos); i++)
cmdline[i] = cmdline[lpos+i];
}
lpos = llen-lpos;
cl_setcpos();
/* fallthrough on purpose! */
case 11: /* C-k kill to end of line */
if (lpos < llen)
{
cl_kill_to_end();
if (c == 21)
{
lpos = 0;
cl_setcpos();
cl_print(cmdline);
cl_setcpos();
}
}
break;
default: /* insert printable character into line */
if (llen < (maxlen-1) && c >= ' ' && c <= '~')
{
if (lpos == llen)
{
cmdline[lpos] = c;
cmdline[lpos+1] = 0;
cl_print(cmdline+lpos);
lpos++;
}
else
{
int i;
for (i = llen; i >= lpos; i--)
cmdline[i+1] = cmdline[i];
cmdline[lpos] = c;
cl_setcpos();
cl_print(cmdline+lpos);
lpos++;
cl_setcpos();
}
llen++;
}
}
}
/* goto part after line here */
yend = ((llen+plen) / 79) + ystart;
gotoxy(0, yend); putchar('\n');
/* remove leading spaces */
/* use c and lpos as indexes now */
for (lpos = 0; cmdline[lpos] == ' '; lpos++);
if (lpos != 0)
{
c = 0;
do
{
cmdline[c] = cmdline[lpos];
c++;
lpos++;
}
while (cmdline[lpos]);
}
cmdline[c] = 0;
return 0;
}
#endif /* NO_FANCY_STUFF */
int
get_based_digit(int c, int base)
{
int digit = -1;
/* make sure letter in the the range we can check! */
c = tolower(c);
/*
* Is it in the range between zero and nine?
*/
if (base > 0 && c >= '0' && c <= '9' && c < (base + '0'))
{
digit = c - '0';
}
/*
* Is it in the range used by a letter?
*/
if (base > 10 && c >= 'a' && c <= 'z' && c < ((base - 10) + 'a'))
{
digit = c - 'a' + 10;
}
return digit;
}
int
safe_parse_maxint(char **str_ptr, int *myint_ptr)
{
register char *ptr = *str_ptr;
register int myint = 0, digit;
int mult = 10, found = 0;
/*
* Is this a hex number?
*/
if (*ptr == '0' && tolower(*(ptr+1)) == 'x')
{
ptr += 2;
mult = 16;
}
while ((digit = get_based_digit(*ptr, mult)) != -1)
{
found = 1;
if (myint > ((MAXINT - digit)/mult))
{
errnum = ERR_NUMBER_PARSING;
return 0;
}
myint = (myint * mult) + digit;
ptr++;
}
if (!found)
{
errnum = ERR_NUMBER_PARSING;
return 0;
}
*str_ptr = ptr;
*myint_ptr = myint;
return 1;
}
int
tolower(int c)
{
if (c >= 'A' && c <= 'Z')
return (c + ('a' - 'A'));
return c;
}
int
isspace(int c)
{
if (c == ' ' || c == '\t' || c == '\n')
return 1;
return 0;
}
int
strncat(char *s1, char *s2, int n)
{
int i = -1;
while (++i < n && s1[i] != 0);
while (i < n && (s1[i++] = *(s2++)) != 0);
s1[n-1] = 0;
if (i >= n)
return 0;
s1[i] = 0;
return 1;
}
int
strcmp(char *s1, char *s2)
{
while (*s1 == *s2)
{
if (!*(s1++))
return 0;
s2++;
}
if (*s1 == 0)
return -1;
return 1;
}
char *
strstr(char *s1, char *s2)
{
char *ptr, *tmp;
while (*s1)
{
ptr = s1;
tmp = s2;
while (*s1 && *s1++ == *tmp++);
if (tmp > s2 && !*(tmp-1))
return ptr;
}
return 0;
}
int
memcheck(int start, int len)
{
if ( (start < 0x1000) || (start < 0x100000
&& (mbi.mem_lower * 1024) < (start+len))
|| (start >= 0x100000
&& (mbi.mem_upper * 1024) < ((start-0x100000)+len)) )
errnum = ERR_WONT_FIT;
return (!errnum);
}
int
bcopy(char *from, char *to, int len)
{
if (memcheck((int)to, len))
{
if ((to >= from+len) || (to <= from))
{
while (len > 3)
{
len -= 4;
*(((unsigned long *)to)++) = *(((unsigned long *)from)++);
}
while (len-- > 0)
*(to++) = *(from++);
}
else
{
while (len-- > 0)
to[len] = from[len];
}
}
return (!errnum);
}
int
bzero(char *start, int len)
{
if (memcheck((int)start, len))
{
while (len-- > 0)
*(start++) = 0;
}
return (!errnum);
}

890
shared_src/cmdline.c Normal file
View file

@ -0,0 +1,890 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1996 Erich Boleyn <erich@uruk.org>
*
* 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.
*/
#define _CMDLINE_C
#include "shared.h"
#ifdef DEBUG
unsigned long apic_addr;
int start_cpu(int cpu_num, int start_addr, unsigned long my_apic_addr);
extern char patch_code[];
extern char patch_code_end[];
unsigned long reg_table[] =
{ 0x20, 0x30, 0x80, 0x90, 0xa0, 0xd0, 0xe0, 0xf0, 0x280, 0x300, 0x310,
0x320, 0x350, 0x360, 0x370, 0x380, 0x390, 0x3e0, 0 };
int
get_remote_APIC_reg(int cpu_num, int reg, unsigned long *retval)
{
int i, j = 1000;
i = *((volatile unsigned long *) (apic_addr+0xc0));
*((volatile unsigned long *) (apic_addr+0x310)) = (cpu_num << 24);
i = *((volatile unsigned long *) (apic_addr+0xc0));
*((volatile unsigned long *) (apic_addr+0x300)) = (0x300 | (reg>>4));
while (((i = (*((volatile unsigned long *) (apic_addr+0x300)) & 0x30000))
== 1) && (--j));
if (!i || i == 3 || j == 0)
return 1;
*retval = *((volatile unsigned long *) (apic_addr+0xc0));
return 0;
}
void
list_regs(int cpu_num)
{
int i = 0, j = 0;
unsigned long tmpval;
while (reg_table[i] != 0)
{
printf(" %x: ", reg_table[i]);
if (cpu_num == -1)
tmpval = *((volatile unsigned long *) (apic_addr+reg_table[i]));
else if (get_remote_APIC_reg(cpu_num, reg_table[i], &tmpval))
printf("error!");
printf("%x", tmpval);
i++;
j++;
if (j == 5 || reg_table[i] == 0)
{
j = 0;
putchar('\n');
}
else
putchar(',');
}
}
void
boot_cpu(int cpu_num)
{
int i, start_addr = (128 * 1024);
bcopy( patch_code, ((char *) start_addr),
((int) patch_code_end) - ((int) patch_code) );
outb(0x70, 0xf);
*((volatile unsigned short *) 0x467) = 0;
*((volatile unsigned short *) 0x469) = ((unsigned short)(start_addr >> 4));
outb(0x71, 0xa);
print_error();
printf("Starting probe for CPU #%d... value = (%x)\n",
cpu_num, *((int *) start_addr) );
i = start_cpu(cpu_num, start_addr, apic_addr);
printf("Return value = (%x), waiting for RET...", i);
i = getc();
outb(0x70, 0xf);
printf("\nEnding value = (%x), Status code = (%x)\n",
*((int *) start_addr), (unsigned long)inb(0x71));
}
unsigned char
sum(unsigned char *addr, int len)
{
int i;
unsigned long retval = 0;
for (i = 0; i < len; i++)
{
retval += addr[len];
}
return ((unsigned char)(retval & 0xFF));
}
int
get_mp_parameters(unsigned char *addr)
{
int i, may_be_bad;
unsigned long backup;
if (((int)addr)&0xF || addr[0] != '_' || addr[1] != 'M' || addr[2] != 'P'
|| addr[3] != '_')
return 0;
may_be_bad = 0;
if (sum(addr, addr[8] * 16))
{
printf("Found MP structure but checksum bad, use (y/n) ?");
i = getc();
putchar('\n');
if (i != 'y')
return 0;
may_be_bad = 1;
}
backup = apic_addr;
printf("MP Floating Pointer Structure (address, then 12 bytes starting at 4):
%x, %x, %x, %x\n", (int)addr,
*((int *)(addr+4)), *((int *)(addr+8)), *((int *)(addr+12)));
if (*((int *)(addr+4)) != 0)
{
addr = *((unsigned char **)(addr+4));
apic_addr = *((unsigned long *)(addr+0x24));
printf("MP Configuration Table, local APIC at (%x)\n", apic_addr);
}
if (may_be_bad)
{
printf("Use this entry (y/n) ?");
i = getc();
putchar('\n');
if (i != 'y')
{
apic_addr = backup;
return 0;
}
}
return 1;
}
int
probe_mp_table(void)
{
int i, probe_addr = *((unsigned short *)0x40E);
probe_addr <<= 4;
if (probe_addr > 0 && probe_addr <= 639*1024
&& *((unsigned char *) probe_addr) > 0
&& probe_addr + *((unsigned char *) probe_addr) * 0x400 <= 640*1024)
{
for (i = 0; i < 1024; i += 16)
{
if (get_mp_parameters((unsigned char *)(probe_addr+i)))
return 1;
}
}
/*
* Technically, if there is an EBDA, we shouldn't search the last
* KB of memory, but I don't think it will be a problem.
*/
if (mbi.mem_lower > 512)
probe_addr = 639 * 1024;
else
probe_addr = 511 * 1024;
for (i = 0; i < 1024; i += 16)
{
if (get_mp_parameters((unsigned char *)(probe_addr+i)))
return 1;
}
for (probe_addr = 0xF0000; probe_addr < 0x100000; probe_addr += 16)
{
if (get_mp_parameters((unsigned char *)probe_addr))
return 1;
}
return 0;
}
void
copy_patch_code(void)
{
int start_addr = (128 * 1024);
bcopy( patch_code, ((char *) start_addr),
((int) patch_code_end) - ((int) patch_code) );
outb(0x70, 0xf);
*((volatile unsigned short *) 0x467) = 0;
*((volatile unsigned short *) 0x469) = ((unsigned short)(start_addr >> 4));
outb(0x71, 0xa);
print_error();
}
void
send_init(int cpu_num)
{
int i, start_addr = (128 * 1024);
*((volatile unsigned long *) (apic_addr+0x280)) = 0;
i = *((volatile unsigned long *) (apic_addr+0x280));
*((volatile unsigned long *) (apic_addr+0x310)) = (cpu_num << 24);
i = *((volatile unsigned long *) (apic_addr+0x280));
*((volatile unsigned long *) (apic_addr+0x300)) = 0xc500;
for (i = 0; i < 100000; i++);
*((volatile unsigned long *) (apic_addr+0x300)) = 0x8500;
for (i = 0; i < 1000000; i++);
i = *((volatile unsigned long *) (apic_addr+0x280));
i &= 0xEF;
if (i)
printf("APIC error (%x)\n", i);
}
void
send_startup(int cpu_num)
{
int i, start_addr = (128 * 1024);
printf("Starting value = (%x)\n", *((int *) start_addr) );
*((volatile unsigned long *) (apic_addr+0x280)) = 0;
i = *((volatile unsigned long *) (apic_addr+0x280));
*((volatile unsigned long *) (apic_addr+0x310)) = (cpu_num << 24);
i = *((volatile unsigned long *) (apic_addr+0x280));
*((volatile unsigned long *) (apic_addr+0x300)) = (0x600 | (start_addr>>12));
for (i = 0; i < 100000; i++);
i = *((volatile unsigned long *) (apic_addr+0x280));
i &= 0xEF;
if (i)
printf("APIC error (%x)\n", i);
else
{
printf("Waiting for RET...");
i = getc();
outb(0x70, 0xf);
printf("\nEnding value = (%x), Status code = (%x)\n",
*((int *) start_addr), (unsigned long)inb(0x71));
}
}
#endif /* DEBUG */
/*
* This is used for determining of the command-line should ask the user
* to correct errors.
*/
int fallback = -1;
char *
skip_to(int after_equal, char *cmdline)
{
while (*cmdline && (*cmdline != (after_equal ? '=' : ' ')))
cmdline++;
if (after_equal)
cmdline++;
while (*cmdline == ' ')
cmdline++;
return cmdline;
}
void
init_cmdline(void)
{
printf(" [ Minimal BASH-like line editing is supported. For the first word, TAB
lists possible command completions. Anywhere else TAB lists the possible
completions of a device/filename. ESC at any time exits. ]\n");
}
#ifdef DEBUG
char commands[] =
" Possible commands are: \"pause= ...\", \"uppermem= <kbytes>\", \"root= <device>\",
\"rootnoverify= <device>\", \"chainloader= <file>\", \"kernel= <file> ...\",
\"testload= <file>\", \"syscmd= <cmd>\", \"displaymem\", \"probemps\",
\"module= <file> ...\", \"modulenounzip= <file> ...\", \"makeactive\", \"boot\", and
\"install= <stage1_file> [d] <dest_dev> <file> <addr> [p] [<config_file>]\"\n";
#else /* DEBUG */
char commands[] =
" Possible commands are: \"pause= ...\", \"uppermem= <kbytes>\", \"root= <device>\",
\"rootnoverify= <device>\", \"chainloader= <file>\", \"kernel= <file> ...\",
\"module= <file> ...\", \"modulenounzip= <file> ...\", \"makeactive\", \"boot\", and
\"install= <stage1_file> [d] <dest_dev> <file> <addr> [p] [<config_file>]\"\n";
#endif /* DEBUG */
#ifdef DEBUG
static void
debug_fs_print_func(int sector)
{
printf("[%d]", sector);
}
#endif /* DEBUG */
static int installaddr, installlist, installsect;
static void
debug_fs_blocklist_func(int sector)
{
#ifdef DEBUG
printf("[%d]", sector);
#endif /* DEBUG */
if (*((unsigned long *)(installlist-4))
+ *((unsigned short *)installlist) != sector
|| installlist == BOOTSEC_LOCATION+STAGE1_FIRSTLIST+4)
{
installlist -= 8;
if (*((unsigned long *)(installlist-8)))
errnum = ERR_WONT_FIT;
else
{
*((unsigned short *)(installlist+2)) = (installaddr >> 4);
*((unsigned long *)(installlist-4)) = sector;
}
}
*((unsigned short *)installlist) += 1;
installsect = sector;
installaddr += 512;
}
int
enter_cmdline(char *script, char *heap)
{
int bootdev, cmd_len, type = 0, run_cmdline = 1, have_run_cmdline = 0;
#ifdef DEBUG
int mptest = 0;
#endif /* DEBUG */
char *cur_heap = heap, *cur_entry = script, *old_entry;
/* initialization */
saved_drive = boot_drive;
saved_partition = install_partition;
current_drive = 0xFF;
errnum = 0;
/* restore memory probe state */
mbi.mem_upper = saved_mem_upper;
if (mem_map)
mbi.flags |= MB_INFO_MEM_MAP;
/* XXX evil hack !! */
bootdev = bsd_bootdev();
if (!script)
{
init_page();
init_cmdline();
}
restart:
if (script)
{
if (errnum)
{
if (fallback != -1)
return 0;
print_error();
run_cmdline = 1;
if (!have_run_cmdline)
{
have_run_cmdline = 1;
putchar('\n');
init_cmdline();
}
}
else
{
run_cmdline = 0;
/* update position in the boot script */
old_entry = cur_entry;
while (*(cur_entry++));
/* copy to work area */
bcopy(old_entry, cur_heap, ((int)cur_entry) - ((int)old_entry));
printf("%s\n", old_entry);
}
}
else
{
cur_heap[0] = 0;
print_error();
}
if (run_cmdline && get_cmdline("command> ", commands, cur_heap, 2048))
return 1;
if (strcmp("boot", cur_heap) == 0 || (script && !*cur_heap))
{
if ((type == 'f') | (type == 'n'))
bsd_boot(type, bootdev);
if (type == 'l')
linux_boot();
if (type == 'c')
{
gateA20(0);
boot_drive = saved_drive;
chain_stage1(0, BOOTSEC_LOCATION, BOOTSEC_LOCATION-16);
}
if (!type)
{
printf(" Error, cannot boot unless kernel loaded.\n");
if (fallback != -1)
return 0;
if (script)
{
printf("Press any key to continue...");
getc();
return 1;
}
else
goto restart;
}
/* this is the final possibility */
multi_boot((int)entry_addr, (int)(&mbi));
}
/* get clipped command-line */
cur_cmdline = skip_to(1, cur_heap);
cmd_len = 0;
while (cur_cmdline[cmd_len++]);
if (strcmp("chainloader", cur_heap) < 1)
{
if (open(cur_cmdline) && (read(BOOTSEC_LOCATION, SECTOR_SIZE)
== SECTOR_SIZE)
&& (*((unsigned short *) (BOOTSEC_LOCATION+BOOTSEC_SIG_OFFSET))
== BOOTSEC_SIGNATURE))
type = 'c';
else if (!errnum)
{
errnum = ERR_EXEC_FORMAT;
type = 0;
}
}
else if (strcmp("pause", cur_heap) < 1)
{
if (getc() == 27)
return 1;
}
else if (strcmp("uppermem", cur_heap) < 1)
{
if (safe_parse_maxint(&cur_cmdline, (int *)&(mbi.mem_upper)))
mbi.flags &= ~MB_INFO_MEM_MAP;
}
else if (strcmp("root", cur_heap) < 1)
{
set_device(cur_cmdline);
/* this will respond to any "rootn<XXX>" command,
but that's OK */
if (!errnum && (cur_heap[4] == 'n' || open_device()
|| errnum == ERR_FSYS_MOUNT))
{
errnum = 0;
saved_partition = current_partition;
saved_drive = current_drive;
if (cur_heap[4] != 'n')
{
/* XXX evil hack !! */
bootdev = bsd_bootdev();
print_fsys_type();
}
else
current_drive = -1;
}
}
else if (strcmp("kernel", cur_heap) < 1)
{
/* make sure it's at the beginning of the boot heap area */
bcopy(cur_heap, heap, cmd_len + (((int)cur_cmdline) - ((int)cur_heap)));
cur_cmdline = heap + (((int)cur_cmdline) - ((int)cur_heap));
cur_heap = heap;
if (type = load_image())
cur_heap = cur_cmdline + cmd_len;
}
else if (strcmp("module", cur_heap) < 1)
{
if (type == 'm')
{
#ifndef NO_DECOMPRESSION
/* this will respond to any "modulen<XXX>" command,
but that's OK */
if (cur_heap[6] = 'n')
no_decompression = 1;
#endif /* NO_DECOMPRESSION */
if (load_module())
cur_heap = cur_cmdline + cmd_len;
#ifndef NO_DECOMPRESSION
no_decompression = 0;
#endif /* NO_DECOMPRESSION */
}
else
errnum = ERR_NEED_KERNEL;
}
else if (strcmp("install", cur_heap) < 1)
{
char *stage1_file = cur_cmdline, *dest_dev, *file, *addr, *config_file;
char buffer[SECTOR_SIZE], old_sect[SECTOR_SIZE];
int i = BOOTSEC_LOCATION+STAGE1_FIRSTLIST-4, new_drive = 0xFF;
dest_dev = skip_to(0, stage1_file);
if (*dest_dev == 'd')
{
new_drive = 0;
dest_dev = skip_to(0, dest_dev);
}
file = skip_to(0, dest_dev);
addr = skip_to(0, file);
if (safe_parse_maxint(&addr, &installaddr) && open(stage1_file)
&& read((int)buffer, SECTOR_SIZE) == SECTOR_SIZE
&& set_device(dest_dev) && open_partition()
&& devread(0, 0, SECTOR_SIZE, (int)old_sect))
{
int dest_drive = current_drive, dest_geom = buf_geom;
int dest_sector = part_start, i;
#ifndef NO_DECOMPRESSION
no_decompression = 1;
#endif
/* copy possible DOS BPB, 59 bytes at byte offset 3 */
bcopy(old_sect+BOOTSEC_BPB_OFFSET, buffer+BOOTSEC_BPB_OFFSET,
BOOTSEC_BPB_LENGTH);
/* if for a hard disk, copy possible MBR/extended part table */
if ((dest_drive & 0x80) && current_partition == 0xFFFFFF)
bcopy(old_sect+BOOTSEC_PART_OFFSET, buffer+BOOTSEC_PART_OFFSET,
BOOTSEC_PART_LENGTH);
if (*((short *)(buffer+STAGE1_VER_MAJ_OFFS)) != COMPAT_VERSION
|| (*((unsigned short *) (buffer+BOOTSEC_SIG_OFFSET))
!= BOOTSEC_SIGNATURE)
|| (!(dest_drive & 0x80)
&& (*((unsigned char *) (buffer+BOOTSEC_PART_OFFSET)) == 0x80
|| buffer[BOOTSEC_PART_OFFSET] == 0)))
{
errnum = ERR_BAD_VERSION;
}
else if (open(file))
{
if (!new_drive)
new_drive = current_drive;
bcopy(buffer, (char*)BOOTSEC_LOCATION, SECTOR_SIZE);
*((unsigned char *)(BOOTSEC_LOCATION+STAGE1_FIRSTLIST))
= new_drive;
*((unsigned short *)(BOOTSEC_LOCATION+STAGE1_INSTALLADDR))
= installaddr;
i = BOOTSEC_LOCATION+STAGE1_FIRSTLIST-4;
while (*((unsigned long *)i))
{
if (i < BOOTSEC_LOCATION+STAGE1_FIRSTLIST-256
|| (*((int *)(i-4)) & 0x80000000)
|| *((unsigned short *)i) >= 0xA00
|| *((short *) (i+2)) == 0)
{
errnum = ERR_BAD_VERSION;
break;
}
*((int *)i) = 0;
*((int *)(i-4)) = 0;
i -= 8;
}
installlist = BOOTSEC_LOCATION+STAGE1_FIRSTLIST+4;
debug_fs = debug_fs_blocklist_func;
if (!errnum && read(SCRATCHADDR, SECTOR_SIZE) == SECTOR_SIZE)
{
if (*((long *)SCRATCHADDR) != 0x8070ea
|| (*((short *)(SCRATCHADDR+STAGE2_VER_MAJ_OFFS))
!= COMPAT_VERSION))
errnum = ERR_BAD_VERSION;
else
{
int write_stage2_sect = 0, stage2_sect = installsect;
char *ptr;
ptr = skip_to(0, addr);
if (*ptr == 'p')
{
write_stage2_sect++;
*((long *)(SCRATCHADDR+STAGE2_INSTALLPART))
= current_partition;
ptr = skip_to(0, ptr);
}
if (*ptr)
{
char *str
= ((char *) (SCRATCHADDR+STAGE2_VER_STR_OFFS));
write_stage2_sect++;
while (*(str++)); /* find string */
while (*(str++) = *(ptr++)); /* do copy */
}
read(0x100000, -1);
buf_track = -1;
if (!errnum
&& (biosdisk(BIOSDISK_SUBFUNC_WRITE,
dest_drive, dest_geom,
dest_sector, 1, (BOOTSEC_LOCATION>>4))
|| (write_stage2_sect
&& biosdisk(BIOSDISK_SUBFUNC_WRITE,
current_drive, buf_geom,
stage2_sect, 1, SCRATCHSEG))))
errnum = ERR_WRITE;
}
}
debug_fs = NULL;
}
#ifndef NO_DECOMPRESSION
no_decompression = 0;
#endif
}
}
#ifdef DEBUG
else if (strcmp("testload", cur_heap) < 1)
{
if (open(cur_cmdline))
{
int i;
debug_fs = debug_fs_print_func;
/*
* Perform filesystem test on the specified file.
*/
/* read whole file first */
printf("Whole file: ");
read(0x100000, -1);
/* now compare two sections of the file read differently */
for (i = 0; i < 0x10ac0; i++)
{
*((unsigned char *)(0x200000+i)) = 0;
*((unsigned char *)(0x300000+i)) = 1;
}
/* first partial read */
printf("\nPartial read 1: ");
filepos = 0;
read(0x200000, 0x7);
read(0x200007, 0x100);
read(0x200107, 0x10);
read(0x200117, 0x999);
read(0x200ab0, 0x10);
read(0x200ac0, 0x10000);
/* second partial read */
printf("\nPartial read 2: ");
filepos = 0;
read(0x300000, 0x10000);
read(0x310000, 0x10);
read(0x310010, 0x7);
read(0x310017, 0x10);
read(0x310027, 0x999);
read(0x3109c0, 0x100);
printf("\nHeader1 = 0x%x, next = 0x%x, next = 0x%x, next = 0x%x\n",
*((int *)0x200000), *((int *)0x200004), *((int *)0x200008),
*((int *)0x20000c));
printf("Header2 = 0x%x, next = 0x%x, next = 0x%x, next = 0x%x\n",
*((int *)0x300000), *((int *)0x300004), *((int *)0x300008),
*((int *)0x30000c));
for (i = 0; i < 0x10ac0 && *((unsigned char *)(0x200000+i))
== *((unsigned char *)(0x300000+i)); i++);
printf("Max is 0x10ac0: i=0x%x, filepos=0x%x\n", i, filepos);
debug_fs = NULL;
}
}
else if (strcmp("syscmd", cur_heap) < 1)
{
switch(cur_cmdline[0])
{
case 'F':
if (debug_fs)
{
debug_fs = NULL;
printf(" Filesystem tracing is now off\n");
}
else
{
debug_fs = debug_fs_print_func;
printf(" Filesystem tracing if now on\n");
}
break;
case 'R':
{
char *ptr = cur_cmdline+1;
int myaddr;
if (safe_parse_maxint(&ptr, &myaddr))
printf("0x%x: 0x%x", myaddr, *((unsigned *)myaddr));
}
break;
case 'r':
if (mptest)
{
list_regs(-1);
break;
}
case 'p':
if (mptest)
{
copy_patch_code();
break;
}
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if (mptest)
{
int j = cur_cmdline[0] - '0';
switch (cur_cmdline[1])
{
case 'i':
send_init(j);
break;
case 's':
send_startup(j);
break;
case 'r':
list_regs(j);
break;
case 'b':
boot_cpu(j);
}
break;
}
default:
printf("Bad subcommand, try again please\n");
}
}
else if (strcmp("probemps", cur_heap) == 0)
{
apic_addr = 0xFEE00000;
if (mptest = probe_mp_table())
printf("APIC test (%x), SPIV test(%x)\n",
*((volatile unsigned long *) (apic_addr+0x30)),
*((volatile unsigned long *) (apic_addr+0xf0)));
else
printf("No MPS information found\n");
}
else if (strcmp("displaymem", cur_heap) == 0)
{
if (get_eisamemsize() != -1)
printf(" EISA Memory BIOS Interface is present\n");
if (get_mem_map(SCRATCHADDR, 0) != 0 || *((int *) SCRATCHADDR) != 0)
printf(" Address Map BIOS Interface is present\n");
printf(" Lower memory: %uK, Upper memory (to first chipset hole): %uK\n",
mbi.mem_lower, mbi.mem_upper);
if (mbi.flags & MB_INFO_MEM_MAP)
{
struct AddrRangeDesc *map = (struct AddrRangeDesc *) mbi.mmap_addr;
int end_addr = mbi.mmap_addr + mbi.mmap_length;
printf(" [Address Range Descriptor entries immediately follow (values are 64-bit)]\n");
while (end_addr > (int)map)
{
char *str;
if (map->Type == MB_ARD_MEMORY)
str = "Usable RAM";
else
str = "Reserved";
printf(" %s: Base Address: 0x%x X 4GB + 0x%x,
Length: %u X 4GB + %u bytes\n",
str, map->BaseAddrHigh, map->BaseAddrLow,
map->LengthHigh, map->LengthLow);
map = ((struct AddrRangeDesc *) (((int)map) + 4 + map->size));
}
}
}
#endif /* DEBUG */
else if (strcmp("makeactive", cur_heap) == 0)
make_saved_active();
else if (*cur_heap && *cur_heap != ' ')
errnum = ERR_UNRECOGNIZED;
goto restart;
}

199
shared_src/common.c Normal file
View file

@ -0,0 +1,199 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1996 Erich Boleyn <erich@uruk.org>
*
* 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.
*/
#define _COMMON_C
#include "shared.h"
/*
* Shared BIOS/boot data.
*/
struct multiboot_info mbi;
unsigned long saved_drive;
unsigned long saved_partition;
unsigned long saved_mem_upper;
int mem_map = 0;
/*
* Error code stuff.
*/
int errnum = 0;
#ifndef NO_FANCY_STUFF
char *err_list[] =
{
0,
"Selected item won\'t fit into memory",
"Selected disk doesn\'t exist",
"Disk read error",
"Disk write error",
"Disk geometry error",
"Attempt to access block outside partition",
"Partition table invalid or corrupt",
"No such partition",
"Bad filename (must be absolute pathname or blocklist)",
"Bad file or directory type",
"File not found",
"Cannot mount selected partition",
"Inconsistent filesystem structure",
"Filesystem compatibility error, can\'t read whole file",
"Error while parsing number",
"Device string unrecognizable",
"Invalid device requested",
"Invalid or unsupported executable format",
"Loading below 1MB is not supported",
"Unsupported Multiboot features requested",
"Unknown boot failure",
"Must load Multiboot kernel before modules",
"Unrecognized command",
"Bad or incompatible header on compressed file",
"Bad or corrupt data while decompressing file",
"Bad or corrupt version of stage1/stage2",
0
};
/* static for BIOS memory map fakery */
static struct AddrRangeDesc fakemap[3] =
{
{ 20, 0, 0, 0, 0, MB_ARD_MEMORY },
{ 20, 0x100000, 0, 0, 0, MB_ARD_MEMORY },
{ 20, 0x1000000, 0, 0, 0, MB_ARD_MEMORY }
};
#endif /* NO_FANCY_STUFF */
/*
* This queries for BIOS information.
*/
void
init_bios_info(void)
{
/*
* Get information from BIOS on installed RAM.
*/
mbi.mem_lower = get_memsize(0);
mbi.mem_upper = get_memsize(1);
#ifndef NO_FANCY_STUFF
/*
* We need to call this somewhere before trying to put data
* above 1 MB, since without calling it, address line 20 will be wired
* to 0. Not too desirable.
*/
gateA20(1);
/*
* The "mem_upper" variable only recognizes upper memory in the
* first memory region. If there are multiple memory regions,
* the rest are reported to a Multiboot-compliant OS, but otherwise
* unused by GRUB.
*/
{
int cont = 0, mem1, mem2, addr;
mbi.mmap_addr = (addr = (((int) end) & ~3) + 4);
mbi.mmap_length = 0;
do
{
cont = get_mem_map(addr, cont);
if ( ! *((int *)addr) )
break;
/*
* This is to get the upper memory up to the first memory
* hole into the "mbi.mem_upper" element, for OS's that
* don't care about the memory map, but might care about
* RAM above 64MB.
*/
if (((struct AddrRangeDesc *)addr)->BaseAddrLow == 0x100000
&& ((struct AddrRangeDesc *)addr)->BaseAddrHigh == 0
&& ((struct AddrRangeDesc *)addr)->Type == MB_ARD_MEMORY)
{
/* limit to 4G, as most OS's would probably break with more */
if (!((struct AddrRangeDesc *)addr)->LengthHigh)
mbi.mem_upper = ((struct AddrRangeDesc *)addr)->LengthLow >> 10;
else
mbi.mem_upper = 0x3FBFC0; /* 4G - 1M - 64K */
}
mbi.mmap_length += *((int *)addr) + 4;
addr += *((int *)addr) + 4;
mem_map++;
}
while (cont);
if (!mem_map && (mem1 = get_eisamemsize()) != -1)
{
mem2 = mem1 >> 16;
mem1 &= 0xFFFF;
mbi.mem_upper = mem1;
if (!mem2 || (mem1 == 0x3c00))
mbi.mem_upper += (mem2 << 6);
else
{
/* XXX should I do this at all ??? */
mbi.mmap_addr = (int)fakemap;
mbi.mmap_length = sizeof(fakemap);
fakemap[0].LengthLow = (mbi.mem_lower << 10);
fakemap[1].LengthLow = (mem1 << 10);
fakemap[2].LengthLow = (mem2 << 16);
mem_map++;
}
}
}
saved_mem_upper = mbi.mem_upper;
/*
* Initialize other Multiboot Info flags.
*/
mbi.flags = MB_INFO_MEMORY | MB_INFO_CMDLINE | MB_INFO_BOOTDEV;
#endif /* NO_FANCY_STUFF */
/*
* Set boot drive and partition.
*/
saved_drive = boot_drive;
saved_partition = install_partition;
/*
* Start main routine here.
*/
cmain();
}

93
shared_src/defs.h Normal file
View file

@ -0,0 +1,93 @@
/*
* Mach Operating System
* Copyright (c) 1991,1990 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/*
* Common definitions for Berkeley Fast File System.
*/
/*
* Compatibility definitions for disk IO.
*/
/*
* Disk devices do all IO in 512-byte blocks.
*/
#define DEV_BSIZE 512
/*
* Conversion between bytes and disk blocks.
*/
#define btodb(byte_offset) ((byte_offset) >> 9)
#define dbtob(block_number) ((block_number) << 9)
/*
* Compatibility definitions for old type names.
*/
typedef unsigned char u_char; /* unsigned char */
typedef unsigned short u_short; /* unsigned short */
typedef unsigned int u_int; /* unsigned int */
typedef struct _quad_ {
unsigned int val[2]; /* 2 int values make... */
} quad; /* an 8-byte item */
typedef unsigned int time_t; /* an unsigned int */
typedef unsigned int daddr_t; /* an unsigned int */
typedef unsigned int off_t; /* another unsigned int */
typedef unsigned short uid_t;
typedef unsigned short gid_t;
typedef unsigned int ino_t;
#define NBBY 8
/*
* The file system is made out of blocks of at most MAXBSIZE units,
* with smaller units (fragments) only in the last direct block.
* MAXBSIZE primarily determines the size of buffers in the buffer
* pool. It may be made larger without any effect on existing
* file systems; however, making it smaller may make some file
* systems unmountable.
*
* Note that the disk devices are assumed to have DEV_BSIZE "sectors"
* and that fragments must be some multiple of this size.
*/
#define MAXBSIZE 8192
#define MAXFRAG 8
/*
* MAXPATHLEN defines the longest permissible path length
* after expanding symbolic links.
*
* MAXSYMLINKS defines the maximum number of symbolic links
* that may be expanded in a path name. It should be set
* high enough to allow all legitimate uses, but halt infinite
* loops reasonably quickly.
*/
#define MAXPATHLEN 1024
#define MAXSYMLINKS 8

142
shared_src/dir.h Normal file
View file

@ -0,0 +1,142 @@
/*
* Mach Operating System
* Copyright (c) 1991,1990 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/*
* Copyright (c) 1982, 1986, 1989 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* @(#)dir.h 7.6 (Berkeley) 5/9/89
*/
#ifndef _BOOT_UFS_DIR_H_
#define _BOOT_UFS_DIR_H_
/*
* A directory consists of some number of blocks of DIRBLKSIZ
* bytes, where DIRBLKSIZ is chosen such that it can be transferred
* to disk in a single atomic operation (e.g. 512 bytes on most machines).
*
* Each DIRBLKSIZ byte block contains some number of directory entry
* structures, which are of variable length. Each directory entry has
* a struct direct at the front of it, containing its inode number,
* the length of the entry, and the length of the name contained in
* the entry. These are followed by the name padded to a 4 byte boundary
* with null bytes. All names are guaranteed null terminated.
* The maximum length of a name in a directory is MAXNAMLEN.
*
* The macro DIRSIZ(dp) gives the amount of space required to represent
* a directory entry. Free space in a directory is represented by
* entries which have dp->d_reclen > DIRSIZ(dp). All DIRBLKSIZ bytes
* in a directory block are claimed by the directory entries. This
* usually results in the last entry in a directory having a large
* dp->d_reclen. When entries are deleted from a directory, the
* space is returned to the previous entry in the same directory
* block by increasing its dp->d_reclen. If the first entry of
* a directory block is free, then its dp->d_ino is set to 0.
* Entries other than the first in a directory do not normally have
* dp->d_ino set to 0.
*/
#define DIRBLKSIZ DEV_BSIZE
#define MAXNAMLEN 255
struct direct {
u_int d_ino; /* inode number of entry */
u_short d_reclen; /* length of this record */
u_short d_namlen; /* length of string in d_name */
char d_name[MAXNAMLEN + 1]; /* name with length <= MAXNAMLEN */
};
/*
* The DIRSIZ macro gives the minimum record length which will hold
* the directory entry. This requires the amount of space in struct direct
* without the d_name field, plus enough space for the name with a terminating
* null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
*/
#undef DIRSIZ
#define DIRSIZ(dp) \
((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
#ifdef KERNEL
/*
* Template for manipulating directories.
* Should use struct direct's, but the name field
* is MAXNAMLEN - 1, and this just won't do.
*/
struct dirtemplate {
u_int dot_ino;
short dot_reclen;
short dot_namlen;
char dot_name[4]; /* must be multiple of 4 */
u_int dotdot_ino;
short dotdot_reclen;
short dotdot_namlen;
char dotdot_name[4]; /* ditto */
};
#endif
/*
* The following information should be obtained from <dirent.h>
* and is provided solely (and temporarily) for backward compatibility.
*/
#ifndef KERNEL
#define d_fileno d_ino /* compatibility with POSIX */
#ifndef DEV_BSIZE
#define DEV_BSIZE 512
#endif
/*
* Definitions for library routines operating on directories.
*/
typedef struct _dirdesc {
int dd_fd;
int dd_loc;
int dd_size;
char dd_buf[DIRBLKSIZ];
} DIR;
#define dirfd(dirp) ((dirp)->dd_fd)
#ifndef NULL
#define NULL 0
#endif
extern DIR *opendir();
extern struct direct *readdir();
extern int telldir();
extern void seekdir();
#define rewinddir(dirp) seekdir((dirp), (long)0)
extern void closedir();
#endif /* not KERNEL */
#endif /* _BOOT_UFS_DIR_H_ */

101
shared_src/disk_inode.h Normal file
View file

@ -0,0 +1,101 @@
/*
* Mach Operating System
* Copyright (c) 1991,1990 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/*
* Copyright (c) 1982, 1989 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* @(#)inode.h 7.5 (Berkeley) 7/3/89
*/
#ifndef _BOOT_UFS_DISK_INODE_H_
#define _BOOT_UFS_DISK_INODE_H_
/*
* The I node is the focus of all file activity in the BSD Fast File System.
* There is a unique inode allocated for each active file,
* each current directory, each mounted-on file, text file, and the root.
* An inode is 'named' by its dev/inumber pair. (iget/iget.c)
* Data in icommon is read in from permanent inode on volume.
*/
#define FFS_NDADDR 12 /* direct addresses in inode */
#define FFS_NIADDR 3 /* indirect addresses in inode */
#define FFS_MAX_FASTLINK_SIZE ((FFS_NDADDR + FFS_NIADDR) * sizeof(daddr_t))
struct icommon {
u_short ic_mode; /* 0: mode and type of file */
short ic_nlink; /* 2: number of links to file */
uid_t ic_uid; /* 4: owner's user id */
gid_t ic_gid; /* 6: owner's group id */
quad ic_size; /* 8: number of bytes in file */
time_t ic_atime; /* 16: time last accessed */
int ic_atspare;
time_t ic_mtime; /* 24: time last modified */
int ic_mtspare;
time_t ic_ctime; /* 32: last time inode changed */
int ic_ctspare;
union {
struct {
daddr_t Mb_db[FFS_NDADDR]; /* 40: disk block addresses */
daddr_t Mb_ib[FFS_NIADDR]; /* 88: indirect blocks */
} ic_Mb;
char ic_Msymlink[FFS_MAX_FASTLINK_SIZE];
/* 40: symbolic link name */
} ic_Mun;
#define ic_db ic_Mun.ic_Mb.Mb_db
#define ic_ib ic_Mun.ic_Mb.Mb_ib
#define ic_symlink ic_Mun.ic_Msymlink
int ic_flags; /* 100: status, currently unused */
int ic_blocks; /* 104: blocks actually held */
int ic_gen; /* 108: generation number */
int ic_spare[4]; /* 112: reserved, currently unused */
} i_ic;
/*
* Same structure, but on disk.
*/
struct dinode {
union {
struct icommon di_com;
char di_char[128];
} di_un;
};
#define di_ic di_un.di_com
#endif /* _BOOT_UFS_DISK_INODE_H_ */

101
shared_src/disk_inode_ffs.h Normal file
View file

@ -0,0 +1,101 @@
/*
* Mach Operating System
* Copyright (c) 1991,1990 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/*
* Copyright (c) 1982, 1989 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* @(#)inode.h 7.5 (Berkeley) 7/3/89
*/
#ifndef _BOOT_UFS_DISK_INODE_FFS_H_
#define _BOOT_UFS_DISK_INODE_FFS_H_
#define NDADDR FFS_NDADDR
#define NIADDR FFS_NIADDR
#define MAX_FASTLINK_SIZE FFS_MAX_FASTLINK_SIZE
#define IC_FASTLINK 0x0001 /* Symbolic link in inode */
#define i_mode ic_mode
#define i_nlink ic_nlink
#define i_uid ic_uid
#define i_gid ic_gid
#if BYTE_MSF
#define i_size ic_size.val[1]
#else /* BYTE_LSF */
#define i_size ic_size.val[0]
#endif
#define i_db ic_db
#define i_ib ic_ib
#define i_atime ic_atime
#define i_mtime ic_mtime
#define i_ctime ic_ctime
#define i_blocks ic_blocks
#define i_rdev ic_db[0]
#define i_symlink ic_symlink
#define i_flags ic_flags
#define i_gen ic_gen
/* modes */
#define IFMT 0xf000 /* type of file */
#define IFCHR 0x2000 /* character special */
#define IFDIR 0x4000 /* directory */
#define IFBLK 0x6000 /* block special */
#define IFREG 0x8000 /* regular */
#define IFLNK 0xa000 /* symbolic link */
#define IFSOCK 0xc000 /* socket */
#define ISUID 0x0800 /* set user id on execution */
#define ISGID 0x0400 /* set group id on execution */
#define ISVTX 0x0200 /* save swapped text even after use */
#define IREAD 0x0100 /* read, write, execute permissions */
#define IWRITE 0x0080
#define IEXEC 0x0040
#ifdef EEK
#define f_fs u.ffs.ffs_fs
#define i_ic u.ffs.ffs_ic
#define f_nindir u.ffs.ffs_nindir
#define f_blk u.ffs.ffs_blk
#define f_blksize u.ffs.ffs_blksize
#define f_blkno u.ffs.ffs_blkno
#endif /* EEK */
#endif _BOOT_UFS_DISK_INODE_FFS_H_

1056
shared_src/disk_io.c Normal file

File diff suppressed because it is too large Load diff

114
shared_src/fat.h Normal file
View file

@ -0,0 +1,114 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1996 Erich Boleyn <erich@uruk.org>
*
* 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.
*/
/*
* Defines for the FAT BIOS Parameter Block (embedded in the first block
* of the partition.
*/
#define FAT_BPB_SIGNATURE 0x29
/* is checking for this signature thing even valid? */
#define FAT_BPB_CHECK_SIG(bpb) \
(*((unsigned char *) (((int)bpb) + 38)) == FAT_BPB_SIGNATURE)
#define FAT_BPB_NUM_SECTORS(bpb) \
( *((unsigned short *) (((int)bpb) + 19)) ? \
*((unsigned short *) (((int)bpb) + 19)) : \
*((unsigned long *) (((int)bpb) + 32)) )
#define FAT_BPB_BYTES_PER_SECTOR(bpb) \
(*((unsigned short *) (((int)bpb) + 11)))
#define FAT_BPB_SECT_PER_CLUST(bpb) \
(*((unsigned char *) (((int)bpb) + 13)))
#define FAT_BPB_NUM_FAT(bpb) \
(*((unsigned char *) (((int)bpb) + 16)))
#define FAT_BPB_RESERVED_SECTORS(bpb) \
(*((unsigned short *) (((int)bpb) + 14)))
#define FAT_BPB_FAT_SECTORS(bpb) \
(*((unsigned short *) (((int)bpb) + 22)))
#define FAT_BPB_FAT_START(bpb) FAT_BPB_RESERVED_SECTORS(bpb)
/*
* This appears to be a MAJOR kludge!! Don't use it if possible...
*/
#define FAT_BPB_HIDDEN_SECTORS(bpb) \
(*((unsigned long *) (((int)bpb) + 28)))
#define FAT_BPB_ROOT_DIR_START(bpb) \
( FAT_BPB_NUM_FAT(bpb) * FAT_BPB_FAT_SECTORS(bpb) \
+ FAT_BPB_FAT_START(bpb) )
#define FAT_BPB_ROOT_DIR_LENGTH(bpb) \
( (*((unsigned short *) (((int)bpb) + 17)) + 0xF) >> 4 )
#define FAT_BPB_DATA_OFFSET(bpb) \
( FAT_BPB_ROOT_DIR_START(bpb) + FAT_BPB_ROOT_DIR_LENGTH(bpb) )
#define FAT_BPB_NUM_CLUST(bpb) \
( ( FAT_BPB_NUM_SECTORS(bpb) - FAT_BPB_DATA_OFFSET(bpb) ) \
/ FAT_BPB_SECT_PER_CLUST(bpb) )
/*
* Defines minimum disk size to be considered a FAT partition
*/
#define FAT_MIN_NUM_SECTORS 720 /* 360 K disk */
/*
* Defines how to differentiate a 12-bit and 16-bit FAT.
*/
#define FAT_MAX_12BIT_CLUST 4087 /* 4085 + 2 */
#define FAT_BPB_FLOPPY_NUM_SECTORS(bpb) \
( *((unsigned short *) (((int)bpb) + 19)) \
&& !*((unsigned long *) (((int)bpb) + 32)) \
&& *((unsigned short *) (((int)bpb) + 19)) >= FAT_MIN_NUM_SECTORS \
&& ((*((unsigned short *) (((int)bpb) + 19)) - FAT_BPB_DATA_OFFSET(bpb)) \
/ FAT_BPB_SECT_PER_CLUST(bpb)) < (FAT_BPB_FAT_SECTORS(bpb) * 342) )
/*
* Defines for the file "attribute" byte
*/
#define FAT_ATTRIB_OK_MASK 0x37
#define FAT_ATTRIB_NOT_OK_MASK 0xC8
#define FAT_ATTRIB_DIR 0x10
/*
* Defines for FAT directory entries
*/
#define FAT_DIRENTRY_LENGTH 32
#define FAT_DIRENTRY_ATTRIB(entry) \
(*((unsigned char *) (entry+11)))
#define FAT_DIRENTRY_VALID(entry) \
( ((*((unsigned char *) entry)) != 0) \
& ((*((unsigned char *) entry)) != 0xE5) \
& !(FAT_DIRENTRY_ATTRIB(entry) & FAT_ATTRIB_NOT_OK_MASK) )
#define FAT_DIRENTRY_FIRST_CLUSTER(entry) \
(*((unsigned short *) (entry+26)))
#define FAT_DIRENTRY_FILELENGTH(entry) \
(*((unsigned long *) (entry+28)))

119
shared_src/filesys.h Normal file
View file

@ -0,0 +1,119 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1996 Erich Boleyn <erich@uruk.org>
*
* 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.
*/
#include "pc_slice.h"
#define SECTORS(geom) ( (geom) & 0xFF )
#define HEADS(geom) ( ( ( (geom) >> 8 ) & 0xFF ) + 1 )
#define CYLINDERS(geom) ( ( ( (geom) >> 16 ) & 0x3FF ) + 1 )
/*
* Default to all functioning filesystems enabled
*/
#if !( defined(FSYS_FFS) || defined(FSYS_FAT) || defined(FSYS_EXT2FS) )
#define FSYS_FFS
#define FSYS_FAT
#define FSYS_EXT2FS
#endif
#ifdef FSYS_FFS
#define FSYS_FFS_NUM 1
int ffs_mount(void);
int ffs_read(int addr, int len);
int ffs_dir(char *dirname);
#else
#define FSYS_FFS_NUM 0
#endif
#ifdef FSYS_FAT
#define FSYS_FAT_NUM 1
int fat_mount(void);
/* XX FAT filesystem uses block filesystem code for read! */
int fat_dir(char *dirname);
#ifdef NO_BLOCK_FILES
#undef NO_BLOCK_FILES
#endif /* NO_BLOCK_FILES */
#else
#define FSYS_FAT_NUM 0
#endif
#ifdef FSYS_EXT2FS
#define FSYS_EXT2FS_NUM 1
int ext2fs_mount(void);
int ext2fs_read(int addr, int len);
int ext2fs_dir(char *dirname);
#else
#define FSYS_EXT2FS_NUM 0
#endif
#ifndef NUM_FSYS
#define NUM_FSYS ( FSYS_FFS_NUM + FSYS_FAT_NUM + FSYS_EXT2FS_NUM )
#endif
/* defines for the block filesystem info area */
#ifndef NO_BLOCK_FILES
#define BLK_CUR_FILEPOS (*((int*)FSYS_BUF))
#define BLK_CUR_BLKLIST (*((int*)(FSYS_BUF+4)))
#define BLK_CUR_BLKNUM (*((int*)(FSYS_BUF+8)))
#define BLK_MAX_ADDR (FSYS_BUF+0x7FF9)
#define BLK_BLKSTART(l) (*((int*)l))
#define BLK_BLKLENGTH(l) (*((int*)(l+4)))
#define BLK_BLKLIST_START (FSYS_BUF+12)
#define BLK_BLKLIST_INC_VAL 8
#endif /* NO_BLOCK_FILES */
/* this next part is pretty ugly, but it keeps it in one place! */
struct fsys_entry
{
char *name;
int (*mount_func)(void);
int (*read_func)(int addr, int len);
int (*dir_func)(char *dirname);
};
#ifndef _DISK_IO_C
extern int fsmax;
extern int print_possibilities;
extern struct fsys_entry fsys_table[NUM_FSYS+1];
#else
int fsmax;
int print_possibilities;
struct fsys_entry fsys_table[NUM_FSYS+1] =
{
#ifdef FSYS_FAT
{ "fat", fat_mount, 0, fat_dir },
#endif
#ifdef FSYS_EXT2FS
{ "ext2fs", ext2fs_mount, ext2fs_read, ext2fs_dir },
#endif
/* XX FFS should come last as it's superblock is commonly crossing tracks
on floppies from track 1 to 2, while others only use 1. */
#ifdef FSYS_FFS
{ "ffs", ffs_mount, ffs_read, ffs_dir },
#endif
{ 0, 0, 0, 0 }
};
#endif

90
shared_src/freebsd.h Normal file
View file

@ -0,0 +1,90 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1996 Erich Boleyn <erich@uruk.org>
*
* 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.
*/
/* command-line parameter defines */
#define RB_ASKNAME 0x01 /* ask for file name to reboot from */
#define RB_SINGLE 0x02 /* reboot to single user only */
#define RB_NOSYNC 0x04 /* dont sync before reboot */
#define RB_HALT 0x08 /* don't reboot, just halt */
#define RB_INITNAME 0x10 /* name given for /etc/init (unused) */
#define RB_DFLTROOT 0x20 /* use compiled-in rootdev */
#define RB_KDB 0x40 /* give control to kernel debugger */
#define RB_RDONLY 0x80 /* mount root fs read-only */
#define RB_DUMP 0x100 /* dump kernel memory before reboot */
#define RB_MINIROOT 0x200 /* mini-root present in memory at boot time */
#define RB_CONFIG 0x400 /* invoke user configuration routing */
#define RB_VERBOSE 0x800 /* print all potentially useful info */
#define RB_SERIAL 0x1000 /* user serial port as console */
#define RB_CDROM 0x2000 /* use cdrom as root */
#define RB_BOOTINFO 0x80000000 /* have `struct bootinfo *' arg */
/*
* Constants for converting boot-style device number to type,
* adaptor (uba, mba, etc), unit number and partition number.
* Type (== major device number) is in the low byte
* for backward compatibility. Except for that of the "magic
* number", each mask applies to the shifted value.
* Format:
* (4) (4) (4) (4) (8) (8)
* --------------------------------
* |MA | AD| CT| UN| PART | TYPE |
* --------------------------------
*/
#define B_ADAPTORSHIFT 24
#define B_CONTROLLERSHIFT 20
#define B_UNITSHIFT 16
#define B_PARTITIONSHIFT 8
#define B_TYPESHIFT 0
#define B_DEVMAGIC ((unsigned long)0xa0000000)
#define MAKEBOOTDEV(type, adaptor, controller, unit, partition) \
(((type) << B_TYPESHIFT) | ((adaptor) << B_ADAPTORSHIFT) | \
((controller) << B_CONTROLLERSHIFT) | ((unit) << B_UNITSHIFT) | \
((partition) << B_PARTITIONSHIFT) | B_DEVMAGIC)
/* Only change the version number if you break compatibility. */
#define BOOTINFO_VERSION 1
#define N_BIOS_GEOM 8
/*
* A zero bootinfo field often means that there is no info available.
* Flags are used to indicate the validity of fields where zero is a
* normal value.
*/
struct bootinfo {
unsigned int bi_version;
unsigned char *bi_kernelname;
struct nfs_diskless *bi_nfs_diskless;
/* End of fields that are always present. */
#define bi_endcommon bi_n_bios_used
unsigned int bi_n_bios_used;
unsigned long bi_bios_geom[N_BIOS_GEOM];
unsigned int bi_size;
unsigned char bi_memsizes_valid;
unsigned char bi_pad[3];
unsigned long bi_basemem;
unsigned long bi_extmem;
unsigned long bi_symtab;
unsigned long bi_esymtab;
};

455
shared_src/fs.h Normal file
View file

@ -0,0 +1,455 @@
/*
* Mach Operating System
* Copyright (c) 1991,1990 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/*
* Copyright (c) 1982, 1986 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* @(#)fs.h 7.7 (Berkeley) 5/9/89
*/
/*
* Each disk drive contains some number of file systems.
* A file system consists of a number of cylinder groups.
* Each cylinder group has inodes and data.
*
* A file system is described by its super-block, which in turn
* describes the cylinder groups. The super-block is critical
* data and is replicated in each cylinder group to protect against
* catastrophic loss. This is done at `newfs' time and the critical
* super-block data does not change, so the copies need not be
* referenced further unless disaster strikes.
*
* For file system fs, the offsets of the various blocks of interest
* are given in the super block as:
* [fs->fs_sblkno] Super-block
* [fs->fs_cblkno] Cylinder group block
* [fs->fs_iblkno] Inode blocks
* [fs->fs_dblkno] Data blocks
* The beginning of cylinder group cg in fs, is given by
* the ``cgbase(fs, cg)'' macro.
*
* The first boot and super blocks are given in absolute disk addresses.
* The byte-offset forms are preferred, as they don't imply a sector size.
*/
#define BBSIZE 8192
#define SBSIZE 8192
#define BBOFF ((off_t)(0))
#define SBOFF ((off_t)(BBOFF + BBSIZE))
#define BBLOCK ((daddr_t)(0))
#define SBLOCK ((daddr_t)(BBLOCK + BBSIZE / DEV_BSIZE))
/*
* Addresses stored in inodes are capable of addressing fragments
* of `blocks'. File system blocks of at most size MAXBSIZE can
* be optionally broken into 2, 4, or 8 pieces, each of which is
* addressible; these pieces may be DEV_BSIZE, or some multiple of
* a DEV_BSIZE unit.
*
* Large files consist of exclusively large data blocks. To avoid
* undue wasted disk space, the last data block of a small file may be
* allocated as only as many fragments of a large block as are
* necessary. The file system format retains only a single pointer
* to such a fragment, which is a piece of a single large block that
* has been divided. The size of such a fragment is determinable from
* information in the inode, using the ``blksize(fs, ip, lbn)'' macro.
*
* The file system records space availability at the fragment level;
* to determine block availability, aligned fragments are examined.
*
* The root inode is the root of the file system.
* Inode 0 can't be used for normal purposes and
* historically bad blocks were linked to inode 1,
* thus the root inode is 2. (inode 1 is no longer used for
* this purpose, however numerous dump tapes make this
* assumption, so we are stuck with it)
*/
#define ROOTINO ((ino_t)2) /* i number of all roots */
/*
* MINBSIZE is the smallest allowable block size.
* In order to insure that it is possible to create files of size
* 2^32 with only two levels of indirection, MINBSIZE is set to 4096.
* MINBSIZE must be big enough to hold a cylinder group block,
* thus changes to (struct cg) must keep its size within MINBSIZE.
* Note that super blocks are always of size SBSIZE,
* and that both SBSIZE and MAXBSIZE must be >= MINBSIZE.
*/
#define MINBSIZE 4096
/*
* The path name on which the file system is mounted is maintained
* in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in
* the super block for this name.
* The limit on the amount of summary information per file system
* is defined by MAXCSBUFS. It is currently parameterized for a
* maximum of two million cylinders.
*/
#define MAXMNTLEN 512
#define MAXCSBUFS 32
/*
* Per cylinder group information; summarized in blocks allocated
* from first cylinder group data blocks. These blocks have to be
* read in from fs_csaddr (size fs_cssize) in addition to the
* super block.
*
* N.B. sizeof(struct csum) must be a power of two in order for
* the ``fs_cs'' macro to work (see below).
*/
struct csum {
int cs_ndir; /* number of directories */
int cs_nbfree; /* number of free blocks */
int cs_nifree; /* number of free inodes */
int cs_nffree; /* number of free frags */
};
/*
* Super block for a file system.
*/
#define FS_MAGIC 0x011954
struct fs
{
int xxx1; /* struct fs *fs_link;*/
int xxx2; /* struct fs *fs_rlink;*/
daddr_t fs_sblkno; /* addr of super-block in filesys */
daddr_t fs_cblkno; /* offset of cyl-block in filesys */
daddr_t fs_iblkno; /* offset of inode-blocks in filesys */
daddr_t fs_dblkno; /* offset of first data after cg */
int fs_cgoffset; /* cylinder group offset in cylinder */
int fs_cgmask; /* used to calc mod fs_ntrak */
time_t fs_time; /* last time written */
int fs_size; /* number of blocks in fs */
int fs_dsize; /* number of data blocks in fs */
int fs_ncg; /* number of cylinder groups */
int fs_bsize; /* size of basic blocks in fs */
int fs_fsize; /* size of frag blocks in fs */
int fs_frag; /* number of frags in a block in fs */
/* these are configuration parameters */
int fs_minfree; /* minimum percentage of free blocks */
int fs_rotdelay; /* num of ms for optimal next block */
int fs_rps; /* disk revolutions per second */
/* these fields can be computed from the others */
int fs_bmask; /* ``blkoff'' calc of blk offsets */
int fs_fmask; /* ``fragoff'' calc of frag offsets */
int fs_bshift; /* ``lblkno'' calc of logical blkno */
int fs_fshift; /* ``numfrags'' calc number of frags */
/* these are configuration parameters */
int fs_maxcontig; /* max number of contiguous blks */
int fs_maxbpg; /* max number of blks per cyl group */
/* these fields can be computed from the others */
int fs_fragshift; /* block to frag shift */
int fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */
int fs_sbsize; /* actual size of super block */
int fs_csmask; /* csum block offset */
int fs_csshift; /* csum block number */
int fs_nindir; /* value of NINDIR */
int fs_inopb; /* value of INOPB */
int fs_nspf; /* value of NSPF */
/* yet another configuration parameter */
int fs_optim; /* optimization preference, see below */
/* these fields are derived from the hardware */
int fs_npsect; /* # sectors/track including spares */
int fs_interleave; /* hardware sector interleave */
int fs_trackskew; /* sector 0 skew, per track */
int fs_headswitch; /* head switch time, usec */
int fs_trkseek; /* track-to-track seek, usec */
/* sizes determined by number of cylinder groups and their sizes */
daddr_t fs_csaddr; /* blk addr of cyl grp summary area */
int fs_cssize; /* size of cyl grp summary area */
int fs_cgsize; /* cylinder group size */
/* these fields are derived from the hardware */
int fs_ntrak; /* tracks per cylinder */
int fs_nsect; /* sectors per track */
int fs_spc; /* sectors per cylinder */
/* this comes from the disk driver partitioning */
int fs_ncyl; /* cylinders in file system */
/* these fields can be computed from the others */
int fs_cpg; /* cylinders per group */
int fs_ipg; /* inodes per group */
int fs_fpg; /* blocks per group * fs_frag */
/* this data must be re-computed after crashes */
struct csum fs_cstotal; /* cylinder summary information */
/* these fields are cleared at mount time */
char fs_fmod; /* super block modified flag */
char fs_clean; /* file system is clean flag */
char fs_ronly; /* mounted read-only flag */
char fs_flags; /* currently unused flag */
char fs_fsmnt[MAXMNTLEN]; /* name mounted on */
/* these fields retain the current block allocation info */
int fs_cgrotor; /* last cg searched */
#if 1
int was_fs_csp[MAXCSBUFS];
#else
struct csum *fs_csp[MAXCSBUFS];/* list of fs_cs info buffers */
#endif
int fs_cpc; /* cyl per cycle in postbl */
short fs_opostbl[16][8]; /* old rotation block list head */
long fs_sparecon[50]; /* reserved for future constants */
long fs_contigsumsize; /* size of cluster summary array */
long fs_maxsymlinklen; /* max length of an internal symlink */
long fs_inodefmt; /* format of on-disk inodes */
quad fs_maxfilesize; /* maximum representable file size */
quad fs_qbmask; /* ~fs_bmask - for use with quad size */
quad fs_qfmask; /* ~fs_fmask - for use with quad size */
long fs_state; /* validate fs_clean field */
int fs_postblformat; /* format of positional layout tables */
int fs_nrpos; /* number of rotaional positions */
int fs_postbloff; /* (short) rotation block list head */
int fs_rotbloff; /* (u_char) blocks for each rotation */
int fs_magic; /* magic number */
u_char fs_space[1]; /* list of blocks for each rotation */
/* actually longer */
};
/*
* Preference for optimization.
*/
#define FS_OPTTIME 0 /* minimize allocation time */
#define FS_OPTSPACE 1 /* minimize disk fragmentation */
/*
* Rotational layout table format types
*/
#define FS_42POSTBLFMT -1 /* 4.2BSD rotational table format */
#define FS_DYNAMICPOSTBLFMT 1 /* dynamic rotational table format */
/*
* Macros for access to superblock array structures
*/
#define fs_postbl(fs, cylno) \
(((fs)->fs_postblformat == FS_42POSTBLFMT) \
? ((fs)->fs_opostbl[cylno]) \
: ((short *)((char *)(fs) + (fs)->fs_postbloff) + (cylno) * (fs)->fs_nrpos))
#define fs_rotbl(fs) \
(((fs)->fs_postblformat == FS_42POSTBLFMT) \
? ((fs)->fs_space) \
: ((u_char *)((char *)(fs) + (fs)->fs_rotbloff)))
/*
* Convert cylinder group to base address of its global summary info.
*
* N.B. This macro assumes that sizeof(struct csum) is a power of two.
*/
#define fs_cs(fs, indx) \
fs_csp[(indx) >> (fs)->fs_csshift][(indx) & ~(fs)->fs_csmask]
/*
* Cylinder group block for a file system.
*/
#define CG_MAGIC 0x090255
struct cg {
int xxx1; /* struct cg *cg_link;*/
int cg_magic; /* magic number */
time_t cg_time; /* time last written */
int cg_cgx; /* we are the cgx'th cylinder group */
short cg_ncyl; /* number of cyl's this cg */
short cg_niblk; /* number of inode blocks this cg */
int cg_ndblk; /* number of data blocks this cg */
struct csum cg_cs; /* cylinder summary information */
int cg_rotor; /* position of last used block */
int cg_frotor; /* position of last used frag */
int cg_irotor; /* position of last used inode */
int cg_frsum[MAXFRAG]; /* counts of available frags */
int cg_btotoff; /* (long) block totals per cylinder */
int cg_boff; /* (short) free block positions */
int cg_iusedoff; /* (char) used inode map */
int cg_freeoff; /* (u_char) free block map */
int cg_nextfreeoff; /* (u_char) next available space */
int cg_sparecon[16]; /* reserved for future use */
u_char cg_space[1]; /* space for cylinder group maps */
/* actually longer */
};
/*
* Macros for access to cylinder group array structures
*/
#define cg_blktot(cgp) \
(((cgp)->cg_magic != CG_MAGIC) \
? (((struct ocg *)(cgp))->cg_btot) \
: ((int *)((char *)(cgp) + (cgp)->cg_btotoff)))
#define cg_blks(fs, cgp, cylno) \
(((cgp)->cg_magic != CG_MAGIC) \
? (((struct ocg *)(cgp))->cg_b[cylno]) \
: ((short *)((char *)(cgp) + (cgp)->cg_boff) + (cylno) * (fs)->fs_nrpos))
#define cg_inosused(cgp) \
(((cgp)->cg_magic != CG_MAGIC) \
? (((struct ocg *)(cgp))->cg_iused) \
: ((char *)((char *)(cgp) + (cgp)->cg_iusedoff)))
#define cg_blksfree(cgp) \
(((cgp)->cg_magic != CG_MAGIC) \
? (((struct ocg *)(cgp))->cg_free) \
: ((u_char *)((char *)(cgp) + (cgp)->cg_freeoff)))
#define cg_chkmagic(cgp) \
((cgp)->cg_magic == CG_MAGIC || ((struct ocg *)(cgp))->cg_magic == CG_MAGIC)
/*
* The following structure is defined
* for compatibility with old file systems.
*/
struct ocg {
int xxx1; /* struct ocg *cg_link;*/
int xxx2; /* struct ocg *cg_rlink;*/
time_t cg_time; /* time last written */
int cg_cgx; /* we are the cgx'th cylinder group */
short cg_ncyl; /* number of cyl's this cg */
short cg_niblk; /* number of inode blocks this cg */
int cg_ndblk; /* number of data blocks this cg */
struct csum cg_cs; /* cylinder summary information */
int cg_rotor; /* position of last used block */
int cg_frotor; /* position of last used frag */
int cg_irotor; /* position of last used inode */
int cg_frsum[8]; /* counts of available frags */
int cg_btot[32]; /* block totals per cylinder */
short cg_b[32][8]; /* positions of free blocks */
char cg_iused[256]; /* used inode map */
int cg_magic; /* magic number */
u_char cg_free[1]; /* free block map */
/* actually longer */
};
/*
* Turn file system block numbers into disk block addresses.
* This maps file system blocks to device size blocks.
*/
#define fsbtodb(fs, b) ((b) << (fs)->fs_fsbtodb)
#define dbtofsb(fs, b) ((b) >> (fs)->fs_fsbtodb)
/*
* Cylinder group macros to locate things in cylinder groups.
* They calc file system addresses of cylinder group data structures.
*/
#define cgbase(fs, c) ((daddr_t)((fs)->fs_fpg * (c)))
#define cgstart(fs, c) \
(cgbase(fs, c) + (fs)->fs_cgoffset * ((c) & ~((fs)->fs_cgmask)))
#define cgsblock(fs, c) (cgstart(fs, c) + (fs)->fs_sblkno) /* super blk */
#define cgtod(fs, c) (cgstart(fs, c) + (fs)->fs_cblkno) /* cg block */
#define cgimin(fs, c) (cgstart(fs, c) + (fs)->fs_iblkno) /* inode blk */
#define cgdmin(fs, c) (cgstart(fs, c) + (fs)->fs_dblkno) /* 1st data */
/*
* Macros for handling inode numbers:
* inode number to file system block offset.
* inode number to cylinder group number.
* inode number to file system block address.
*/
#define itoo(fs, x) ((x) % INOPB(fs))
#define itog(fs, x) ((x) / (fs)->fs_ipg)
#define itod(fs, x) \
((daddr_t)(cgimin(fs, itog(fs, x)) + \
(blkstofrags((fs), (((x) % (fs)->fs_ipg) / INOPB(fs))))))
/*
* Give cylinder group number for a file system block.
* Give cylinder group block number for a file system block.
*/
#define dtog(fs, d) ((d) / (fs)->fs_fpg)
#define dtogd(fs, d) ((d) % (fs)->fs_fpg)
/*
* Extract the bits for a block from a map.
* Compute the cylinder and rotational position of a cyl block addr.
*/
#define blkmap(fs, map, loc) \
(((map)[(loc) / NBBY] >> ((loc) % NBBY)) & (0xff >> (NBBY - (fs)->fs_frag)))
#define cbtocylno(fs, bno) \
((bno) * NSPF(fs) / (fs)->fs_spc)
#define cbtorpos(fs, bno) \
(((bno) * NSPF(fs) % (fs)->fs_spc / (fs)->fs_nsect * (fs)->fs_trackskew + \
(bno) * NSPF(fs) % (fs)->fs_spc % (fs)->fs_nsect * (fs)->fs_interleave) % \
(fs)->fs_nsect * (fs)->fs_nrpos / (fs)->fs_npsect)
/*
* The following macros optimize certain frequently calculated
* quantities by using shifts and masks in place of divisions
* modulos and multiplications.
*/
#define blkoff(fs, loc) /* calculates (loc % fs->fs_bsize) */ \
((loc) & ~(fs)->fs_bmask)
#define fragoff(fs, loc) /* calculates (loc % fs->fs_fsize) */ \
((loc) & ~(fs)->fs_fmask)
#define lblkno(fs, loc) /* calculates (loc / fs->fs_bsize) */ \
((loc) >> (fs)->fs_bshift)
#define numfrags(fs, loc) /* calculates (loc / fs->fs_fsize) */ \
((loc) >> (fs)->fs_fshift)
#define blkroundup(fs, size) /* calculates roundup(size, fs->fs_bsize) */ \
(((size) + (fs)->fs_bsize - 1) & (fs)->fs_bmask)
#define fragroundup(fs, size) /* calculates roundup(size, fs->fs_fsize) */ \
(((size) + (fs)->fs_fsize - 1) & (fs)->fs_fmask)
#define fragstoblks(fs, frags) /* calculates (frags / fs->fs_frag) */ \
((frags) >> (fs)->fs_fragshift)
#define blkstofrags(fs, blks) /* calculates (blks * fs->fs_frag) */ \
((blks) << (fs)->fs_fragshift)
#define fragnum(fs, fsb) /* calculates (fsb % fs->fs_frag) */ \
((fsb) & ((fs)->fs_frag - 1))
#define blknum(fs, fsb) /* calculates rounddown(fsb, fs->fs_frag) */ \
((fsb) &~ ((fs)->fs_frag - 1))
/*
* Determine the number of available frags given a
* percentage to hold in reserve
*/
#define freespace(fs, percentreserved) \
(blkstofrags((fs), (fs)->fs_cstotal.cs_nbfree) + \
(fs)->fs_cstotal.cs_nffree - ((fs)->fs_dsize * (percentreserved) / 100))
/*
* Determining the size of a file block in the file system.
*/
#define blksize(fs, ip, lbn) \
(((lbn) >= NDADDR || (ip)->i_size >= ((lbn) + 1) << (fs)->fs_bshift) \
? (fs)->fs_bsize \
: (fragroundup(fs, blkoff(fs, (ip)->i_size))))
#define dblksize(fs, dip, lbn) \
(((lbn) >= NDADDR || (dip)->di_size >= ((lbn) + 1) << (fs)->fs_bshift) \
? (fs)->fs_bsize \
: (fragroundup(fs, blkoff(fs, (dip)->di_size))))
/*
* Number of disk sectors per block; assumes DEV_BSIZE byte sector size.
*/
#define NSPB(fs) ((fs)->fs_nspf << (fs)->fs_fragshift)
#define NSPF(fs) ((fs)->fs_nspf)
/*
* INOPB is the number of inodes in a secondary storage block.
*/
#define INOPB(fs) ((fs)->fs_inopb)
#define INOPF(fs) ((fs)->fs_inopb >> (fs)->fs_fragshift)
/*
* NINDIR is the number of indirects in a file system block.
*/
#define NINDIR(fs) ((fs)->fs_nindir)

634
shared_src/fsys_ext2fs.c Normal file
View file

@ -0,0 +1,634 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1996 Erich Boleyn <erich@uruk.org>
*
* 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.
*/
#include "shared.h"
#ifdef E2DEBUG
#include "pc_slice.h"
#else
#include "filesys.h"
#endif
static int mapblock1, mapblock2;
/* sizes are always in bytes, BLOCK values are always in DEV_BSIZE (sectors) */
#define DEV_BSIZE 512
/* include/linux/fs.h */
#define BLOCK_SIZE 1024 /* initial block size for superblock read */
/* made up, defaults to 1 but can be passed via mount_opts */
#define WHICH_SUPER 1
/* kind of from fs/ext2/super.c */
#define SBLOCK (WHICH_SUPER * BLOCK_SIZE / DEV_BSIZE) /* = 2 */
/* include/asm-i386/types.h */
typedef __signed__ char __s8;
typedef unsigned char __u8;
typedef __signed__ short __s16;
typedef unsigned short __u16;
typedef __signed__ int __s32;
typedef unsigned int __u32;
/*
* Constants relative to the data blocks, from ext2_fs.h
*/
#define EXT2_NDIR_BLOCKS 12
#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1)
#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1)
#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
/* include/linux/ext2_fs.h */
struct ext2_super_block {
__u32 s_inodes_count; /* Inodes count */
__u32 s_blocks_count; /* Blocks count */
__u32 s_r_blocks_count; /* Reserved blocks count */
__u32 s_free_blocks_count; /* Free blocks count */
__u32 s_free_inodes_count; /* Free inodes count */
__u32 s_first_data_block; /* First Data Block */
__u32 s_log_block_size; /* Block size */
__s32 s_log_frag_size; /* Fragment size */
__u32 s_blocks_per_group; /* # Blocks per group */
__u32 s_frags_per_group; /* # Fragments per group */
__u32 s_inodes_per_group; /* # Inodes per group */
__u32 s_mtime; /* Mount time */
__u32 s_wtime; /* Write time */
__u16 s_mnt_count; /* Mount count */
__s16 s_max_mnt_count; /* Maximal mount count */
__u16 s_magic; /* Magic signature */
__u16 s_state; /* File system state */
__u16 s_errors; /* Behaviour when detecting errors */
__u16 s_pad;
__u32 s_lastcheck; /* time of last check */
__u32 s_checkinterval; /* max. time between checks */
__u32 s_creator_os; /* OS */
__u32 s_rev_level; /* Revision level */
__u16 s_def_resuid; /* Default uid for reserved blocks */
__u16 s_def_resgid; /* Default gid for reserved blocks */
__u32 s_reserved[235]; /* Padding to the end of the block */
};
struct ext2_group_desc
{
__u32 bg_block_bitmap; /* Blocks bitmap block */
__u32 bg_inode_bitmap; /* Inodes bitmap block */
__u32 bg_inode_table; /* Inodes table block */
__u16 bg_free_blocks_count; /* Free blocks count */
__u16 bg_free_inodes_count; /* Free inodes count */
__u16 bg_used_dirs_count; /* Directories count */
__u16 bg_pad;
__u32 bg_reserved[3];
};
struct ext2_inode {
__u16 i_mode; /* File mode */
__u16 i_uid; /* Owner Uid */
__u32 i_size; /* 4: Size in bytes */
__u32 i_atime; /* Access time */
__u32 i_ctime; /* 12: Creation time */
__u32 i_mtime; /* Modification time */
__u32 i_dtime; /* 20: Deletion Time */
__u16 i_gid; /* Group Id */
__u16 i_links_count; /* 24: Links count */
__u32 i_blocks; /* Blocks count */
__u32 i_flags; /* 32: File flags */
union {
struct {
__u32 l_i_reserved1;
} linux1;
struct {
__u32 h_i_translator;
} hurd1;
struct {
__u32 m_i_reserved1;
} masix1;
} osd1; /* OS dependent 1 */
__u32 i_block[EXT2_N_BLOCKS];/* 40: Pointers to blocks */
__u32 i_version; /* File version (for NFS) */
__u32 i_file_acl; /* File ACL */
__u32 i_dir_acl; /* Directory ACL */
__u32 i_faddr; /* Fragment address */
union {
struct {
__u8 l_i_frag; /* Fragment number */
__u8 l_i_fsize; /* Fragment size */
__u16 i_pad1;
__u32 l_i_reserved2[2];
} linux2;
struct {
__u8 h_i_frag; /* Fragment number */
__u8 h_i_fsize; /* Fragment size */
__u16 h_i_mode_high;
__u16 h_i_uid_high;
__u16 h_i_gid_high;
__u32 h_i_author;
} hurd2;
struct {
__u8 m_i_frag; /* Fragment number */
__u8 m_i_fsize; /* Fragment size */
__u16 m_pad1;
__u32 m_i_reserved2[2];
} masix2;
} osd2; /* OS dependent 2 */
};
/* linux/limits.h */
#define NAME_MAX 255 /* # chars in a file name */
/* linux/posix_type.h */
typedef long off_t;
/* linux/ext2fs.h */
#define EXT2_NAME_LEN 255
struct ext2_dir_entry {
__u32 inode; /* Inode number */
__u16 rec_len; /* Directory entry length */
__u16 name_len; /* Name length */
char name[EXT2_NAME_LEN]; /* File name */
};
/* linux/ext2fs.h */
/*
* EXT2_DIR_PAD defines the directory entries boundaries
*
* NOTE: It must be a multiple of 4
*/
#define EXT2_DIR_PAD 4
#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1)
#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
~EXT2_DIR_ROUND)
/* ext2/super.c */
#define log2(n) ffz(~(n))
#define EXT2_SUPER_MAGIC 0xEF53 /* include/linux/ext2_fs.h */
#define EXT2_ROOT_INO 2 /* include/linux/ext2_fs.h */
/* made up, these are pointers into FSYS_BUF */
/* read once, always stays there: */
#define SUPERBLOCK \
((struct ext2_super_block *)(FSYS_BUF))
#define GROUP_DESC \
((struct ext2_group_desc *) \
((int)SUPERBLOCK + sizeof(struct ext2_super_block)))
#define INODE \
((struct ext2_inode *)((int)GROUP_DESC + EXT2_BLOCK_SIZE(SUPERBLOCK)))
#define DATABLOCK1 \
((int)((int)INODE + sizeof(struct ext2_inode)))
#define DATABLOCK2 \
((int)((int)DATABLOCK1 + EXT2_BLOCK_SIZE(SUPERBLOCK)))
/* linux/ext2_fs.h */
#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (__u32))
#define EXT2_ADDR_PER_BLOCK_BITS(s) (log2(EXT2_ADDR_PER_BLOCK(s)))
/* linux/ext2_fs.h */
#define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10)
/* kind of from ext2/super.c */
#define EXT2_BLOCK_SIZE(s) (1 << EXT2_BLOCK_SIZE_BITS(s))
/* linux/ext2fs.h */
#define EXT2_DESC_PER_BLOCK(s) \
(EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
/* linux/stat.h */
#define S_IFMT 00170000
#define S_IFREG 0100000
#define S_IFDIR 0040000
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
/* include/asm-i386/bitops.h */
/*
* ffz = Find First Zero in word. Undefined if no zero exists,
* so code should check against ~0UL first..
*/
__inline__ unsigned long ffz(unsigned long word)
{
__asm__("bsfl %1,%0"
:"=r" (word)
:"r" (~word));
return word;
}
/* check filesystem types and read superblock into memory buffer */
int
ext2fs_mount(void)
{
int retval = 1;
if ( (((current_drive & 0x80) || (current_slice != 0))
&& (current_slice != PC_SLICE_TYPE_EXT2FS)
&& (current_slice != (PC_SLICE_TYPE_BSD | (FS_OTHER<<8))))
|| part_length < (SBLOCK + (sizeof(struct ext2_super_block)/DEV_BSIZE))
|| !devread(SBLOCK, 0, sizeof(struct ext2_super_block), (int)SUPERBLOCK)
|| SUPERBLOCK->s_magic != EXT2_SUPER_MAGIC)
retval = 0;
return retval;
}
/* not part of the interface
takes a file system block number and reads it into area pointed
to by buffer */
int
ext2_rdfsb (int fsblock, int buffer) {
#ifdef E2DEBUG
printf("fsblock %d buffer %d\n", fsblock, buffer);
#endif /* E2DEBUG */
return devread(fsblock * EXT2_BLOCK_SIZE(SUPERBLOCK) / DEV_BSIZE, 0,
EXT2_BLOCK_SIZE(SUPERBLOCK), (int)buffer);
}
/* from
ext2/inode.c:ext2_bmap()
*/
/* not part of interface
maps "logical block" (the file offset div blocksize) into
"physical blocks" (the location in the file system) via an inode */
int
ext2fs_block_map(int logical_block)
{
#ifdef E2DEBUG
unsigned char * i;
for (i = (unsigned char *)INODE;
i < ((unsigned char *)INODE + sizeof(struct ext2_inode));
i++) {
printf("%c", "0123456789abcdef"[*i >> 4]);
printf("%c", "0123456789abcdef"[*i % 16]);
if (!((i + 1 - (unsigned char *)INODE) % 16)) { printf("\n"); }
else { printf(" "); }
}
printf("logical block %d\n", logical_block);
#endif /* E2DEBUG */
/* if it is directly pointed to by the inode, return that physical addr */
if (logical_block < EXT2_NDIR_BLOCKS) {
#ifdef E2DEBUG
printf ("returning %d\n", (unsigned char *)(INODE->i_block[logical_block]));
printf ("returning %d\n", INODE->i_block[logical_block]);
#endif /* E2DEBUG */
return INODE->i_block[logical_block];
}
/* else */
logical_block -= EXT2_NDIR_BLOCKS;
/* try the indirect block */
if (logical_block < EXT2_ADDR_PER_BLOCK(SUPERBLOCK)) {
if ( mapblock1 != 1
&& !ext2_rdfsb(INODE->i_block[EXT2_IND_BLOCK], DATABLOCK1)) {
errnum = ERR_FSYS_CORRUPT;
return -1;
}
mapblock1 = 1;
return ((__u32 *)DATABLOCK1)[logical_block];
}
/* else */
logical_block -= EXT2_ADDR_PER_BLOCK(SUPERBLOCK);
/* now try the double indirect block */
if (logical_block < (1 << (EXT2_ADDR_PER_BLOCK_BITS(SUPERBLOCK) * 2))) {
int bnum;
if ( mapblock1 != 2
&& !ext2_rdfsb(INODE->i_block[EXT2_DIND_BLOCK], DATABLOCK1)) {
errnum = ERR_FSYS_CORRUPT;
return -1;
}
mapblock1 = 2;
if ( (bnum = (((__u32 *)DATABLOCK1)
[logical_block >> EXT2_ADDR_PER_BLOCK_BITS(SUPERBLOCK)]))
!= mapblock2
&& !ext2_rdfsb(bnum, DATABLOCK2)) {
errnum = ERR_FSYS_CORRUPT;
return -1;
}
mapblock2 = bnum;
return ((__u32 *)DATABLOCK2)
[logical_block & (EXT2_ADDR_PER_BLOCK(SUPERBLOCK) - 1)];
}
/* else */
mapblock2 = -1;
logical_block -= (1 << (EXT2_ADDR_PER_BLOCK_BITS(SUPERBLOCK) * 2));
if ( mapblock1 != 3
&& !ext2_rdfsb(INODE->i_block[EXT2_TIND_BLOCK], DATABLOCK1)) {
errnum = ERR_FSYS_CORRUPT;
return -1;
}
mapblock1 = 3;
if (!ext2_rdfsb(((__u32 *)DATABLOCK1)
[logical_block >> (EXT2_ADDR_PER_BLOCK_BITS(SUPERBLOCK)*2)],
DATABLOCK2)) {
errnum = ERR_FSYS_CORRUPT;
return -1;
}
if (!ext2_rdfsb(((__u32 *)DATABLOCK2)
[(logical_block >> EXT2_ADDR_PER_BLOCK_BITS(SUPERBLOCK))
& (EXT2_ADDR_PER_BLOCK(SUPERBLOCK) - 1)],
DATABLOCK2)) {
errnum = ERR_FSYS_CORRUPT;
return -1;
}
return ((__u32 *)DATABLOCK2)
[logical_block & (EXT2_ADDR_PER_BLOCK(SUPERBLOCK)-1)];
}
/* preconditions: all preconds of ext2fs_block_map */
int
ext2fs_read(int addr, int len)
{
int logical_block;
int offset;
int map;
int ret = 0;
int size = 0;
#ifdef E2DEBUG
unsigned char * i;
for (i = (unsigned char *)INODE;
i < ((unsigned char *)INODE + sizeof(struct ext2_inode));
i++) {
printf("%c", "0123456789abcdef"[*i >> 4]);
printf("%c", "0123456789abcdef"[*i % 16]);
if (!((i + 1 - (unsigned char *)INODE) % 16)) { printf("\n"); }
else { printf(" "); }
}
#endif /* E2DEBUG */
while(len > 0) {
/* find the (logical) block component of our location */
logical_block = filepos >> EXT2_BLOCK_SIZE_BITS(SUPERBLOCK);
offset = filepos & (EXT2_BLOCK_SIZE(SUPERBLOCK) - 1);
map = ext2fs_block_map(logical_block);
#ifdef E2DEBUG
printf("map=%d\n", map);
#endif /* E2DEBUG */
if (map < 0)
break;
size = EXT2_BLOCK_SIZE(SUPERBLOCK);
size -= offset;
if (size > len)
size = len;
#ifndef NO_FANCY_STUFF
debug_fs_func = debug_fs;
#endif /* NO_FANCY_STUFF */
devread(map * EXT2_BLOCK_SIZE(SUPERBLOCK) / DEV_BSIZE,
offset, size, addr);
#ifndef NO_FANCY_STUFF
debug_fs_func = NULL;
#endif /* NO_FANCY_STUFF */
addr += size;
len -= size;
filepos += size;
ret += size;
}
if (errnum)
ret = 0;
return ret;
}
/* Based on:
def_blk_fops points to
blkdev_open, which calls (I think):
sys_open()
do_open()
open_namei()
dir_namei() which accesses current->fs->root
fs->root was set during original mount:
(something)... which calls (I think):
ext2_read_super()
iget()
__iget()
read_inode()
ext2_read_inode()
uses desc_per_block_bits, which is set in ext2_read_super()
also uses group descriptors loaded during ext2_read_super()
lookup()
ext2_lookup()
ext2_find_entry()
ext2_getblk()
*/
/* preconditions: ext2fs_mount already executed, therefore supblk in buffer
* known as SUPERBLOCK
* returns: 0 if error, nonzero iff we were able to find the file successfully
* postconditions: on a nonzero return, buffer known as INODE contains the
* inode of the file we were trying to look up
* side effects: messes up GROUP_DESC buffer area
*/
int
ext2fs_dir(char *dirname)
{
int current_ino = EXT2_ROOT_INO; /* start at the root */
int group_id; /* which group the inode is in */
int group_desc; /* fs pointer to that group */
int desc; /* index within that group */
int ino_blk; /* fs pointer of the inode's information */
int str_chk; /* used to hold the results of a string compare */
struct ext2_group_desc * gdp;
struct ext2_inode * raw_inode; /* inode info corresponding to current_ino */
char *rest;
char ch; /* temp char holder */
int off; /* offset within block of directory entry (off mod blocksize) */
int loc; /* location within a directory */
int blk; /* which data blk within dir entry (off div blocksize) */
long map; /* fs pointer of a particular block from dir entry */
struct ext2_dir_entry *dp; /* pointer to directory entry */
#ifdef E2DEBUG
unsigned char *i;
#endif E2DEBUG
/* loop invariants:
current_ino = inode to lookup
dirname = pointer to filename component we are cur looking up within
the directory known pointed to by current_ino (if any)
*/
while (1) {
#ifdef E2DEBUG
printf("inode %d\n", current_ino);
printf("dirname=%s\n", dirname);
#endif /* E2DEBUG */
/* look up an inode */
group_id = (current_ino - 1) / (SUPERBLOCK->s_inodes_per_group);
group_desc = group_id >> log2(EXT2_DESC_PER_BLOCK(SUPERBLOCK));
desc = group_id & (EXT2_DESC_PER_BLOCK(SUPERBLOCK) - 1);
#ifdef E2DEBUG
printf("ipg=%d, dpb=%d\n", SUPERBLOCK->s_inodes_per_group,
EXT2_DESC_PER_BLOCK(SUPERBLOCK));
printf("group_id=%d group_desc=%d desc=%d\n", group_id, group_desc, desc);
#endif /* E2DEBUG */
if (!ext2_rdfsb((WHICH_SUPER + group_desc + 1), (int)GROUP_DESC)) {
return 0;
}
gdp = GROUP_DESC;
ino_blk = gdp[desc].bg_inode_table +
(((current_ino - 1) % (SUPERBLOCK->s_inodes_per_group))
>> log2(EXT2_BLOCK_SIZE(SUPERBLOCK) / sizeof(struct ext2_inode)));
#ifdef E2DEBUG
printf("inode table fsblock=%d\n", ino_blk);
#endif /* E2DEBUG */
if (!ext2_rdfsb(ino_blk, (int)INODE)) {
return 0;
}
/* reset indirect blocks! */
mapblock2 = mapblock1 = -1;
raw_inode = INODE +
((current_ino - 1)
& (EXT2_BLOCK_SIZE(SUPERBLOCK) / sizeof(struct ext2_inode) - 1));
#ifdef E2DEBUG
printf("ipb=%d, sizeof(inode)=%d\n",
(EXT2_BLOCK_SIZE(SUPERBLOCK) / sizeof(struct ext2_inode)),
sizeof(struct ext2_inode));
printf("inode=%x, raw_inode=%x\n", INODE, raw_inode);
printf("offset into inode table block=%d\n", (int)raw_inode - (int)INODE);
for (i = (unsigned char *)INODE; i <= (unsigned char *)raw_inode; i++) {
printf("%c", "0123456789abcdef"[*i >> 4]);
printf("%c", "0123456789abcdef"[*i % 16]);
if (!((i + 1 - (unsigned char *)INODE) % 16)) { printf("\n"); }
else { printf(" "); }
}
printf("first word=%x\n", *((int *)raw_inode));
#endif /* E2DEBUG */
/* copy inode to fixed location */
bcopy((void *)raw_inode, (void *)INODE, sizeof(struct ext2_inode));
#ifdef E2DEBUG
printf("first word=%x\n", *((int *)INODE));
#endif /* E2DEBUG */
/* if end of filename, INODE points to the file's inode */
if (!*dirname || isspace(*dirname))
{
if (!S_ISREG(INODE->i_mode))
{
errnum = ERR_BAD_FILETYPE;
return 0;
}
filemax = (INODE->i_size);
return 1;
}
/* else we have to traverse a directory */
/* skip over slashes */
while (*dirname == '/')
dirname++;
/* if this isn't a directory of sufficient size to hold our file, abort */
if (!(INODE->i_size) || !S_ISDIR(INODE->i_mode))
{
errnum = ERR_BAD_FILETYPE;
return 0;
}
/* skip to next slash or end of filename (space) */
for (rest = dirname; (ch = *rest) && !isspace(ch) && ch != '/'; rest++) ;
/* look through this directory and find the next filename component */
/* invariant: rest points to slash after the next filename component */
*rest = 0;
loc = 0;
do {
#ifdef E2DEBUG
printf("dirname=%s, rest=%s, loc=%d\n", dirname, rest, loc);
#endif /* E2DEBUG */
/* if our location/byte offset into the directory exceeds the size,
give up */
if (loc >= INODE->i_size) {
if (print_possibilities < 0) {
putchar('\n');
}
else {
errnum = ERR_FILE_NOT_FOUND;
*rest = ch;
}
return (print_possibilities < 0);
}
/* else, find the (logical) block component of our location */
blk = loc >> EXT2_BLOCK_SIZE_BITS(SUPERBLOCK);
/* now we know which logical block of the directory entry we are looking
for, now we have to translate that to the physical (fs) block on
the disk */
map = ext2fs_block_map(blk);
#ifdef E2DEBUG
printf("fs block=%d\n", map);
#endif /* E2DEBUG */
mapblock2 = -1;
if ((map < 0) || !ext2_rdfsb(map, DATABLOCK2)) {
errnum = ERR_FSYS_CORRUPT;
*rest = ch;
return 0;
}
off = loc & (EXT2_BLOCK_SIZE(SUPERBLOCK) - 1);
dp = (struct ext2_dir_entry *)(DATABLOCK2 + off);
/* advance loc prematurely to next on-disk directory entry */
loc += dp->rec_len;
/* NOTE: ext2fs filenames are NOT null-terminated */
#ifdef E2DEBUG
printf("directory entry ino=%d\n", dp->inode);
if (dp->inode)
printf("entry=%s\n", dp->name);
#endif /* E2DEBUG */
if (dp->inode)
{
int saved_c = dp->name[dp->name_len];
dp->name[dp->name_len] = 0;
str_chk = strcmp(dirname, dp->name);
if (print_possibilities && ch != '/'
&& (!*dirname || str_chk <= 0))
{
if (print_possibilities > 0)
print_possibilities = -print_possibilities;
printf(" %s", dp->name);
}
dp->name[dp->name_len] = saved_c;
}
} while (!dp->inode || (str_chk || (print_possibilities && ch != '/')) );
current_ino = dp->inode;
*(dirname = rest) = ch;
}
/* never get here */
}

256
shared_src/fsys_fat.c Normal file
View file

@ -0,0 +1,256 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1996 Erich Boleyn <erich@uruk.org>
*
* 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.
*/
#include "shared.h"
#include "filesys.h"
#include "fat.h"
static int num_clust;
static int mapblock;
static int data_offset;
static int fat_size;
/* pointer(s) into filesystem info buffer for DOS stuff */
#define BPB ( FSYS_BUF + 32256 ) /* 512 bytes long */
#define FAT_BUF ( FSYS_BUF + 30208 ) /* 4 sector FAT buffer */
int
fat_mount(void)
{
int retval = 1;
if ( (((current_drive & 0x80) || (current_slice != 0))
&& (current_slice != PC_SLICE_TYPE_FAT12)
&& (current_slice != PC_SLICE_TYPE_FAT16_LT32M)
&& (current_slice != PC_SLICE_TYPE_FAT16_GT32M)
&& (current_slice != (PC_SLICE_TYPE_BSD | (FS_MSDOS<<8))))
|| !devread(0, 0, SECTOR_SIZE, BPB)
|| FAT_BPB_BYTES_PER_SECTOR(BPB) != SECTOR_SIZE
|| FAT_BPB_SECT_PER_CLUST(BPB) < 1 || FAT_BPB_SECT_PER_CLUST(BPB) > 64
|| (FAT_BPB_SECT_PER_CLUST(BPB) & (FAT_BPB_SECT_PER_CLUST(BPB) - 1))
|| !( (current_drive & 0x80)
|| FAT_BPB_FLOPPY_NUM_SECTORS(BPB) ) )
retval = 0;
else
{
mapblock = -4096;
data_offset = FAT_BPB_DATA_OFFSET(BPB);
num_clust = FAT_BPB_NUM_CLUST(BPB) + 2;
if (num_clust > FAT_MAX_12BIT_CLUST)
fat_size = 4;
else
fat_size = 3;
}
return retval;
}
static int
fat_create_blocklist(int first_fat_entry)
{
BLK_CUR_FILEPOS = 0;
BLK_CUR_BLKNUM = 0;
BLK_CUR_BLKLIST = BLK_BLKLIST_START;
block_file = 1;
filepos = 0;
if (first_fat_entry < 0)
{
/* root directory */
BLK_BLKSTART(BLK_BLKLIST_START) = FAT_BPB_ROOT_DIR_START(BPB);
fsmax = filemax = SECTOR_SIZE * (BLK_BLKLENGTH(BLK_BLKLIST_START)
= FAT_BPB_ROOT_DIR_LENGTH(BPB));
}
else /* any real directory/file */
{
int blk_cur_blklist = BLK_BLKLIST_START, blk_cur_blknum;
int last_fat_entry, new_mapblock;
fsmax = 0;
do
{
BLK_BLKSTART(blk_cur_blklist)
= (first_fat_entry-2) * FAT_BPB_SECT_PER_CLUST(BPB) + data_offset;
blk_cur_blknum = 0;
do
{
blk_cur_blknum += FAT_BPB_SECT_PER_CLUST(BPB);
last_fat_entry = first_fat_entry;
/*
* Do FAT table translation here!
*/
new_mapblock = (last_fat_entry * fat_size) >> 1;
if (new_mapblock > (mapblock + 2045)
|| new_mapblock < (mapblock + 3))
{
mapblock = ( (new_mapblock < 6) ? 0 :
((new_mapblock - 6) & ~0x1FF) );
if (!devread((mapblock>>9)+FAT_BPB_FAT_START(BPB),
0, SECTOR_SIZE * 4, FAT_BUF))
return 0;
}
first_fat_entry
= *((unsigned short *) (FAT_BUF + (new_mapblock - mapblock)));
if (num_clust <= FAT_MAX_12BIT_CLUST)
{
if (last_fat_entry & 1)
first_fat_entry >>= 4;
else
first_fat_entry &= 0xFFF;
}
if (first_fat_entry < 2)
{
errnum = ERR_FSYS_CORRUPT;
return 0;
}
}
while (first_fat_entry == (last_fat_entry + 1)
&& first_fat_entry < num_clust);
BLK_BLKLENGTH(blk_cur_blklist) = blk_cur_blknum;
fsmax += blk_cur_blknum * SECTOR_SIZE;
blk_cur_blklist += BLK_BLKLIST_INC_VAL;
}
while (first_fat_entry < num_clust && blk_cur_blklist < (FAT_BUF - 7));
}
return 1;
}
/* XX FAT filesystem uses the block-list filesystem read function,
so none is defined here. */
int
fat_dir(char *dirname)
{
char *rest, ch, filename[13], dir_buf[FAT_DIRENTRY_LENGTH];
int attrib = FAT_ATTRIB_DIR, map = -1;
/* main loop to find desired directory entry */
loop:
if (!fat_create_blocklist(map))
return 0;
/* if we have a real file (and we're not just printing possibilities),
then this is where we want to exit */
if (!*dirname || isspace(*dirname))
{
if (attrib & FAT_ATTRIB_DIR)
{
errnum = ERR_BAD_FILETYPE;
return 0;
}
return 1;
}
/* continue with the file/directory name interpretation */
while (*dirname == '/')
dirname++;
filemax = fsmax;
if (!filemax || !(attrib & FAT_ATTRIB_DIR))
{
errnum = ERR_BAD_FILETYPE;
return 0;
}
for (rest = dirname; (ch = *rest) && !isspace(ch) && ch != '/'; rest++) ;
*rest = 0;
do
{
if (read((int)dir_buf, FAT_DIRENTRY_LENGTH) != FAT_DIRENTRY_LENGTH)
{
if (!errnum)
{
if (print_possibilities < 0)
{
putchar('\n');
return 1;
}
errnum = ERR_FILE_NOT_FOUND;
*rest = ch;
}
return 0;
}
if (!FAT_DIRENTRY_VALID(dir_buf))
continue;
/* XXX convert to 8.3 filename format here */
{
int i, j, c;
for (i = 0; i < 8 && (c = filename[i] = tolower(dir_buf[i]))
&& !isspace(c) ; i++) ;
filename[i++] = '.';
for (j = 0; j < 3 && (c = filename[i+j] = tolower(dir_buf[8+j]))
&& !isspace(c) ; j++) ;
if (j == 0)
i--;
filename[i+j] = 0;
}
if (print_possibilities && ch != '/'
&& (!*dirname || strcmp(dirname, filename) <= 0))
{
if (print_possibilities > 0)
print_possibilities = -print_possibilities;
printf(" %s", filename);
}
}
while (strcmp(dirname, filename) != 0 || (print_possibilities && ch != '/'));
*(dirname = rest) = ch;
attrib = FAT_DIRENTRY_ATTRIB(dir_buf);
filemax = FAT_DIRENTRY_FILELENGTH(dir_buf);
map = FAT_DIRENTRY_FIRST_CLUSTER(dir_buf);
/* go back to main loop at top of function */
goto loop;
}

267
shared_src/fsys_ffs.c Normal file
View file

@ -0,0 +1,267 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1996 Erich Boleyn <erich@uruk.org>
*
* 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.
*/
/*
* Elements of this file were originally from the FreeBSD "biosboot"
* bootloader file "disk.c" dated 4/12/95.
*
* The license and header comments from that file are included here.
*/
/*
* Mach Operating System
* Copyright (c) 1992, 1991 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*
* from: Mach, Revision 2.2 92/04/04 11:35:49 rpd
* $Id$
*/
#include "shared.h"
#include "filesys.h"
#include "defs.h"
#include "disk_inode.h"
#include "disk_inode_ffs.h"
#include "dir.h"
#include "fs.h"
/* used for filesystem map blocks */
static int mapblock;
/* pointer to superblock */
#define SUPERBLOCK ((struct fs *) ( FSYS_BUF + 8192 ))
#define INODE ((struct icommon *) ( FSYS_BUF + 16384 ))
#define MAPBUF ( FSYS_BUF + 24576 )
int
ffs_mount(void)
{
int retval = 1;
if ( (((current_drive & 0x80) || (current_slice != 0))
&& current_slice != (PC_SLICE_TYPE_BSD | (FS_BSDFFS<<8)))
|| part_length < (SBLOCK + (SBSIZE/DEV_BSIZE))
|| !devread(SBLOCK, 0, SBSIZE, (int) SUPERBLOCK)
|| SUPERBLOCK->fs_magic != FS_MAGIC )
retval = 0;
mapblock = -1;
return retval;
}
int
block_map(int file_block)
{
int bnum;
if (file_block < NDADDR)
return(INODE->i_db[file_block]);
if ( (bnum = fsbtodb(SUPERBLOCK, INODE->i_ib[0])) != mapblock )
{
if (!devread(bnum, 0, SUPERBLOCK->fs_bsize, MAPBUF))
{
mapblock = -1;
errnum = ERR_FSYS_CORRUPT;
return -1;
}
mapblock = bnum;
}
return (((int *)MAPBUF)[(file_block - NDADDR) % NINDIR(SUPERBLOCK)]);
}
int
ffs_read(int addr, int len)
{
int logno, off, size, map, ret = 0;
while (len && !errnum)
{
off = blkoff(SUPERBLOCK, filepos);
logno = lblkno(SUPERBLOCK, filepos);
size = blksize(SUPERBLOCK, INODE, logno);
if ((map = block_map(logno)) < 0)
break;
size -= off;
if (size > len)
size = len;
#ifndef NO_FANCY_STUFF
debug_fs_func = debug_fs;
#endif /* NO_FANCY_STUFF */
devread(fsbtodb(SUPERBLOCK, map), off, size, addr);
#ifndef NO_FANCY_STUFF
debug_fs_func = NULL;
#endif /* NO_FANCY_STUFF */
addr += size;
len -= size;
filepos += size;
ret += size;
}
if (errnum)
ret = 0;
return ret;
}
int
ffs_dir(char *dirname)
{
char *rest, ch;
int block, off, loc, map, ino = ROOTINO;
struct direct *dp;
/* main loop to find destination inode */
loop:
/* load current inode (defaults to the root inode) */
if (!devread(fsbtodb(SUPERBLOCK,itod(SUPERBLOCK,ino)),
0, SUPERBLOCK->fs_bsize, FSYS_BUF))
return 0; /* XXX what return value? */
bcopy((void *)&(((struct dinode *)FSYS_BUF)[ino % (SUPERBLOCK->fs_inopb)]),
(void *)INODE, sizeof (struct dinode));
/* if we have a real file (and we're not just printing possibilities),
then this is where we want to exit */
if (!*dirname || isspace(*dirname))
{
if ((INODE->i_mode & IFMT) != IFREG)
{
errnum = ERR_BAD_FILETYPE;
return 0;
}
filemax = INODE->i_size;
/* incomplete implementation requires this! */
fsmax = (NDADDR + NINDIR(SUPERBLOCK)) * SUPERBLOCK->fs_bsize;
return 1;
}
/* continue with file/directory name interpretation */
while (*dirname == '/')
dirname++;
if (!(INODE->i_size) || ((INODE->i_mode & IFMT) != IFDIR))
{
errnum = ERR_BAD_FILETYPE;
return 0;
}
for (rest = dirname; (ch = *rest) && !isspace(ch) && ch != '/'; rest++) ;
*rest = 0;
loc = 0;
/* loop for reading a the entries in a directory */
do
{
if (loc >= INODE->i_size)
{
putchar('\n');
if (print_possibilities < 0)
return 1;
errnum = ERR_FILE_NOT_FOUND;
*rest = ch;
return 0;
}
if (!(off = blkoff(SUPERBLOCK, loc)))
{
block = lblkno(SUPERBLOCK, loc);
if ( (map = block_map(block)) < 0
|| !devread(fsbtodb(SUPERBLOCK, map), 0,
blksize(SUPERBLOCK, INODE, block), FSYS_BUF) )
{
errnum = ERR_FSYS_CORRUPT;
*rest = ch;
return 0;
}
}
dp = (struct direct *)(FSYS_BUF + off);
loc += dp->d_reclen;
if (dp->d_ino && print_possibilities && ch != '/'
&& (!*dirname || strcmp(dirname, dp->d_name) <= 0))
{
if (print_possibilities > 0)
print_possibilities = -print_possibilities;
printf(" %s", dp->d_name);
}
}
while (!dp->d_ino || (strcmp(dirname, dp->d_name) != 0
|| (print_possibilities && ch != '/')) );
/* only get here if we have a matching directory entry */
ino = dp->d_ino;
*(dirname = rest) = ch;
/* go back to main loop at top of function */
goto loop;
}

659
shared_src/gunzip.c Normal file
View file

@ -0,0 +1,659 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1996 Erich Boleyn <erich@uruk.org>
*
* 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.
*/
/*
* Most of this file was originally the source file "inflate.c", written
* by Mark Adler. It has been very heavily modified. In particular, the
* original would run through the whole file at once, and this version can
* be stopped and restarted on any boundary during the decompression process.
*
* The license and header comments that file are included here.
*/
/* inflate.c -- Not copyrighted 1992 by Mark Adler
version c10p1, 10 January 1993 */
/* You can do whatever you like with this source file, though I would
prefer that if you modify it and redistribute it that you include
comments to that effect with your name and the date. Thank you.
[The history has been moved to the file ChangeLog.]
*/
/*
Inflate deflated (PKZIP's method 8 compressed) data. The compression
method searches for as much of the current string of bytes (up to a
length of 258) in the previous 32K bytes. If it doesn't find any
matches (of at least length 3), it codes the next byte. Otherwise, it
codes the length of the matched string and its distance backwards from
the current position. There is a single Huffman code that codes both
single bytes (called "literals") and match lengths. A second Huffman
code codes the distance information, which follows a length code. Each
length or distance code actually represents a base value and a number
of "extra" (sometimes zero) bits to get to add to the base value. At
the end of each deflated block is a special end-of-block (EOB) literal/
length code. The decoding process is basically: get a literal/length
code; if EOB then done; if a literal, emit the decoded byte; if a
length then get the distance and emit the referred-to bytes from the
sliding window of previously emitted data.
There are (currently) three kinds of inflate blocks: stored, fixed, and
dynamic. The compressor deals with some chunk of data at a time, and
decides which method to use on a chunk-by-chunk basis. A chunk might
typically be 32K or 64K. If the chunk is uncompressible, then the
"stored" method is used. In this case, the bytes are simply stored as
is, eight bits per byte, with none of the above coding. The bytes are
preceded by a count, since there is no longer an EOB code.
If the data is compressible, then either the fixed or dynamic methods
are used. In the dynamic method, the compressed data is preceded by
an encoding of the literal/length and distance Huffman codes that are
to be used to decode this block. The representation is itself Huffman
coded, and so is preceded by a description of that code. These code
descriptions take up a little space, and so for small blocks, there is
a predefined set of codes, called the fixed codes. The fixed method is
used if the block codes up smaller that way (usually for quite small
chunks), otherwise the dynamic method is used. In the latter case, the
codes are customized to the probabilities in the current block, and so
can code it much better than the pre-determined fixed codes.
The Huffman codes themselves are decoded using a mutli-level table
lookup, in order to maximize the speed of decoding plus the speed of
building the decoding tables. See the comments below that precede the
lbits and dbits tuning parameters.
*/
/*
Notes beyond the 1.93a appnote.txt:
1. Distance pointers never point before the beginning of the output
stream.
2. Distance pointers can point back across blocks, up to 32k away.
3. There is an implied maximum of 7 bits for the bit length table and
15 bits for the actual data.
4. If only one code exists, then it is encoded using one bit. (Zero
would be more efficient, but perhaps a little confusing.) If two
codes exist, they are coded using one bit each (0 and 1).
5. There is no way of sending zero distance codes--a dummy must be
sent if there are none. (History: a pre 2.0 version of PKZIP would
store blocks with no distance codes, but this was discovered to be
too harsh a criterion.) Valid only for 1.93a. 2.04c does allow
zero distance codes, which is sent as one code of zero bits in
length.
6. There are up to 286 literal/length codes. Code 256 represents the
end-of-block. Note however that the static length tree defines
288 codes just to fill out the Huffman codes. Codes 286 and 287
cannot be used though, since there is no length base or extra bits
defined for them. Similarly, there are up to 30 distance codes.
However, static trees define 32 codes (all 5 bits) to fill out the
Huffman codes, but the last two had better not show up in the data.
7. Unzip can check dynamic Huffman blocks for complete code sets.
The exception is that a single code would not be complete (see #4).
8. The five bits following the block type is really the number of
literal codes sent minus 257.
9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
(1+6+6). Therefore, to output three times the length, you output
three codes (1+1+1), whereas to output four times the same length,
you only need two codes (1+3). Hmm.
10. In the tree reconstruction algorithm, Code = Code + Increment
only if BitLength(i) is not zero. (Pretty obvious.)
11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19)
12. Note: length code 284 can represent 227-258, but length code 285
really is 258. The last length deserves its own, short code
since it gets used a lot in very redundant files. The length
258 is special since 258 - 3 (the min match length) is 255.
13. The literal/length and distance code bit lengths are read as a
single stream of lengths. It is possible (and advantageous) for
a repeat code (16, 17, or 18) to go across the boundary between
the two sets of lengths.
*/
#include "shared.h"
#include "filesys.h"
/* so we can disable decompression */
int no_decompression = 0;
/* used to tell if "read" should be redirected to "gunzip_read" */
int compressed_file;
/* internal variables only */
static int gzip_data_offset;
static int gzip_filepos;
static int gzip_filemax;
static int gzip_fsmax;
static int saved_filepos;
static unsigned long gzip_crc;
/* internal extra variables for use of inflate code */
static int block_type;
static int block_len;
/* Function prototypes */
static void initialize_tables(void);
static int huft_build(unsigned *, unsigned, unsigned, ush *, ush *,
struct huft **, int *);
static int huft_free(struct huft *);
static int inflate_codes(struct huft *, struct huft *, int, int);
/* internal variable swap function */
static void
gunzip_swap_values(void)
{
register int itmp;
/* swap filepos */
itmp = filepos;
filepos = gzip_filepos;
gzip_filepos = itmp;
/* swap filemax */
itmp = filemax;
filemax = gzip_filemax;
gzip_filemax = itmp;
/* swap fsmax */
itmp = fsmax;
fsmax = gzip_fsmax;
gzip_fsmax = itmp;
}
/* internal function for eating variable-length header fields */
static int
bad_field(int len)
{
char ch = 1;
int not_retval = 1;
do
{
if (len >= 0)
{
if (!(len--))
break;
}
else
{
if (!ch)
break;
}
}
while ((not_retval = read((int)&ch, 1)) == 1);
return (!not_retval);
}
/* Little-Endian defines for the 2-byte magic number for gzip files */
#define GZIP_HDR_LE 0x8B1F
#define OLD_GZIP_HDR_LE 0x9E1F
/* Compression methods (see algorithm.doc) */
#define STORED 0
#define COMPRESSED 1
#define PACKED 2
#define LZHED 3
/* methods 4 to 7 reserved */
#define DEFLATED 8
#define MAX_METHODS 9
/* gzip flag byte */
#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
#define COMMENT 0x10 /* bit 4 set: file comment present */
#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
#define RESERVED 0xC0 /* bit 6,7: reserved */
#define UNSUPP_FLAGS (CONTINUATION|ENCRYPTED|RESERVED)
/* inflate block codes */
#define INFLATE_STORED 0
#define INFLATE_FIXED 1
#define INFLATE_DYNAMIC 2
typedef unsigned char uch;
typedef unsigned short ush;
typedef unsigned long ulg;
/*
* Window Size
*
* This must be a power of two, and at least 32K for zip's deflate method
*/
#define WSIZE 0x8000
int
gunzip_test_header(void)
{
unsigned char buf[10];
/* "compressed_file" is already reset to zero by this point */
/*
* This checks if the file is gzipped. If a problem occurs here
* (other than a real error with the disk) then we don't think it
* is a compressed file, and simply mark it as such.
*/
if (no_decompression || read((int)buf, 10) != 10
|| ((*((unsigned short *) buf) != GZIP_HDR_LE)
& (*((unsigned short *) buf) != OLD_GZIP_HDR_LE)))
{
filepos = 0;
return (!errnum);
}
/*
* This does consistency checking on the header data. If a
* problem occurs from here on, then we have corrupt or otherwise
* bad data, and the error should be reported to the user.
*/
if (buf[2] != DEFLATED || (buf[3] & UNSUPP_FLAGS)
|| ((buf[3] & EXTRA_FIELD)
&& (read((int)buf, 2) != 2 || bad_field(*((unsigned short *) buf))))
|| ((buf[3] & ORIG_NAME) && bad_field(-1))
|| ((buf[3] & COMMENT) && bad_field(-1))
|| ((gzip_data_offset = filepos), (filepos = filemax - 8),
(read((int)buf, 8) != 8)))
{
if (!errnum)
errnum = ERR_BAD_GZIP_HEADER;
return 0;
}
gzip_crc = *((unsigned long *) buf);
gzip_fsmax = gzip_filemax = *((unsigned long *) (buf+4));
initialize_tables();
compressed_file = 1;
gunzip_swap_values();
/*
* Now "gzip_*" values refer to the compressed data.
*/
filepos = 0;
return 1;
}
uch slide[WSIZE];
/* Huffman code lookup table entry--this entry is four bytes for machines
that have 16-bit pointers (e.g. PC's in the small or medium model).
Valid extra bits are 0..13. e == 15 is EOB (end of block), e == 16
means that v is a literal, 16 < e < 32 means that v is a pointer to
the next table, which codes e - 16 bits, and lastly e == 99 indicates
an unused code. If a code with e == 99 is looked up, this implies an
error in the data. */
struct huft {
uch e; /* number of extra bits or operation */
uch b; /* number of bits in this code or subcode */
union {
ush n; /* literal, length base, or distance base */
struct huft *t; /* pointer to next level of table */
} v;
};
/* The inflate algorithm uses a sliding 32K byte window on the uncompressed
stream to find repeated byte strings. This is implemented here as a
circular buffer. The index is updated simply by incrementing and then
and'ing with 0x7fff (32K-1). */
/* It is left to other modules to supply the 32K area. It is assumed
to be usable as if it were declared "uch slide[32768];" or as just
"uch *slide;" and then malloc'ed in the latter case. The definition
must be in unzip.h, included above. */
/* current position in slide */
unsigned wp;
#define flush_output(w) (wp=(w),flush_window())
/* Tables for deflate from PKZIP's appnote.txt. */
static unsigned border[] = { /* Order of the bit length code lengths */
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
static ush cplens[] = { /* Copy lengths for literal codes 257..285 */
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
/* note: see note #13 above about the 258 in this list. */
static ush cplext[] = { /* Extra bits for literal codes 257..285 */
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */
static ush cpdist[] = { /* Copy offsets for distance codes 0..29 */
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
8193, 12289, 16385, 24577};
static ush cpdext[] = { /* Extra bits for distance codes */
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
12, 12, 13, 13};
/*
Huffman code decoding is performed using a multi-level table lookup.
The fastest way to decode is to simply build a lookup table whose
size is determined by the longest code. However, the time it takes
to build this table can also be a factor if the data being decoded
is not very long. The most common codes are necessarily the
shortest codes, so those codes dominate the decoding time, and hence
the speed. The idea is you can have a shorter table that decodes the
shorter, more probable codes, and then point to subsidiary tables for
the longer codes. The time it costs to decode the longer codes is
then traded against the time it takes to make longer tables.
This results of this trade are in the variables lbits and dbits
below. lbits is the number of bits the first level table for literal/
length codes can decode in one step, and dbits is the same thing for
the distance codes. Subsequent tables are also less than or equal to
those sizes. These values may be adjusted either when all of the
codes are shorter than that, in which case the longest code length in
bits is used, or when the shortest code is *longer* than the requested
table size, in which case the length of the shortest code in bits is
used.
There are two different values for the two tables, since they code a
different number of possibilities each. The literal/length table
codes 286 possible values, or in a flat code, a little over eight
bits. The distance table codes 30 possible values, or a little less
than five bits, flat. The optimum values for speed end up being
about one bit more than those, so lbits is 8+1 and dbits is 5+1.
The optimum values may differ though from machine to machine, and
possibly even between compilers. Your mileage may vary.
*/
int lbits = 9; /* bits in base literal/length lookup table */
int dbits = 6; /* bits in base distance lookup table */
/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
#define BMAX 16 /* maximum bit length of any code (16 for explode) */
#define N_MAX 288 /* maximum number of codes in any set */
unsigned hufts; /* track memory usage */
/* XXXXXX */
/* Macros for inflate() bit peeking and grabbing.
The usage is:
NEEDBITS(j)
x = b & mask_bits[j];
DUMPBITS(j)
where NEEDBITS makes sure that b has at least j bits in it, and
DUMPBITS removes the bits from b. The macros use the variable k
for the number of bits in b. Normally, b and k are register
variables for speed, and are initialized at the beginning of a
routine that uses these macros from a global bit buffer and count.
If we assume that EOB will be the longest code, then we will never
ask for bits with NEEDBITS that are beyond the end of the stream.
So, NEEDBITS should not read any more bytes than are needed to
meet the request. Then no bytes need to be "returned" to the buffer
at the end of the last block.
However, this assumption is not true for fixed blocks--the EOB code
is 7 bits, but the other literal/length codes can be 8 or 9 bits.
(The EOB code is shorter than other codes because fixed blocks are
generally short. So, while a block always has an EOB, many other
literal/length codes have a significantly lower probability of
showing up at all.) However, by making the first table have a
lookup of seven bits, the EOB code will be found in that first
lookup, and so will not require that too many bits be pulled from
the stream.
*/
ulg bb; /* bit buffer */
unsigned bk; /* bits in bit buffer */
ush mask_bits[] = {
0x0000,
0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
};
#define NEEDBITS(n) {while(k<(n)){b|=((ulg)get_byte())<<k;k+=8;}}
#define DUMPBITS(n) {b>>=(n);k-=(n);}
static void
needbits(int n)
{
register k = bk;
while (k < n)
{
bb |= ((ulg) get_byte()) << k;
k += 8;
}
bk = k;
}
#define dumpbits(n) {bb>>=(n);bk-=(n);}
static void
init_stored_block(void)
{
register ulg b; /* bit buffer */
register unsigned k; /* number of bits in bit buffer */
/* make local copies of globals */
b = bb; /* initialize bit buffer */
k = bk;
new_block = 0;
/* go to byte boundary */
DUMPBITS(k & 7);
/* get the length and its complement */
NEEDBITS(16);
block_len = ((unsigned)b & 0xffff);
DUMPBITS(16);
NEEDBITS(16);
if (block_len != (unsigned)((~b) & 0xffff))
errnum = ERR_BAD_GZIP_DATA;
DUMPBITS(16);
/* restore global variables */
bb = b;
bk = k;
}
static void
get_new_block(void)
{
register ulg b; /* bit buffer */
register unsigned k; /* number of bits in bit buffer */
hufts = 0;
/* make local bit buffer */
b = bb;
k = bk;
/* read in last block bit */
NEEDBITS(1);
last_block = (int)b & 1;
DUMPBITS(1);
/* read in block type */
NEEDBITS(2);
block_type = (unsigned)b & 3;
DUMPBITS(2);
/* restore the global bit buffer */
bb = b;
bk = k;
}
static void
inflate_window(void)
{
/* initialize window */
wp = 0;
/*
* Main decompression loop.
*/
while (wp < WSIZE && !errnum)
{
if (!block_len)
get_new_block();
if (block_type > INFLATE_DYNAMIC)
{
errnum = ERR_BAD_GZIP_DATA;
continue;
}
if (block_type == INFLATE_STORED)
{
/*
* This is basically a glorified pass-through
*/
if (!block_len)
init_stored_block();
while (block_len && wp < WSIZE && !errnum)
{
slide[wp++] = get_byte();
block_len--;
}
continue;
}
/*
* Init other kind of block.
*/
if (!block_len)
{
if (block_type == INFLATE_FIXED)
init_fixed_block();
if (block_type == INFLATE_DYNAMIC)
init_dynamic_block();
}
/*
* Expand other kind of block.
*/
if (inflate_codes() && !block_len)
{
/* we're done with the block, so free data structures */
huft_free(tl);
huft_free(td);
}
}
saved_filepos += WSIZE;
}
static void
initialize_tables(void)
{
saved_filepos = 0;
filepos = gzip_data_offset;
/* initialize window, bit buffer */
bk = 0;
bb = 0;
/* reset partial decompression code */
last_block = 0;
}
int
gunzip_read(int addr, int len)
{
int last_block, size; /* last block flag */
int ret = 0;
compressed_file = 0;
gunzip_swap_values();
/*
* Now "gzip_*" values refer to the uncompressed data.
*/
/* do we reset decompression to the beginning of the file? */
if (saved_filepos > gzip_filepos+WSIZE)
initialize_tables();
/*
* This loop operates upon uncompressed data only. The only
* special thing it does is to make sure the decompression
* window is within the range of data it needs.
*/
while (len > 0 && !errnum)
{
register int size;
while (gzip_filepos >= saved_filepos)
inflate_window();
size = saved_filepos - gzip_filepos;
if (size > len)
size = len;
bcopy((char *)slide, (char *)addr, size);
addr += size;
len -= size;
gzip_filepos += size;
ret += size;
}
compressed_file = 1;
gunzip_swap_values();
/*
* Now "gzip_*" values refer to the compressed data.
*/
if (errnum)
ret = 0;
return ret;
}

205
shared_src/i386-elf.h Normal file
View file

@ -0,0 +1,205 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1996 Erich Boleyn <erich@uruk.org>
*
* 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.
*/
/* 32-bit data types */
typedef unsigned long Elf32_Addr;
typedef unsigned short Elf32_Half;
typedef unsigned long Elf32_Off;
typedef signed long Elf32_Sword;
typedef unsigned long Elf32_Word;
/* "unsigned char" already exists */
/* ELF header */
typedef struct {
#define EI_NIDENT 16
/* first four characters are defined below */
#define EI_MAG0 0
#define ELFMAG0 0x7f
#define EI_MAG1 1
#define ELFMAG1 'E'
#define EI_MAG2 2
#define ELFMAG2 'L'
#define EI_MAG3 3
#define ELFMAG3 'F'
#define EI_CLASS 4 /* data sizes */
#define ELFCLASS32 1 /* i386 -- up to 32-bit data sizes present */
#define EI_DATA 5 /* data type and ordering */
#define ELFDATA2LSB 1 /* i386 -- LSB 2's complement */
#define EI_VERSION 6 /* version number. "e_version" must be the same */
#define EV_CURRENT 1 /* current version number */
#define EI_PAD 7 /* from here in is just padding */
unsigned char e_ident[EI_NIDENT]; /* basic identification block */
#define ET_EXEC 2 /* we only care about executable types */
Elf32_Half e_type; /* file types */
#define EM_386 3 /* i386 -- obviously use this one */
Elf32_Half e_machine; /* machine types */
Elf32_Word e_version; /* use same as "EI_VERSION" above */
Elf32_Addr e_entry; /* entry point of the program */
Elf32_Off e_phoff; /* program header table file offset */
Elf32_Off e_shoff; /* section header table file offset */
Elf32_Word e_flags; /* flags */
Elf32_Half e_ehsize; /* elf header size in bytes */
Elf32_Half e_phentsize; /* program header entry size */
Elf32_Half e_phnum; /* number of entries in program header */
Elf32_Half e_shentsize; /* section header entry size */
Elf32_Half e_shnum; /* number of entries in section header */
#define SHN_UNDEF 0
#define SHN_LORESERVE 0xff00
#define SHN_LOPROC 0xff00
#define SHN_HIPROC 0xff1f
#define SHN_ABS 0xfff1
#define SHN_COMMON 0xfff2
#define SHN_HIRESERVE 0xffff
Elf32_Half e_shstrndx; /* section header table index */
} Elf32_Ehdr;
#define BOOTABLE_I386_ELF(h) \
((h.e_ident[EI_MAG0] == ELFMAG0) & (h.e_ident[EI_MAG1] == ELFMAG1) \
& (h.e_ident[EI_MAG2] == ELFMAG2) & (h.e_ident[EI_MAG3] == ELFMAG3) \
& (h.e_ident[EI_CLASS] == ELFCLASS32) & (h.e_ident[EI_DATA] == ELFDATA2LSB) \
& (h.e_ident[EI_VERSION] == EV_CURRENT) & (h.e_type == ET_EXEC) \
& (h.e_machine == EM_386) & (h.e_version == EV_CURRENT))
/* symbol table - page 4-25, figure 4-15 */
typedef struct
{
Elf32_Word st_name;
Elf32_Addr st_value;
Elf32_Word st_size;
unsigned char st_info;
unsigned char st_other;
Elf32_Half st_shndx;
} Elf32_Sym;
/* symbol type and binding attributes - page 4-26 */
#define ELF32_ST_BIND(i) ((i) >> 4)
#define ELF32_ST_TYPE(i) ((i) & 0xf)
#define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf))
/* symbol binding - page 4-26, figure 4-16 */
#define STB_LOCAL 0
#define STB_GLOBAL 1
#define STB_WEAK 2
#define STB_LOPROC 13
#define STB_HIPROC 15
/* symbol types - page 4-28, figure 4-17 */
#define STT_NOTYPE 0
#define STT_OBJECT 1
#define STT_FUNC 2
#define STT_SECTION 3
#define STT_FILE 4
#define STT_LOPROC 13
#define STT_HIPROC 15
/* Macros to split/combine relocation type and symbol page 4-32 */
#define ELF32_R_SYM(__i) ((__i)>>8)
#define ELF32_R_TYPE(__i) ((unsigned char) (__i))
#define ELF32_R_INFO(__s, __t) (((__s)<<8) + (unsigned char) (__t))
/* program header - page 5-2, figure 5-1 */
typedef struct {
Elf32_Word p_type;
Elf32_Off p_offset;
Elf32_Addr p_vaddr;
Elf32_Addr p_paddr;
Elf32_Word p_filesz;
Elf32_Word p_memsz;
Elf32_Word p_flags;
Elf32_Word p_align;
} Elf32_Phdr;
/* segment types - page 5-3, figure 5-2 */
#define PT_NULL 0
#define PT_LOAD 1
#define PT_DYNAMIC 2
#define PT_INTERP 3
#define PT_NOTE 4
#define PT_SHLIB 5
#define PT_PHDR 6
#define PT_LOPROC 0x70000000
#define PT_HIPROC 0x7fffffff
/* segment permissions - page 5-6 */
#define PF_X 0x1
#define PF_W 0x2
#define PF_R 0x4
#define PF_MASKPROC 0xf0000000
/* dynamic structure - page 5-15, figure 5-9 */
typedef struct {
Elf32_Sword d_tag;
union {
Elf32_Word d_val;
Elf32_Addr d_ptr;
} d_un;
} Elf32_Dyn;
/* Dynamic array tags - page 5-16, figure 5-10. */
#define DT_NULL 0
#define DT_NEEDED 1
#define DT_PLTRELSZ 2
#define DT_PLTGOT 3
#define DT_HASH 4
#define DT_STRTAB 5
#define DT_SYMTAB 6
#define DT_RELA 7
#define DT_RELASZ 8
#define DT_RELAENT 9
#define DT_STRSZ 10
#define DT_SYMENT 11
#define DT_INIT 12
#define DT_FINI 13
#define DT_SONAME 14
#define DT_RPATH 15
#define DT_SYMBOLIC 16
#define DT_REL 17
#define DT_RELSZ 18
#define DT_RELENT 19
#define DT_PLTREL 20
#define DT_DEBUG 21
#define DT_TEXTREL 22
#define DT_JMPREL 23

156
shared_src/imgact_aout.h Normal file
View file

@ -0,0 +1,156 @@
/*-
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* from: @(#)exec.h 8.1 (Berkeley) 6/11/93
* $Id$
*/
/*
* 11/23/95 - Kludge to get "ntohl" null macro added. -- ESB
* - and for __LDPGSZ
*/
#ifndef _IMGACT_AOUT_H_
#define _IMGACT_AOUT_H_
/* XXX ESB */
#define ntohl(x) ((x << 24) | ((x & 0xFF00) << 8) \
| ((x >> 8) & 0xFF00) | (x >> 24))
#define htonl(x) ntohl(x)
#define __LDPGSZ 0x1000
#define N_GETMAGIC(ex) \
( (ex).a_midmag & 0xffff )
#define N_GETMID(ex) \
( (N_GETMAGIC_NET(ex) == ZMAGIC) ? N_GETMID_NET(ex) : \
((ex).a_midmag >> 16) & 0x03ff )
#define N_GETFLAG(ex) \
( (N_GETMAGIC_NET(ex) == ZMAGIC) ? N_GETFLAG_NET(ex) : \
((ex).a_midmag >> 26) & 0x3f )
#define N_SETMAGIC(ex,mag,mid,flag) \
( (ex).a_midmag = (((flag) & 0x3f) <<26) | (((mid) & 0x03ff) << 16) | \
((mag) & 0xffff) )
#define N_GETMAGIC_NET(ex) \
(ntohl((ex).a_midmag) & 0xffff)
#define N_GETMID_NET(ex) \
((ntohl((ex).a_midmag) >> 16) & 0x03ff)
#define N_GETFLAG_NET(ex) \
((ntohl((ex).a_midmag) >> 26) & 0x3f)
#define N_SETMAGIC_NET(ex,mag,mid,flag) \
( (ex).a_midmag = htonl( (((flag)&0x3f)<<26) | (((mid)&0x03ff)<<16) | \
(((mag)&0xffff)) ) )
#define N_ALIGN(ex,x) \
(N_GETMAGIC(ex) == ZMAGIC || N_GETMAGIC(ex) == QMAGIC || \
N_GETMAGIC_NET(ex) == ZMAGIC || N_GETMAGIC_NET(ex) == QMAGIC ? \
((x) + __LDPGSZ - 1) & ~(unsigned long)(__LDPGSZ - 1) : (x))
/* Valid magic number check. */
#define N_BADMAG(ex) \
(N_GETMAGIC(ex) != OMAGIC && N_GETMAGIC(ex) != NMAGIC && \
N_GETMAGIC(ex) != ZMAGIC && N_GETMAGIC(ex) != QMAGIC && \
N_GETMAGIC_NET(ex) != OMAGIC && N_GETMAGIC_NET(ex) != NMAGIC && \
N_GETMAGIC_NET(ex) != ZMAGIC && N_GETMAGIC_NET(ex) != QMAGIC)
/* Address of the bottom of the text segment. */
#define N_TXTADDR(ex) \
((N_GETMAGIC(ex) == OMAGIC || N_GETMAGIC(ex) == NMAGIC || \
N_GETMAGIC(ex) == ZMAGIC) ? 0 : __LDPGSZ)
/* Address of the bottom of the data segment. */
#define N_DATADDR(ex) \
N_ALIGN(ex, N_TXTADDR(ex) + (ex).a_text)
/* Text segment offset. */
#define N_TXTOFF(ex) \
(N_GETMAGIC(ex) == ZMAGIC ? __LDPGSZ : (N_GETMAGIC(ex) == QMAGIC || \
N_GETMAGIC_NET(ex) == ZMAGIC) ? 0 : sizeof(struct exec))
/* Data segment offset. */
#define N_DATOFF(ex) \
N_ALIGN(ex, N_TXTOFF(ex) + (ex).a_text)
/* Relocation table offset. */
#define N_RELOFF(ex) \
N_ALIGN(ex, N_DATOFF(ex) + (ex).a_data)
/* Symbol table offset. */
#define N_SYMOFF(ex) \
(N_RELOFF(ex) + (ex).a_trsize + (ex).a_drsize)
/* String table offset. */
#define N_STROFF(ex) (N_SYMOFF(ex) + (ex).a_syms)
/*
* Header prepended to each a.out file.
* only manipulate the a_midmag field via the
* N_SETMAGIC/N_GET{MAGIC,MID,FLAG} macros in a.out.h
*/
struct exec {
unsigned long a_midmag; /* htonl(flags<<26 | mid<<16 | magic) */
unsigned long a_text; /* text segment size */
unsigned long a_data; /* initialized data size */
unsigned long a_bss; /* uninitialized data size */
unsigned long a_syms; /* symbol table size */
unsigned long a_entry; /* entry point */
unsigned long a_trsize; /* text relocation size */
unsigned long a_drsize; /* data relocation size */
};
#define a_magic a_midmag /* XXX Hack to work with current kern_execve.c */
/* a_magic */
#define OMAGIC 0x107 /* 0407 old impure format */
#define NMAGIC 0x108 /* 0410 read-only text */
#define ZMAGIC 0x10b /* 0413 demand load format */
#define QMAGIC 0xcc /* 0314 "compact" demand load format */
/* a_mid */
#define MID_ZERO 0 /* unknown - implementation dependent */
#define MID_SUN010 1 /* sun 68010/68020 binary */
#define MID_SUN020 2 /* sun 68020-only binary */
#define MID_I386 134 /* i386 BSD binary */
#define MID_SPARC 138 /* sparc */
#define MID_HP200 200 /* hp200 (68010) BSD binary */
#define MID_HP300 300 /* hp300 (68020+68881) BSD binary */
#define MID_HPUX 0x20C /* hp200/300 HP-UX binary */
#define MID_HPUX800 0x20B /* hp800 HP-UX binary */
/*
* a_flags
*/
#define EX_PIC 0x10 /* contains position independant code */
#define EX_DYNAMIC 0x20 /* contains run-time link-edit info */
#define EX_DPMASK 0x30 /* mask for the above */
#endif /* !_IMGACT_AOUT_H_ */

79
shared_src/mb_header.h Normal file
View file

@ -0,0 +1,79 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1996 Erich Boleyn <erich@uruk.org>
*
* 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.
*/
/*
* MultiBoot Header description
*/
struct multiboot_header
{
/* Must be MULTIBOOT_MAGIC - see below. */
unsigned magic;
/* Feature flags - see below. */
unsigned flags;
/*
* Checksum
*
* The above fields plus this one must equal 0 mod 2^32.
*/
unsigned checksum;
/* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */
unsigned header_addr;
unsigned load_addr;
unsigned load_end_addr;
unsigned bss_end_addr;
unsigned entry_addr;
};
/*
* The entire multiboot_header must be contained
* within the first MULTIBOOT_SEARCH bytes of the kernel image.
*/
#define MULTIBOOT_SEARCH 8192
#define MULTIBOOT_FOUND(addr, len) \
(!((addr) & 0x3) && ((len) >= 12) && (*((int *)(addr)) == MULTIBOOT_MAGIC) \
&& !(*((unsigned *)(addr)) + *((unsigned *)(addr+4)) \
+ *((unsigned *)(addr+8))) \
&& (!(MULTIBOOT_AOUT_KLUDGE & *((int *)(addr+4))) || ((len) >= 32)))
/* Magic value identifying the multiboot_header. */
#define MULTIBOOT_MAGIC 0x1BADB002
/*
* Features flags for 'flags'.
* If a boot loader sees a flag in MULTIBOOT_MUSTKNOW set
* and it doesn't understand it, it must fail.
*/
#define MULTIBOOT_MUSTKNOW 0x0000FFFF
/* currently unsupported flags... this is a kind of version number. */
#define MULTIBOOT_UNSUPPORTED 0x0000FFFC
/* Align all boot modules on i386 page (4KB) boundaries. */
#define MULTIBOOT_PAGE_ALIGN 0x00000001
/* Must pass memory information to OS. */
#define MULTIBOOT_MEMORY_INFO 0x00000002
/* This flag indicates the use of the other fields in the header. */
#define MULTIBOOT_AOUT_KLUDGE 0x00010000

141
shared_src/mb_info.h Normal file
View file

@ -0,0 +1,141 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1996 Erich Boleyn <erich@uruk.org>
*
* 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.
*/
/*
* The structure type "mod_list" is used by the "multiboot_info" structure.
*/
struct mod_list
{
/* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */
unsigned long mod_start;
unsigned long mod_end;
/* Module command line */
unsigned long cmdline;
/* padding to take it to 16 bytes (must be zero) */
unsigned long pad;
};
/*
* INT-15, AX=E820 style "AddressRangeDescriptor"
* ...with a "size" parameter on the front which is the structure size - 4,
* pointing to the next one, up until the full buffer length of the memory
* map has been reached.
*/
struct AddrRangeDesc
{
unsigned long size;
unsigned long BaseAddrLow;
unsigned long BaseAddrHigh;
unsigned long LengthLow;
unsigned long LengthHigh;
unsigned long Type;
/* unspecified optional padding... */
};
/* usable memory "Type", all others are reserved. */
#define MB_ARD_MEMORY 1
/*
* MultiBoot Info description
*
* This is the struct passed to the boot image. This is done by placing
* its address in the EAX register.
*/
struct multiboot_info
{
/* MultiBoot info version number */
unsigned long flags;
/* Available memory from BIOS */
unsigned long mem_lower;
unsigned long mem_upper;
/* "root" partition */
unsigned long boot_device;
/* Kernel command line */
unsigned long cmdline;
/* Boot-Module list */
unsigned long mods_count;
unsigned long mods_addr;
union
{
struct
{
/* (a.out) Kernel symbol table info */
unsigned long tabsize;
unsigned long strsize;
unsigned long addr;
unsigned long pad;
} a;
struct
{
/* (ELF) Kernel section header table */
unsigned long num;
unsigned long size;
unsigned long addr;
unsigned long shndx;
} e;
} syms;
/* Memory Mapping buffer */
unsigned long mmap_length;
unsigned long mmap_addr;
};
/*
* Flags to be set in the 'flags' parameter above
*/
/* is there basic lower/upper memory information? */
#define MB_INFO_MEMORY 0x1
/* is there a boot device set? */
#define MB_INFO_BOOTDEV 0x2
/* is the command-line defined? */
#define MB_INFO_CMDLINE 0x4
/* are there modules to do something with? */
#define MB_INFO_MODS 0x8
/* These next two are mutually exclusive */
/* is there a symbol table loaded? */
#define MB_INFO_AOUT_SYMS 0x10
/* is there an ELF section header table? */
#define MB_INFO_ELF_SHDR 0x20
/* is there a full memory map? */
#define MB_INFO_MEM_MAP 0x40
/*
* The following value must be present in the EAX register.
*/
#define MULTIBOOT_VALID 0x2BADB002

202
shared_src/pc_slice.h Normal file
View file

@ -0,0 +1,202 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1996 Erich Boleyn <erich@uruk.org>
*
* 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.
*/
#ifndef _PC_SLICE_H
#define _PC_SLICE_H
/*
* These define the basic PC MBR sector characteristics
*/
#define PC_MBR_SECTOR 0
#define PC_MBR_SIG_OFFSET 510
#define PC_MBR_SIGNATURE 0xaa55
#define PC_SLICE_OFFSET 446
#define PC_SLICE_MAX 4
/*
* Defines to guarantee structural alignment.
*/
#define PC_MBR_CHECK_SIG(mbr_ptr) \
( *( (unsigned short *) (((int) mbr_ptr) + PC_MBR_SIG_OFFSET) ) \
== PC_MBR_SIGNATURE )
#define PC_MBR_SIG(mbr_ptr) \
( *( (unsigned short *) (((int) mbr_ptr) + PC_MBR_SIG_OFFSET) ) )
#define PC_SLICE_FLAG(mbr_ptr, part) \
( *( (unsigned char *) (((int) mbr_ptr) + PC_SLICE_OFFSET \
+ (part << 4)) ) )
#define PC_SLICE_HEAD(mbr_ptr, part) \
( *( (unsigned char *) (((int) mbr_ptr) + PC_SLICE_OFFSET + 1 \
+ (part << 4)) ) )
#define PC_SLICE_SEC(mbr_ptr, part) \
( *( (unsigned char *) (((int) mbr_ptr) + PC_SLICE_OFFSET + 2 \
+ (part << 4)) ) )
#define PC_SLICE_CYL(mbr_ptr, part) \
( *( (unsigned char *) (((int) mbr_ptr) + PC_SLICE_OFFSET + 3 \
+ (part << 4)) ) )
#define PC_SLICE_TYPE(mbr_ptr, part) \
( *( (unsigned char *) (((int) mbr_ptr) + PC_SLICE_OFFSET + 4 \
+ (part << 4)) ) )
#define PC_SLICE_EHEAD(mbr_ptr, part) \
( *( (unsigned char *) (((int) mbr_ptr) + PC_SLICE_OFFSET + 5 \
+ (part << 4)) ) )
#define PC_SLICE_ESEC(mbr_ptr, part) \
( *( (unsigned char *) (((int) mbr_ptr) + PC_SLICE_OFFSET + 6 \
+ (part << 4)) ) )
#define PC_SLICE_ECYL(mbr_ptr, part) \
( *( (unsigned char *) (((int) mbr_ptr) + PC_SLICE_OFFSET + 7 \
+ (part << 4)) ) )
#define PC_SLICE_START(mbr_ptr, part) \
( *( (unsigned long *) (((int) mbr_ptr) + PC_SLICE_OFFSET + 8 \
+ (part << 4)) ) )
#define PC_SLICE_LENGTH(mbr_ptr, part) \
( *( (unsigned long *) (((int) mbr_ptr) + PC_SLICE_OFFSET + 12 \
+ (part << 4)) ) )
/*
* PC flag types are defined here.
*/
#define PC_SLICE_FLAG_NONE 0
#define PC_SLICE_FLAG_BOOTABLE 0x80
/*
* Known PC partition types are defined here.
*/
#define PC_SLICE_TYPE_NONE 0
#define PC_SLICE_TYPE_FAT12 1
#define PC_SLICE_TYPE_FAT16_LT32M 4
#define PC_SLICE_TYPE_EXTENDED 5
#define PC_SLICE_TYPE_FAT16_GT32M 6
#define PC_SLICE_TYPE_EXT2FS 0x83
/* this next one is special, as it uses it's own partitioning scheme
to subdivide the PC partition from there */
#define PC_SLICE_TYPE_BSD 0xa5
/*
* *BSD-style disklabel & partition definitions.
*
* This is a subdivided slice of type 'PC_SLICE_TYPE_BSD', so all of
* these, except where noted, are relative to the slice in question.
*/
#define BSD_LABEL_SECTOR 1
#define BSD_LABEL_MAGIC 0x82564557
#define BSD_LABEL_MAG_OFFSET 0
#define BSD_LABEL_MAG2_OFFSET 132
#define BSD_LABEL_NPARTS_OFFSET 138
#define BSD_LABEL_NPARTS_MAX 8
#define BSD_PART_OFFSET 148
/*
* Defines to guarantee structural alignment.
*/
#define BSD_LABEL_CHECK_MAG(l_ptr) \
( *( (unsigned long *) (((int) l_ptr) + BSD_LABEL_MAG_OFFSET) ) \
== ( (unsigned long) BSD_LABEL_MAGIC ) )
#define BSD_LABEL_MAG(l_ptr) \
( *( (unsigned long *) (((int) l_ptr) + BSD_LABEL_MAG_OFFSET) ) )
#define BSD_LABEL_DTYPE(l_ptr) \
( *( (unsigned short *) (((int) l_ptr) + BSD_LABEL_MAG_OFFSET + 4) ) )
#define BSD_LABEL_NPARTS(l_ptr) \
( *( (unsigned short *) (((int) l_ptr) + BSD_LABEL_NPARTS_OFFSET) ) )
#define BSD_PART_LENGTH(l_ptr, part) \
( *( (unsigned long *) (((int) l_ptr) + BSD_PART_OFFSET \
+ (part << 4)) ) )
#define BSD_PART_START(l_ptr, part) \
( *( (unsigned long *) (((int) l_ptr) + BSD_PART_OFFSET + 4 \
+ (part << 4)) ) )
#define BSD_PART_FRAG_SIZE(l_ptr, part) \
( *( (unsigned long *) (((int) l_ptr) + BSD_PART_OFFSET + 8 \
+ (part << 4)) ) )
#define BSD_PART_TYPE(l_ptr, part) \
( *( (unsigned char *) (((int) l_ptr) + BSD_PART_OFFSET + 12 \
+ (part << 4)) ) )
#define BSD_PART_FRAGS_PER_BLOCK(l_ptr, part) \
( *( (unsigned char *) (((int) l_ptr) + BSD_PART_OFFSET + 13 \
+ (part << 4)) ) )
#define BSD_PART_EXTRA(l_ptr, part) \
( *( (unsigned short *) (((int) l_ptr) + BSD_PART_OFFSET + 14 \
+ (part << 4)) ) )
/* possible values for the "DISKTYPE"... all essentially irrelevant
except for DTYPE_SCSI */
#define DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */
#define DTYPE_MSCP 2 /* MSCP */
#define DTYPE_DEC 3 /* other DEC (rk, rl) */
#define DTYPE_SCSI 4 /* SCSI */
#define DTYPE_ESDI 5 /* ESDI interface */
#define DTYPE_ST506 6 /* ST506 etc. */
#define DTYPE_HPIB 7 /* CS/80 on HP-IB */
#define DTYPE_HPFL 8 /* HP Fiber-link */
#define DTYPE_FLOPPY 10 /* floppy */
/* possible values for the *BSD-style partition type */
#define FS_UNUSED 0 /* unused */
#define FS_SWAP 1 /* swap */
#define FS_V6 2 /* Sixth Edition */
#define FS_V7 3 /* Seventh Edition */
#define FS_SYSV 4 /* System V */
#define FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */
#define FS_V8 6 /* Eighth Edition, 4K blocks */
#define FS_BSDFFS 7 /* 4.2BSD fast file system */
#define FS_MSDOS 8 /* MSDOS file system */
#define FS_BSDLFS 9 /* 4.4BSD log-structured file system */
#define FS_OTHER 10 /* in use, but unknown/unsupported */
#define FS_HPFS 11 /* OS/2 high-performance file system */
#define FS_ISO9660 12 /* ISO 9660, normally CD-ROM */
#define FS_BOOT 13 /* partition contains bootstrap */
#endif /* _PC_SLICE_H */

483
shared_src/shared.h Normal file
View file

@ -0,0 +1,483 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1996 Erich Boleyn <erich@uruk.org>
*
* 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.
*/
/*
* Generic defines to use anywhere
*/
/*
* Integer sizes
*/
#define MAXINT 0x7FFFFFFF
/*
* This is the location of the raw device buffer. It is 31.5K
* in size.
*/
#define BUFFERSEG 0x7000
#define BUFFERADDR 0x70000
/* 512-byte scratch area */
#define SCRATCHSEG 0x77e0
#define SCRATCHADDR 0x77e00
/*
* BIOS disk defines
*/
#define BIOSDISK_SUBFUNC_READ 0x2
#define BIOSDISK_SUBFUNC_WRITE 0x3
#define BIOSDISK_ERROR_GEOMETRY 0x100
/*
* This is the location of the filesystem (not raw device) buffer.
* It is 32K in size, do not overrun!
*/
#define FSYS_BUF 0x68000
/*
* Linux setup parameters
*/
#define LINUX_STAGING_AREA 0x100000
#define LINUX_SETUP 0x90000
#define LINUX_SETUP_MAXLEN 0x1E00
#define LINUX_KERNEL 0x10000
#define LINUX_KERNEL_MAXLEN 0x7F000
#define LINUX_SETUP_SEG 0x9020
#define LINUX_INIT_SEG 0x9000
#define LINUX_KERNEL_LEN_OFFSET 0x1F4
#define LINUX_SETUP_LEN_OFFSET 0x1F1
#define LINUX_SETUP_STACK 0x3FF4
#define CL_MY_LOCATION 0x92000
#define CL_MY_END_ADDR 0x920FF
#define CL_MAGIC_ADDR 0x90020
#define CL_MAGIC 0xA33F
#define CL_BASE_ADDR 0x90000
#define CL_OFFSET 0x90022
/*
* General disk stuff
*/
#define SECTOR_SIZE 0x200
#define BIOS_FLAG_FIXED_DISK 0x80
#define BOOTSEC_LOCATION 0x7C00
#define BOOTSEC_SIGNATURE 0xAA55
#define BOOTSEC_BPB_OFFSET 0x3
#define BOOTSEC_BPB_LENGTH 0x3B
#define BOOTSEC_PART_OFFSET 0x1BE
#define BOOTSEC_PART_LENGTH 0x40
#define BOOTSEC_SIG_OFFSET 0x1FE
/*
* GRUB specific information
* (in LSB order)
*/
#define COMPAT_VERSION_MAJOR 1
#define COMPAT_VERSION_MINOR 0
#define COMPAT_VERSION ((COMPAT_VERSION_MINOR<<8)|COMPAT_VERSION_MAJOR)
#define STAGE1_VER_MAJ_OFFS 0x1bc
#define STAGE1_INSTALLSEG 0x1ba
#define STAGE1_INSTALLADDR 0x1b8
#define STAGE1_FIRSTLIST 0x1b0
#define STAGE2_VER_MAJ_OFFS 0x6
#define STAGE2_INSTALLPART 0x8
#define STAGE2_VER_STR_OFFS 0xc
/*
* defines for use when switching between real and protected mode
*/
#define data32 .byte 0x66
#define addr32 .byte 0x67
#define CR0_PE_ON 0x1
#define CR0_PE_OFF 0xfffffffe
#define PROT_MODE_CSEG 0x8
#define PROT_MODE_DSEG 0x10
#define PSEUDO_RM_CSEG 0x18
#define PSEUDO_RM_DSEG 0x20
#define STACKOFF 0x2000 - 0x10
#define PROTSTACKINIT FSYS_BUF - 0x10
/*
* Assembly code defines
*
* "EXT_C" is assumed to be defined in the Makefile by the configure
* command.
*/
#define ENTRY(x) .globl EXT_C(x) ; EXT_C(x) ## :
#define VARIABLE(x) ENTRY(x)
#define K_RDWR 0x60 /* keyboard data & cmds (read/write) */
#define K_STATUS 0x64 /* keyboard status */
#define K_CMD 0x64 /* keybd ctlr command (write-only) */
#define K_OBUF_FUL 0x01 /* output buffer full */
#define K_IBUF_FUL 0x02 /* input buffer full */
#define KC_CMD_WIN 0xd0 /* read output port */
#define KC_CMD_WOUT 0xd1 /* write output port */
#define KB_OUTPUT_MASK 0xdd /* enable output buffer full interrupt
enable data line
enable clock line */
#define KB_A20_ENABLE 0x02
#ifndef ASM_FILE
/*
* Below this should be ONLY defines and other constructs for C code.
*/
static inline unsigned char
inb(unsigned short port)
{
unsigned char data;
__asm __volatile("inb %1,%0" : "=a" (data) : "d" (port));
return data;
}
static inline void
outb(unsigned short port, unsigned char val)
{
__asm __volatile("outb %0,%1" : :"a" (val), "d" (port));
}
/* multiboot stuff */
#include "mb_header.h"
#include "mb_info.h"
extern char end[]; /* will be the end of the bss */
/* this function must be called somewhere... */
void cmain(void) __attribute__ ((noreturn));
#define NULL ((void *) 0)
/*
* From "asm.S"
*/
extern unsigned long install_partition;
extern unsigned long boot_drive;
extern char version_string[];
extern char config_file[];
/* calls for direct boot-loader chaining */
void chain_stage1(int segment, int offset, int part_table_addr)
__attribute__ ((noreturn));
void chain_stage2(int segment, int offset) __attribute__ ((noreturn));
/* do some funky stuff, then boot linux */
void linux_boot(void) __attribute__ ((noreturn));
/* booting a multiboot executable */
void multi_boot(int start, int mbi) __attribute__ ((noreturn));
/* sets it to linear or wired A20 operation */
void gateA20(int linear);
/* memory probe routines */
int get_memsize(int type);
int get_eisamemsize(void);
int get_mmap_entry(int buf, int cont);
/* low-level timing info */
int getrtsecs(void);
/* low-level character I/O */
void cls(void);
int getxy(void); /* returns packed values, LSB+1 is x, LSB is y */
void gotoxy(int x, int y);
/* displays an ASCII character. IBM displays will translate some
characters to special graphical ones */
#define DISP_UL 218
#define DISP_UR 191
#define DISP_LL 192
#define DISP_LR 217
#define DISP_HORIZ 196
#define DISP_VERT 179
#define DISP_LEFT 0x1b
#define DISP_RIGHT 0x1a
#define DISP_UP 0x18
#define DISP_DOWN 0x19
void putchar(int c);
/* returns packed BIOS/ASCII code */
#define BIOS_CODE(x) ((x) >> 8)
#define ASCII_CHAR(x) ((x) & 0xFF)
#define KEY_LEFT 0x4B00
#define KEY_RIGHT 0x4D00
#define KEY_UP 0x4800
#define KEY_DOWN 0x5000
#define KEY_INSERT 0x5200
#define KEY_DELETE 0x5300
#define KEY_HOME 0x4700
#define KEY_END 0x4F00
#define KEY_PGUP 0x4900
#define KEY_PGDN 0x5100
int asm_getkey(void);
/* returns 0 if non-ASCII character */
#define getc() ASCII_CHAR(getkey())
/* like 'getkey', but doesn't wait, returns -1 if nothing available */
int checkkey(void);
/* sets text mode character attribute at the cursor position */
#define ATTRIB_NORMAL 0x7
#define ATTRIB_INVERSE 0x70
void set_attrib(int attr);
/* low-level disk I/O */
int get_diskinfo(int drive);
int biosdisk(int subfunc, int drive, int geometry,
int sector, int nsec, int segment);
/*
* From "cmdline.c"
*/
#ifndef _CMDLINE_C
extern int fallback;
extern char commands[];
#endif /* _CMDLINE_C */
char *skip_to(int after_equal, char *cmdline);
void init_cmdline(void);
int enter_cmdline(char *script, char *heap);
/*
* From "char_io.c"
*/
#ifndef _CHAR_IO_C
int special_attribute;
#endif /* _CHAR_IO_C */
#define ERR_NONE 0
#define ERR_WONT_FIT (ERR_NONE + 1)
#define ERR_NO_DISK (ERR_WONT_FIT + 1)
#define ERR_READ (ERR_NO_DISK + 1)
#define ERR_WRITE (ERR_READ + 1)
#define ERR_GEOM (ERR_WRITE + 1)
#define ERR_OUTSIDE_PART (ERR_GEOM + 1)
#define ERR_BAD_PART_TABLE (ERR_OUTSIDE_PART + 1)
#define ERR_NO_PART (ERR_BAD_PART_TABLE + 1)
#define ERR_BAD_FILENAME (ERR_NO_PART + 1)
#define ERR_BAD_FILETYPE (ERR_BAD_FILENAME + 1)
#define ERR_FILE_NOT_FOUND (ERR_BAD_FILETYPE + 1)
#define ERR_FSYS_MOUNT (ERR_FILE_NOT_FOUND + 1)
#define ERR_FSYS_CORRUPT (ERR_FSYS_MOUNT + 1)
#define ERR_FILELENGTH (ERR_FSYS_CORRUPT + 1)
#define ERR_NUMBER_PARSING (ERR_FILELENGTH + 1)
#define ERR_DEV_FORMAT (ERR_NUMBER_PARSING + 1)
#define ERR_DEV_VALUES (ERR_DEV_FORMAT + 1)
#define ERR_EXEC_FORMAT (ERR_DEV_VALUES + 1)
#define ERR_BELOW_1MB (ERR_EXEC_FORMAT + 1)
#define ERR_BOOT_FEATURES (ERR_BELOW_1MB + 1)
#define ERR_BOOT_FAILURE (ERR_BOOT_FEATURES + 1)
#define ERR_NEED_KERNEL (ERR_BOOT_FAILURE + 1)
#define ERR_UNRECOGNIZED (ERR_NEED_KERNEL + 1)
#define ERR_BAD_GZIP_HEADER (ERR_UNRECOGNIZED + 1)
#define ERR_BAD_GZIP_DATA (ERR_BAD_GZIP_HEADER + 1)
#define ERR_BAD_VERSION (ERR_BAD_GZIP_DATA + 1)
#define MAX_ERR_NUM (ERR_BAD_VERSION + 1)
/* returns packed BIOS/ASCII code */
#define BIOS_CODE(x) ((x) >> 8)
#define ASCII_CHAR(x) ((x) & 0xFF)
#define KEY_LEFT 0x4B00
#define KEY_RIGHT 0x4D00
#define KEY_UP 0x4800
#define KEY_DOWN 0x5000
#define KEY_INSERT 0x5200
#define KEY_DELETE 0x5300
#define KEY_HOME 0x4700
#define KEY_END 0x4F00
#define KEY_PGUP 0x4900
#define KEY_PGDN 0x5100
int getkey(void); /* actually just calls asm_getkey and invalidates the
disk buffer */
void init_page(void);
void print_error(void);
char *convert_to_ascii(char *buf, int c, ...);
void printf(char *format, ... );
int get_cmdline(char *prompt, char *commands, char *cmdline, int maxlen);
int tolower(int c);
int isspace(int c);
int strncat(char *s1, char *s2, int n);
int strcmp(char *s1, char *s2);
char *strstr(char *s1, char *s2);
int bcopy(char *from, char *to, int len);
int bzero(char *start, int len);
int get_based_digit(int c, int base);
int safe_parse_maxint(char **str_ptr, int *myint_ptr);
int memcheck(int start, int len);
/*
* From "gunzip.c"
*/
#ifndef _GUNZIP_C
extern int no_decompression;
extern int compressed_file;
#endif /* _GUNZIP_C */
int gunzip_test_header(void);
int gunzip_read(int addr, int len);
/*
* From "disk_io.c"
*/
#ifndef _DISK_IO_C
#ifndef NO_FANCY_STUFF
/* instrumentation variables */
extern void (*debug_fs)(int);
extern void (*debug_fs_func)(int);
#endif /* NO_FANCY_STUFF */
extern unsigned long current_drive;
extern unsigned long current_partition;
extern int fsys_type;
#ifndef NO_BLOCK_FILES
extern int block_file;
#endif /* NO_BLOCK_FILES */
extern long part_start;
extern long part_length;
extern int current_slice;
extern int buf_drive;
extern int buf_track;
extern int buf_geom;
/* these are the current file position and maximum file position */
extern int filepos;
extern int filemax;
#endif /* _DISK_IO_C */
int rawread(int drive, int sector, int byte_offset, int byte_len, int addr);
int devread(int sector, int byte_offset, int byte_len, int addr);
int set_device(char *device); /* this gets a device from the string and
places it into the global parameters */
int open_device(void);
int make_saved_active(void); /* sets the active partition to the that
represented by the "saved_" parameters */
int open(char *filename);
int read(int addr, int len); /* if "length" is -1, read all the
remaining data in the file */
int dir(char *dirname); /* list directory, printing all completions */
int bsd_bootdev(void);
void print_fsys_type(void); /* this prints stats on the currently
mounted filesystem */
void print_completions(char *filename); /* this prints device and filename
completions */
void copy_current_part_entry(int addr); /* copies the current partition data
to the desired address */
/*
* From "boot.c"
*/
/* for the entry address */
typedef void
(*entry_func)(int, int, int, int, int, int) __attribute__ ((noreturn));
#ifndef _BOOT_C
extern char *cur_cmdline;
extern entry_func entry_addr;
#endif /* _BOOT_C */
void bsd_boot(int type, int bootdev) __attribute__ ((noreturn));
int load_image(void);
int load_module(void);
/*
* From "common.c"
*/
#ifndef _COMMON_C
/*
* Common BIOS/boot data.
*/
extern struct multiboot_info mbi;
extern unsigned long saved_drive;
extern unsigned long saved_partition;
extern unsigned long saved_mem_upper;
extern int mem_map;
/*
* Error variables.
*/
extern int errnum;
extern char *err_list[];
#endif /* _COMMON_C */
void init_bios_info(void) __attribute__ ((noreturn));
#endif /* ASM_FILE */

42
shared_src/stage1_5.c Normal file
View file

@ -0,0 +1,42 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1996 Erich Boleyn <erich@uruk.org>
*
* 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.
*/
#include "shared.h"
void
cmain(void)
{
printf("\n\nGRUB loading, please wait...\n");
/*
* Here load the true second-stage boot-loader.
*/
if (open(config_file) && read(0x8000, -1))
chain_stage2(0, 0x8000);
/*
* If not, then print error message and die.
*/
print_error();
stop();
}