Initial revision
This commit is contained in:
commit
f397c4797c
25 changed files with 9215 additions and 0 deletions
1580
shared_src/asm.S
Normal file
1580
shared_src/asm.S
Normal file
File diff suppressed because it is too large
Load diff
540
shared_src/boot.c
Normal file
540
shared_src/boot.c
Normal 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
611
shared_src/char_io.c
Normal 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
890
shared_src/cmdline.c
Normal 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
199
shared_src/common.c
Normal 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
93
shared_src/defs.h
Normal 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
142
shared_src/dir.h
Normal 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
101
shared_src/disk_inode.h
Normal 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
101
shared_src/disk_inode_ffs.h
Normal 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
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
114
shared_src/fat.h
Normal 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
119
shared_src/filesys.h
Normal 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
90
shared_src/freebsd.h
Normal 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
455
shared_src/fs.h
Normal 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
634
shared_src/fsys_ext2fs.c
Normal 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
256
shared_src/fsys_fat.c
Normal 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
267
shared_src/fsys_ffs.c
Normal 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
659
shared_src/gunzip.c
Normal 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
205
shared_src/i386-elf.h
Normal 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
156
shared_src/imgact_aout.h
Normal 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
79
shared_src/mb_header.h
Normal 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
141
shared_src/mb_info.h
Normal 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
202
shared_src/pc_slice.h
Normal 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
483
shared_src/shared.h
Normal 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
42
shared_src/stage1_5.c
Normal 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();
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue