diff -Naur grub-old/stage2/Makefile.am grub-bsd/stage2/Makefile.am --- grub-old/stage2/Makefile.am Mon Oct 18 11:28:39 2004 +++ grub-bsd/stage2/Makefile.am Mon Oct 18 13:10:18 2004 @@ -7,7 +7,7 @@ fat.h filesys.h freebsd.h fs.h hercules.h i386-elf.h \ imgact_aout.h iso9660.h jfs.h mb_header.h mb_info.h md5.h \ nbi.h pc_slice.h serial.h shared.h smp-imps.h term.h \ - terminfo.h tparm.h nbi.h ufs2.h vstafs.h xfs.h + terminfo.h tparm.h nbi.h ufs2.h vstafs.h xfs.h env.h EXTRA_DIST = setjmp.S apm.S $(noinst_SCRIPTS) # For . @@ -19,7 +19,7 @@ disk_io.c fsys_ext2fs.c fsys_fat.c fsys_ffs.c fsys_iso9660.c \ fsys_jfs.c fsys_minix.c fsys_reiserfs.c fsys_ufs2.c \ fsys_vstafs.c fsys_xfs.c gunzip.c md5.c serial.c stage2.c \ - terminfo.c tparm.c + terminfo.c tparm.c env.c libgrub_a_CFLAGS = $(GRUB_CFLAGS) -I$(top_srcdir)/lib \ -DGRUB_UTIL=1 -DFSYS_EXT2FS=1 -DFSYS_FAT=1 -DFSYS_FFS=1 \ -DFSYS_ISO9660=1 -DFSYS_JFS=1 -DFSYS_MINIX=1 -DFSYS_REISERFS=1 \ @@ -91,7 +91,7 @@ cmdline.c common.c console.c disk_io.c fsys_ext2fs.c \ fsys_fat.c fsys_ffs.c fsys_iso9660.c fsys_jfs.c fsys_minix.c \ fsys_reiserfs.c fsys_ufs2.c fsys_vstafs.c fsys_xfs.c gunzip.c \ - hercules.c md5.c serial.c smp-imps.c stage2.c terminfo.c tparm.c + hercules.c md5.c serial.c smp-imps.c stage2.c terminfo.c tparm.c env.c pre_stage2_exec_CFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS) pre_stage2_exec_CCASFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS) pre_stage2_exec_LDFLAGS = $(PRE_STAGE2_LINK) diff -Naur grub-old/stage2/boot.c grub-bsd/stage2/boot.c --- grub-old/stage2/boot.c Mon Oct 18 11:28:39 2004 +++ grub-bsd/stage2/boot.c Tue Oct 19 20:06:48 2004 @@ -25,9 +25,11 @@ #include "imgact_aout.h" #include "i386-elf.h" -static int cur_addr; +#include "env.h" + +int cur_addr; entry_func entry_addr; -static struct mod_list mll[99]; +struct mod_list mll[99]; static int linux_mem_size; /* @@ -616,6 +618,13 @@ if (memaddr < RAW_ADDR (0x100000)) errnum = ERR_BELOW_1MB; + if ((cur_addr==0) && (type == KERNEL_TYPE_FREEBSD)) + { + mll[0].mod_start=memaddr; + mll[0].cmdline=(int)arg; + mll[0].pad=0; + } + /* If the memory range contains the entry address, get the physical address here. */ if (type == KERNEL_TYPE_MULTIBOOT @@ -755,6 +764,14 @@ return KERNEL_TYPE_NONE; } + if (type == KERNEL_TYPE_FREEBSD) + { + mll[0].mod_end=cur_addr; + mbi.mods_count=1; + mbi.flags |= MB_INFO_MODS; + mbi.mods_addr = (int) mll; + } + return type; } @@ -764,7 +781,7 @@ int len; /* if we are supposed to load on 4K boundaries */ - cur_addr = (cur_addr + 0xFFF) & 0xFFFFF000; + cur_addr=(grub_getopt('a'))?page_align(cur_addr):dword_align(cur_addr); if (!grub_open (module)) return 0; @@ -776,7 +793,8 @@ return 0; } - printf (" [Multiboot-module @ 0x%x, 0x%x bytes]\n", cur_addr, len); + printf (" [%s-module @ 0x%x, 0x%x bytes]\n", + (kernel_type==KERNEL_TYPE_FREEBSD)?"FreeBSD":"Multiboot", cur_addr, len); /* these two simply need to be set if any modules are loaded at all */ mbi.flags |= MB_INFO_MODS; @@ -979,6 +997,78 @@ bi.bi_symtab = 0; bi.bi_esymtab = 0; } + + // Set environment + cur_addr = (grub_getopt('a'))?page_align(cur_addr):dword_align(cur_addr); + bi.bi_envp = cur_addr; + { + char* pp; + + grub_fstenv("FreeBSD.*"); + while ((pp=grub_nxtenv())!=NULL) + { + pp+=8; + if ((*pp=='=') || (*pp==0)) continue; + strcpy((char*)cur_addr,pp); + cur_addr+=strlen(pp)+1; + } + memset((char*)cur_addr,0,1); + cur_addr++; + } + + // Set module infos + cur_addr = (grub_getopt('a'))?page_align(cur_addr):dword_align(cur_addr); + bi.bi_modulep = cur_addr; + for (i=0;i #endif +#include + /* The type of kernel loaded. */ kernel_t kernel_type; /* The boot device. */ @@ -1764,6 +1766,23 @@ return 1; break; + case KERNEL_TYPE_FREEBSD: + { + int len=grub_strlen(arg); + + if (mb_cmdline + len + 17 > (char *) MB_CMDLINE_BUF + MB_CMDLINE_BUFLEN) + { + errnum = ERR_WONT_FIT; + return 1; + } + grub_memmove (mb_cmdline, arg, len); + grub_memmove(mb_cmdline+len, " --type=mfs_root", 17); + if (! load_module (arg, mb_cmdline)) + return 1; + mb_cmdline += len + 17; + break; + } + default: errnum = ERR_NEED_LX_KERNEL; return 1; @@ -2475,6 +2494,30 @@ }; +/* lsmod */ +static int +lsmod_func (char *arg, int flags) +{ + int i; + extern struct mod_list mll[99]; + extern int cur_addr; + + for (i=0;i (char *) MB_CMDLINE_BUF + MB_CMDLINE_BUFLEN) { errnum = ERR_WONT_FIT; @@ -3487,12 +3531,13 @@ "module", module_func, BUILTIN_CMDLINE | BUILTIN_HELP_LIST, - "module FILE [ARG ...]", + "module FILE [--type=TYPE] [ARG ...]", "Load a boot module FILE for a Multiboot format boot image (no" " interpretation of the file contents is made, so users of this" " command must know what the kernel in question expects). The" " rest of the line is passed as the \"module command line\", like" - " the `kernel' command." + " the `kernel' command. For FreeBSD modules, you can specify its" + " type using the --type option." }; @@ -4338,6 +4383,121 @@ #endif /* SUPPORT_SERIAL */ +/* show */ +static int +show_func (char *arg, int flags) +{ + if (*arg==0) { grub_prtopt(); grub_prtenv(); } else + do + { + char* ev; + + ev=get_str(&arg); + if (*ev=='-') + { + if (*(ev+1)==0) grub_prtopt(); else + { + int rs; + + rs=grub_getopt(*(++ev)); + if (rs!=-1) printf("%c%c\n",(rs)?'+':'-',*ev); + } + } else + if (*ev) + { + char* pp; + + grub_fstenv(ev); + while ((pp=grub_nxtenv())!=NULL) + printf("%s\n",pp); + } + } while (*arg); + return 0; +} + +static struct builtin builtin_show = +{ + "show", + show_func, + BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST, + "show [name ...]", + "Show the value of variable or option" +}; + + +/* set */ +static int +set_func (char *arg, int flags) +{ + if (*arg==0) show_func(arg,flags); else + do + { + char* ev; + + ev=get_str(&arg); + if (*ev=='-') + { + if (grub_setopt(*(++ev))) + printf("Option %c is not supported\n",ev); + } else + if (*ev) + { + char *nn; + + nn=ev; + while ((*nn!='=') && (*nn)) nn++; + if (*nn=='=') *(nn++)=0; + if ((*ev) && (grub_setenv(ev,nn))) + printf("Variable %s too long\n",ev); + } + } while (*arg); + return 0; +} + +static struct builtin builtin_set = +{ + "set", + set_func, + BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST, + "set [-op | +op | name=value]", + "Set environment variable or option. Variable name can be any string" + " that doesn\'t begin with - . Option is a single character in the" + " range of \"a\"-\"z\", \"A\"-\"Z\", and \"0\"-\"9\"." +}; + + +/* unset */ +static int +unset_func (char *arg, int flags) +{ + if (*arg=='*') grub_clsenv(); else + while (*arg) + { + char* ev; + + ev=get_str(&arg); + if (*ev=='-') + { + if (*(ev+1)==0) grub_clsopt(); else + if (grub_unsetopt(*(++ev))) + printf("Option %c is not supported\n",ev); + } else + if (*ev) grub_unsetenv(ev); + } + return 0; +} + +static struct builtin builtin_unset= +{ + "unset", + unset_func, + BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST, + "unset [parm | *]", + "Unset environment variable. Use \"unset *\" to clear all variables." + " Use \"unset -\" to clear all options." +}; + + /* setkey */ struct keysym { @@ -5643,6 +5803,7 @@ &builtin_ioprobe, &builtin_kernel, &builtin_lock, + &builtin_lsmod, &builtin_makeactive, &builtin_map, #ifdef USE_MD5_PASSWORDS @@ -5669,8 +5830,10 @@ #ifdef SUPPORT_SERIAL &builtin_serial, #endif /* SUPPORT_SERIAL */ + &builtin_set, &builtin_setkey, &builtin_setup, + &builtin_show, #if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES) &builtin_terminal, #endif /* SUPPORT_SERIAL || SUPPORT_HERCULES */ @@ -5685,6 +5848,7 @@ &builtin_timeout, &builtin_title, &builtin_unhide, + &builtin_unset, &builtin_uppermem, &builtin_vbeprobe, &builtin_write, diff -Naur grub-old/stage2/cmdline.c grub-bsd/stage2/cmdline.c --- grub-old/stage2/cmdline.c Mon Oct 18 11:28:39 2004 +++ grub-bsd/stage2/cmdline.c Mon Oct 18 18:38:48 2004 @@ -46,6 +46,32 @@ return cmdline; } +/* This new function extract string from cmd */ +char* +get_str(char** cmd) +{ + char *p1,*p2; + + p2=*cmd; + p1=p2; + if (*p2=='\"') + { + p1++; + p2++; + while ((*p2!='"') && (*p2)) p2++; + } else + { + while ((*p2!=' ') && (*p2!='\t') && (*p2)) p2++; + } + if (*p2) + { + *(p2++)=0; + } + while ((*p2==' ') || (*p2=='\t')) p2++; + *cmd=p2; + return p1; +} + /* Print a helpful message for the command-line interface. */ void print_cmdline_message (int forever) diff -Naur grub-old/stage2/env.c grub-bsd/stage2/env.c --- grub-old/stage2/env.c Thu Jan 1 00:00:00 1970 +++ grub-bsd/stage2/env.c Tue Oct 19 19:01:40 2004 @@ -0,0 +1,214 @@ +/* env.c - Environment manipulation function */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. + * + * 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 +#include + +char ev_buf[EV_BUFLEN]; +int ev_len=1; +unsigned long ev_opt0=0,ev_opt1=0; + +int grub_setenv(char* name,char* value) +{ + int len; + + grub_unsetenv(name); + len=strlen(name)+2; + if (value) len+=strlen(value); + if (ev_len+len>EV_BUFLEN) return 1; + ev_len--; + strcpy(&ev_buf[ev_len],name); + ev_len+=strlen(name); + ev_buf[ev_len++]='='; + if (value) + { + strcpy(&ev_buf[ev_len],value); + ev_len+=strlen(value)+1; + } else ev_buf[ev_len++]=0; + ev_buf[ev_len++]=0; + return 0; +} + +int grub_unsetenv(char* name) +{ + char *ev; + + ev=grub_getenv(name); + if (ev==NULL) return 1; else + { + char *s,*d; + int len; + + d=ev-strlen(name)-1; + s=ev+strlen(ev)+1; + len=&ev_buf[ev_len]-s; + memcpy(d,s,len); + ev_len-=(s-d); + } + return 0; +} + +char* grub_getenv(char* name) +{ + char* ev; + int len; + + len=strlen(name); + for (ev=ev_buf;*ev!=0;ev+=strlen(ev)+1) + { + if ((memcmp(ev,name,len)==0) && (*(ev+len)=='=')) + return ev+len+1; + } + return NULL; +} + +void grub_prtenv(void) +{ + char* ev; + + for (ev=ev_buf;*ev!=0;ev+=strlen(ev)+1) + printf("%s\n",ev); +} + +void grub_clsenv(void) +{ + ev_len=1; + ev_buf[0]=0; +} + +static char *ms,*mp; +static int ml,mf; + +void grub_fstenv(char* mask) +{ + ms=mask; + mf=0; + while (*ms=='*') + { + mf|=1; + ms++; + } + if (*ms) + { + char* pp; + + pp=ms+1; + while ((*pp!='*') && (*pp)) pp++; + if (*pp=='*') mf|=2; + ml=pp-ms; + } else ml=0; + mp=ev_buf; +} + +char* grub_nxtenv(void) +{ + while (*mp) + { + char* cp; + + cp=mp; + mp+=strlen(mp)+1; + if (ml==0) return cp; else + { + char *pp; + int nn; + + pp=strstr(cp,"="); + if (pp==NULL) continue; + nn=pp-cp; + if (mf==0) + { + if ((ml==nn) && (memcmp(cp,ms,ml)==0)) return cp; + } else + if (ml<=nn) { + if (mf==1) + { + if (memcmp(cp+(nn-ml),ms,ml)==0) return cp; + } else + if (mf==2) + { + if (memcmp(cp,ms,ml)==0) return cp; + } else + { + int i; + + for (i=0;i<=nn-ml;i++) + if ((cp[i]==ms[0]) && (memcmp(cp+i,ms,ml)==0)) return cp; + } + } + } + } + return NULL; +} + +int grub_setopt(char opt) +{ + if ((opt>='a') && (opt<='z')) ev_opt0 |= (1l<<(opt-'a')); else + if ((opt>='0') && (opt<='4')) ev_opt0 |= (1l<<(opt-'0'+26)); else + if ((opt>='A') && (opt<='Z')) ev_opt1 |= (1l<<(opt-'A')); else + if ((opt>='5') && (opt<='9')) ev_opt1 |= (1l<<(opt-'5'+26)); else + return 1; + return 0; +} + +int grub_unsetopt(char opt) +{ + if ((opt>='a') && (opt<='z')) ev_opt0 &= ~ (1l<<(opt-'a')); else + if ((opt>='0') && (opt<='4')) ev_opt0 &= ~ (1l<<(opt-'0'+26)); else + if ((opt>='A') && (opt<='Z')) ev_opt1 &= ~ (1l<<(opt-'A')); else + if ((opt>='5') && (opt<='9')) ev_opt1 &= ~ (1l<<(opt-'5'+26)); else + return 1; + return 0; +} + +int grub_getopt(char opt) +{ + if ((opt>='a') && (opt<='z')) return ev_opt0 & (1l<<(opt-'a')); else + if ((opt>='0') && (opt<='4')) return ev_opt0 & (1l<<(opt-'0'+26)); else + if ((opt>='A') && (opt<='Z')) return ev_opt1 & (1l<<(opt-'A')); else + if ((opt>='5') && (opt<='9')) return ev_opt1 & (1l<<(opt-'5'+26)); else + return -1; +} + +void grub_prtopt(void) +{ + int i; + unsigned long mk; + + mk=1; + for (i=0;i<26;i++) + { + if (ev_opt0 & mk) putchar(i+'a'); + if (ev_opt1 & mk) putchar(i+'A'); + mk<<=1; + } + for (;i<31;i++) + { + if (ev_opt0 & mk) putchar(i-26+'0'); + if (ev_opt1 & mk) putchar(i-26+'5'); + mk<<=1; + } + putchar('\n'); +} + +void grub_clsopt(void) +{ + ev_opt0=ev_opt1=0; +} diff -Naur grub-old/stage2/env.h grub-bsd/stage2/env.h --- grub-old/stage2/env.h Thu Jan 1 00:00:00 1970 +++ grub-bsd/stage2/env.h Tue Oct 19 18:35:35 2004 @@ -0,0 +1,42 @@ +/* env.h - Header files for env.c */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. + * + * 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 GRUB_ENV_HEADER +#define GRUB_ENV_HEADER + +#define EV_BUFLEN 4096 + +extern char ev_buf[]; +extern int ev_len; + +int grub_setenv(char*,char*); +int grub_unsetenv(char*); +char* grub_getenv(char*); +void grub_prtenv(void); +void grub_clsenv(void); +void grub_fstenv(char*); +char* grub_nxtenv(void); +int grub_setopt(char); +int grub_unsetopt(char); +int grub_getopt(char); +void grub_prtopt(void); +void grub_clsopt(void); + +#endif diff -Naur grub-old/stage2/freebsd.h grub-bsd/stage2/freebsd.h --- grub-old/stage2/freebsd.h Mon Oct 18 11:28:39 2004 +++ grub-bsd/stage2/freebsd.h Tue Oct 19 19:33:08 2004 @@ -92,4 +92,67 @@ unsigned long bi_extmem; unsigned long bi_symtab; unsigned long bi_esymtab; + unsigned long bi_kernend; + unsigned long bi_envp; + unsigned long bi_modulep; }; + +#define page_align(addr) (((addr) + 0xFFF) & 0xFFFFF000) +#define dword_align(addr) (((addr) + 0x3) & 0xFFFFFFFC) + +#define MODINFO_END 0x0000 /* End of list */ +#define MODINFO_NAME 0x0001 /* Name of module (string) */ +#define MODINFO_TYPE 0x0002 /* Type of module (string) */ +#define MODINFO_ADDR 0x0003 /* Loaded address */ +#define MODINFO_SIZE 0x0004 /* Size of module */ +#define MODINFO_EMPTY 0x0005 /* Has been deleted */ +#define MODINFO_ARGS 0x0006 /* Parameters string */ +#define MODINFO_METADATA 0x8000 /* Module-specfic */ + +#define MODINFOMD_AOUTEXEC 0x0001 /* a.out exec header */ +#define MODINFOMD_ELFHDR 0x0002 /* ELF header */ +#define MODINFOMD_SSYM 0x0003 /* start of symbols */ +#define MODINFOMD_ESYM 0x0004 /* end of symbols */ +#define MODINFOMD_DYNAMIC 0x0005 /* _DYNAMIC pointer */ +#define MODINFOMD_NOCOPY 0x8000 /* don't copy this metadata to the kernel */ + +#define MODINFOMD_DEPLIST (0x4001 | MODINFOMD_NOCOPY) /* depends on */ + +#define COPY32(v, a) { \ + unsigned long x = (v); \ + grub_memmove((void*)a, (void*)&x, sizeof(x)); \ + a += sizeof(x); \ +} + +#define MOD_STR(t, a, s) { \ + COPY32(t, a); \ + COPY32(strlen(s) + 1, a); \ + grub_memmove((void*)a, s, strlen(s) + 1); \ + a += dword_align(strlen(s) + 1); \ +} + +#define MOD_NAME(a, s) MOD_STR(MODINFO_NAME, a, s) +#define MOD_TYPE(a, s) MOD_STR(MODINFO_TYPE, a, s) +#define MOD_ARGS(a, s) MOD_STR(MODINFO_ARGS, a, s) + +#define MOD_VAR(t, a, s) { \ + COPY32(t, a); \ + COPY32(sizeof(s), a); \ + grub_memmove((void*)a, &s, sizeof(s)); \ + a += dword_align(sizeof(s)); \ +} + +#define MOD_ADDR(a, s) MOD_VAR(MODINFO_ADDR, a, s) +#define MOD_SIZE(a, s) MOD_VAR(MODINFO_SIZE, a, s) + +#define MOD_METADATA(a, tt, dd, ss) { \ + COPY32(MODINFO_METADATA | tt, a); \ + COPY32(ss, a); \ + grub_memmove((void*)a, dd, ss); \ + a += dword_align(ss); \ +} + +#define MOD_END(a) { \ + COPY32(MODINFO_END, a); \ + COPY32(0, a); \ +} diff -Naur grub-old/stage2/shared.h grub-bsd/stage2/shared.h --- grub-old/stage2/shared.h Mon Oct 18 11:28:39 2004 +++ grub-bsd/stage2/shared.h Mon Oct 18 18:20:42 2004 @@ -876,6 +876,7 @@ void init_builtins (void); void init_config (void); char *skip_to (int after_equal, char *cmdline); +char *get_str (char**); struct builtin *find_command (char *command); void print_cmdline_message (int forever); void enter_cmdline (char *heap, int forever);