diff --git a/sys/boot/alpha/common/main.c b/sys/boot/alpha/common/main.c index d7f6709fadc6..af337d268c7f 100644 --- a/sys/boot/alpha/common/main.c +++ b/sys/boot/alpha/common/main.c @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: main.c,v 1.2 1998/08/22 10:31:00 dfr Exp $ + * $Id: main.c,v 1.3 1998/08/31 21:10:40 msmith Exp $ */ @@ -118,6 +118,7 @@ main(void) archsw.arch_autoload = alpha_autoload; archsw.arch_getdev = alpha_getdev; archsw.arch_copyin = alpha_copyin; + archsw.arch_copyout = alpha_copyout; archsw.arch_readin = alpha_readin; /* @@ -128,15 +129,6 @@ main(void) */ open("/", O_RDONLY); - /* - * XXX should these be in the MI source? - */ - source("/boot/boot.config"); - printf("\n"); - autoboot(10, NULL); /* try to boot automatically */ - printf("\nType '?' for a list of commands, 'help' for more detailed help.\n"); - /* setenv("prompt", "$currdev>", 1); */ - interact(); /* doesn't return */ } diff --git a/sys/boot/alpha/libalpha/alpha_copy.c b/sys/boot/alpha/libalpha/alpha_copy.c index 9e164de0dbad..250c41692dc6 100644 --- a/sys/boot/alpha/libalpha/alpha_copy.c +++ b/sys/boot/alpha/libalpha/alpha_copy.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id$ + * $Id: alpha_copy.c,v 1.1 1998/08/31 21:10:40 msmith Exp $ */ /* * MD primitives supporting placement of module data @@ -41,6 +41,13 @@ alpha_copyin(void *src, vm_offset_t dest, size_t len) return(len); } +int +alpha_copyout(void *src, vm_offset_t dest, size_t len) +{ + bcopy(src, dest, len); + return(len); +} + int alpha_readin(int fd, vm_offset_t dest, size_t len) { diff --git a/sys/boot/common/bootstrap.h b/sys/boot/common/bootstrap.h index fd78eb7346d7..770ecfd3b609 100644 --- a/sys/boot/common/bootstrap.h +++ b/sys/boot/common/bootstrap.h @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: bootstrap.h,v 1.1.1.1 1998/08/21 03:17:41 msmith Exp $ + * $Id: bootstrap.h,v 1.2 1998/08/31 21:10:42 msmith Exp $ */ #include <sys/types.h> @@ -62,6 +62,8 @@ extern int autoboot(int delay, char *prompt); /* misc.c */ extern char *unargv(int argc, char *argv[]); +extern size_t strlenout(vm_offset_t str); +extern char *strdupout(vm_offset_t str); /* * Modular console support. @@ -123,14 +125,16 @@ struct module_format /* Load function must return EFTYPE if it can't handle the module supplied */ int (* l_load)(char *filename, vm_offset_t dest, struct loaded_module **result); /* Only a loader that will load a kernel (first module) should have an exec handler */ - int (* l_exec)(struct loaded_module *amp); + int (* l_exec)(struct loaded_module *mp); }; extern struct module_format *module_formats[]; /* supplied by consumer */ extern struct loaded_module *loaded_modules; extern int mod_load(char *name, int argc, char *argv[]); +extern int mod_loadobj(char *type, char *name); extern struct loaded_module *mod_findmodule(char *name, char *type); extern void mod_addmetadata(struct loaded_module *mp, int type, size_t size, void *p); extern struct module_metadata *mod_findmetadata(struct loaded_module *mp, int type); +extern void mod_discard(struct loaded_module *mp); /* * Module information subtypes @@ -144,12 +148,18 @@ extern struct module_metadata *mod_findmetadata(struct loaded_module *mp, int ty #define MODINFOMD_AOUTEXEC 0x0001 /* a.out exec header */ #define MODINFOMD_ELFHDR 0x0002 /* ELF header */ +#define MODINFOMD_NOCOPY 0x8000 /* don't copy this metadata to the kernel */ /* MI module loaders */ -extern int aout_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result); +extern int aout_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result); +extern vm_offset_t aout_findsym(char *name, struct loaded_module *mp); /* extern int elf_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result); */ +#define KLD_IDENT_SYMNAME "kld_identifier_" +#define MODINFOMD_KLDIDENT (MODINFOMD_NOCOPY | 0x4000) +#define MODINFOMD_KLDDEP (MODINFOMD_NOCOPY | 0x4001) + #if defined(__ELF__) /* @@ -231,8 +241,36 @@ struct arch_switch int (*arch_getdev)(void **dev, char *name, char **path); /* Copy from local address space to module address space, similar to bcopy() */ int (*arch_copyin)(void *src, vm_offset_t dest, size_t len); + /* Copy to local address space from module address space, similar to bcopy() */ + int (*arch_copyout)(vm_offset_t src, void *dest, size_t len); /* Read from file to module address space, same semantics as read() */ int (*arch_readin)(int fd, vm_offset_t dest, size_t len); }; extern struct arch_switch archsw; +/* + * XXX these belong in a system header + */ +#define KLD_NAMELEN 32 + +struct kld_module_dependancy +{ + char kd_name[KLD_NAMELEN]; + u_int32_t kd_version; +}; + +struct kld_module_identifier +{ + u_int32_t ki_kldversion; + char ki_name[KLD_NAMELEN]; + u_int32_t ki_version; + struct kld_module_dependancy *ki_deps; + int ki_ndeps; + size_t ki_depsize; +}; + +/* + * Use the depsize field in the identifier to correctly index a + * dependancy. + */ +#define KLD_GETDEP(ki, kd, n) (struct kld_module_dependancy *)((char *)(kd) + ((ki)->ki_depsize * (n))) diff --git a/sys/boot/common/commands.c b/sys/boot/common/commands.c index af6a4752daeb..8ed140affa82 100644 --- a/sys/boot/common/commands.c +++ b/sys/boot/common/commands.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id$ + * $Id: commands.c,v 1.1.1.1 1998/08/21 03:17:41 msmith Exp $ */ #include <stand.h> @@ -61,7 +61,7 @@ command_commandlist(int argc, char *argv[]) printf("Available commands:\n"); cmdp = (struct bootblk_command **)Xcommand_set.ls_items; for (i = 0; i < Xcommand_set.ls_length; i++) - if (cmdp[i]->c_name != NULL) + if ((cmdp[i]->c_name != NULL) && (cmdp[i]->c_desc != NULL)) printf(" %-15s %s\n", cmdp[i]->c_name, cmdp[i]->c_desc); return(CMD_OK); } @@ -153,3 +153,38 @@ command_panic(int argc, char *argv[]) cp = unargv(argc - 1, argv + 1); panic(cp); } + +COMMAND_SET(echo, "echo", NULL, command_echo); + +static int +command_echo(int argc, char *argv[]) +{ + char *s; + int nl, ch; + + nl = 0; + optind = 1; + while ((ch = getopt(argc, argv, "n")) != -1) { + switch(ch) { + case 'n': + nl = 1; + break; + case '?': + default: + /* getopt has already reported an error */ + return(CMD_OK); + } + } + argv += (optind); + argc -= (optind); + + s = unargv(argc, argv); + if (s != NULL) { + printf(s); + free(s); + } + if (!nl) + printf("\n"); + return(CMD_OK); +} + diff --git a/sys/boot/common/interp.c b/sys/boot/common/interp.c index a0162ba0a8a0..c58b1c4f3d16 100644 --- a/sys/boot/common/interp.c +++ b/sys/boot/common/interp.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: interp.c,v 1.1.1.1 1998/08/21 03:17:41 msmith Exp $ + * $Id: interp.c,v 1.2 1998/09/01 00:41:24 msmith Exp $ */ /* * Simple commandline interpreter, toplevel and misc. @@ -83,6 +83,24 @@ interact(void) int argc; char **argv; + /* + * Read our default configuration + */ + source("/boot/boot.conf"); + printf("\n"); + /* + * Before interacting, we might want to autoboot + */ + if (getenv("no_autoboot") == NULL) + autoboot(10, NULL); /* try to boot automatically */ + + /* + * Not autobooting, go manual + */ + printf("\nType '?' for a list of commands, 'help' for more detailed help.\n"); + setenv("prompt", "${currdev}>", 1); + + for (;;) { input[0] = '\0'; prompt(); @@ -149,32 +167,29 @@ source(char *filename) } /* - * Emit the current prompt; support primitive embedding of - * environment variables. - * We're a little rude here, modifying the return from getenv(). + * Emit the current prompt; use the same syntax as the parser + * for embedding environment variables. */ static void prompt(void) { - char *p, *cp, *ev, c; + char *p, *cp, *ev; - if ((p = getenv("prompt")) == NULL) - p = ">"; + if ((cp = getenv("prompt")) == NULL) + cp = ">"; + p = strdup(cp); while (*p != 0) { - if (*p == '$') { - for (cp = p + 1; (*cp != 0) && isalpha(*cp); cp++) + if ((*p == '$') && (*(p+1) == '{')) { + for (cp = p + 2; (*cp != 0) && (*cp != '}'); cp++) ; - c = *cp; *cp = 0; - ev = getenv(p + 1); - *cp = c; + ev = getenv(p + 2); - if (ev != NULL) { + if (ev != NULL) printf(ev); - p = cp; - continue; - } + p = cp + 1; + continue; } putchar(*p++); } diff --git a/sys/boot/common/load_aout.c b/sys/boot/common/load_aout.c index 45b632866a0d..5c593724d309 100644 --- a/sys/boot/common/load_aout.c +++ b/sys/boot/common/load_aout.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: aout_freebsd.c,v 1.1.1.1 1998/08/21 03:17:41 msmith Exp $ + * $Id: load_aout.c,v 1.1 1998/08/31 21:10:42 msmith Exp $ */ #include <sys/param.h> @@ -33,10 +33,15 @@ #include <string.h> #include <machine/bootinfo.h> #include <stand.h> +#define _AOUT_INCLUDE_ +#include <nlist.h> +#include <link.h> #include "bootstrap.h" -static int aout_loadimage(int fd, vm_offset_t loadaddr, struct exec *ehdr); +static int aout_loadimage(int fd, vm_offset_t loadaddr, struct exec *ehdr, int kernel); +static vm_offset_t aout_findkldident(struct loaded_module *mp, struct exec *ehdr); +static int aout_fixupkldmod(struct loaded_module *mp, struct exec *ehdr); char *aout_kerneltype = "a.out kernel"; char *aout_moduletype = "a.out module"; @@ -49,12 +54,15 @@ char *aout_moduletype = "a.out module"; int aout_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result) { - struct loaded_module *mp; + struct loaded_module *mp, *kmp; struct exec ehdr; int fd; vm_offset_t addr; int err, kernel; + u_int pad; + mp = NULL; + /* * Open the image, read and validate the a.out header */ @@ -62,35 +70,42 @@ aout_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result) return(EFTYPE); if ((fd = open(filename, O_RDONLY)) == -1) return(errno); - if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) - return(EFTYPE); /* could be EIO, but may be small file */ - if (N_BADMAG(ehdr)) - return(EFTYPE); + if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) { + err = EFTYPE; /* could be EIO, but may be small file */ + goto oerr; + } + if (N_BADMAG(ehdr)) { + err = EFTYPE; + goto oerr; + } /* * Check to see what sort of module we are. * * XXX should check N_GETMID() */ - mp = mod_findmodule(NULL, NULL); + kmp = mod_findmodule(NULL, NULL); if (N_GETFLAG(ehdr) == (EX_DYNAMIC | EX_PIC)) { /* Looks like a kld module */ - if (mp == NULL) { + if (kmp == NULL) { printf("aout_loadmodule: can't load module before kernel\n"); - return(EPERM); + err = EPERM; + goto oerr; } - if (strcmp(aout_kerneltype, mp->m_type)) { - printf("out_loadmodule: can't load module with kernel type '%s'\n", mp->m_type); - return(EPERM); + if (strcmp(aout_kerneltype, kmp->m_type)) { + printf("out_loadmodule: can't load module with kernel type '%s'\n", kmp->m_type); + err = EPERM; + goto oerr; } /* Looks OK, got ahead */ kernel = 0; } else if (N_GETFLAG(ehdr) == 0) { /* Looks like a kernel */ - if (mp != NULL) { + if (kmp != NULL) { printf("aout_loadmodule: kernel already loaded\n"); - return(EPERM); + err = EPERM; + goto oerr; } /* * Calculate destination address based on kernel entrypoint @@ -99,39 +114,56 @@ aout_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result) dest = ehdr.a_entry & 0x100000; if (dest == 0) { printf("aout_loadmodule: not a kernel (maybe static binary?)\n"); - return(EPERM); + err = EPERM; + goto oerr; } kernel = 1; } else { - return(EFTYPE); + err = EFTYPE; + goto oerr; } /* * Ok, we think we should handle this. */ mp = malloc(sizeof(struct loaded_module)); - mp->m_name = strdup(filename); /* XXX should we prune the name? */ + mp->m_name = kernel ? strdup(filename) : NULL; /* XXX should we prune the name? */ mp->m_type = strdup(kernel ? aout_kerneltype : aout_moduletype); - mp->m_args = NULL; /* XXX should we put the bootstrap args here and parse later? */ + mp->m_args = NULL; /* filled in by parent */ mp->m_metadata = NULL; - mp->m_addr = addr = dest; + /* Page-align the load address */ + addr = dest; + pad = (u_int)addr & PAGE_MASK; + if (pad != 0) { + pad = PAGE_SIZE - pad; + addr += pad; + } + mp->m_addr = addr; /* save the aligned load address */ printf("%s at 0x%x\n", filename, addr); - mp->m_size = aout_loadimage(fd, addr, &ehdr); + mp->m_size = aout_loadimage(fd, addr, &ehdr, kernel); if (mp->m_size == 0) goto ioerr; + /* Handle KLD module data */ + if (!kernel && ((err = aout_fixupkldmod(mp, &ehdr)) != 0)) + goto oerr; + /* save exec header as metadata */ mod_addmetadata(mp, MODINFOMD_AOUTEXEC, sizeof(struct exec), &ehdr); /* Load OK, return module pointer */ *result = (struct loaded_module *)mp; - return(0); - + err = 0; + goto out; + ioerr: err = EIO; - close(fd); + oerr: + mod_discard(mp); free(mp); + out: + close(fd); return(err); } @@ -143,17 +175,17 @@ aout_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result) * align the symbol table. */ static int -aout_loadimage(int fd, vm_offset_t loadaddr, struct exec *ehdr) +aout_loadimage(int fd, vm_offset_t loadaddr, struct exec *ehdr, int kernel) { u_int pad; vm_offset_t addr; int ss; - + addr = loadaddr; lseek(fd, N_TXTOFF(*ehdr), SEEK_SET); - + /* text segment */ - printf("text=0x%lx ", ehdr->a_text); + printf(" text=0x%lx ", ehdr->a_text); if (archsw.arch_readin(fd, addr, ehdr->a_text) != ehdr->a_text) return(0); addr += ehdr->a_text; @@ -164,24 +196,23 @@ aout_loadimage(int fd, vm_offset_t loadaddr, struct exec *ehdr) return(0); addr += ehdr->a_data; - /* skip the BSS */ + /* For kernels, we pad the BSS to a page boundary */ + if (kernel) { + pad = (u_int)ehdr->a_bss & PAGE_MASK; + if (pad != 0) { + pad = PAGE_SIZE - pad; + ehdr->a_bss += pad; + } + } printf("bss=0x%lx ", ehdr->a_bss); addr += ehdr->a_bss; - - /* pad to a page boundary */ - pad = (u_int)addr & PAGE_MASK; - if (pad != 0) { - pad = PAGE_SIZE - pad; - addr += pad; - ehdr->a_bss += pad; - } /* symbol table size */ archsw.arch_copyin(&ehdr->a_syms, addr, sizeof(ehdr->a_syms)); addr += sizeof(ehdr->a_syms); /* symbol table */ - printf("symbols=[0x%x+0x%x+0x%lx", pad, sizeof(ehdr->a_syms), ehdr->a_syms); + printf("symbols=[0x%x+0x%lx", sizeof(ehdr->a_syms), ehdr->a_syms); if (archsw.arch_readin(fd, addr, ehdr->a_syms) != ehdr->a_syms) return(0); addr += ehdr->a_syms; @@ -200,3 +231,230 @@ aout_loadimage(int fd, vm_offset_t loadaddr, struct exec *ehdr) return(addr - loadaddr); } + +#define AOUT_RELOC(mp, off) ((mp)->m_addr + (vm_offset_t)(off)) + +/* + * The goal here is to find the one symbol in the loaded object + * which fits the format "kld_identifier_<something>. If there's + * more than one, we fail. + */ +static vm_offset_t +aout_findkldident(struct loaded_module *mp, struct exec *ehdr) +{ + /* XXX much of this can go when we can address the load area directly */ + vm_offset_t sp, ep, cand, stringbase, result; + struct _dynamic dynamic; + struct section_dispatch_table sdt; + struct nzlist nzl; + char *np; + int match; + + /* Get the _DYNAMIC object, which we assume is first in the data segment */ + archsw.arch_copyout(AOUT_RELOC(mp, ehdr->a_text), &dynamic, sizeof(dynamic)); + archsw.arch_copyout(AOUT_RELOC(mp, dynamic.d_un.d_sdt), &sdt, sizeof(struct section_dispatch_table)); + dynamic.d_un.d_sdt = &sdt; /* fix up SDT pointer */ + if (dynamic.d_version != LD_VERSION_BSD) + return(0); + stringbase = AOUT_RELOC(mp, LD_STRINGS(&dynamic)); + + /* start pointer */ + sp = AOUT_RELOC(mp, LD_SYMBOL(&dynamic)); + /* end pointer */ + ep = sp + LD_STABSZ(&dynamic); + + /* + * Walk the entire table comparing names. + */ + match = 0; + result = 0; + for (cand = sp; cand < ep; cand += sizeof(struct nzlist)) { + /* get the entry, check for a name */ + archsw.arch_copyout(cand, &nzl, sizeof(struct nzlist)); + /* is this symbol worth looking at? */ + if ((nzl.nz_strx == 0) || /* no name */ + (nzl.nz_value == 0) || /* not a definition */ + ((nzl.nz_type == N_UNDF+N_EXT) && + (nzl.nz_value != 0) && + (nzl.nz_other == AUX_FUNC))) /* weak function */ + continue; + + np = strdupout(stringbase + nzl.nz_strx); + match = (np[0] == '_') && !strncmp(KLD_IDENT_SYMNAME, np + 1, strlen(KLD_IDENT_SYMNAME)); + free(np); + if (match) { + /* duplicates? */ + if (result) + return(0); + result = AOUT_RELOC(mp, nzl.nz_value); + } + } + return(result); +} + +/* + * Perform extra housekeeping associated with loading a KLD module. + * + * XXX if this returns an error, it seems the heap becomes corrupted. + */ +static int +aout_fixupkldmod(struct loaded_module *mp, struct exec *ehdr) +{ + struct kld_module_identifier kident; + struct kld_module_dependancy *kdeps; + vm_offset_t vp; + size_t dsize; + + /* Find the KLD identifier */ + if ((vp = aout_findkldident(mp, ehdr)) == 0) { + printf("bad a.out module format\n"); + return(EFTYPE); + } + archsw.arch_copyout(vp, &kident, sizeof(struct kld_module_identifier)); + + /* Name the module using the name from the KLD data */ + if (mod_findmodule(kident.ki_name, NULL) != NULL) { + printf("module '%s' already loaded\n", kident.ki_name); + return(EPERM); + } + mp->m_name = strdup(kident.ki_name); + + /* Save the module identifier */ + mod_addmetadata(mp, MODINFOMD_KLDIDENT, sizeof(struct kld_module_identifier), &kident); + + /* Look for dependancy data, add to metadata list */ + if (kident.ki_ndeps > 0) { + dsize = kident.ki_ndeps * kident.ki_depsize; + kdeps = malloc(dsize); + archsw.arch_copyout(AOUT_RELOC(mp, kident.ki_deps), kdeps, dsize); + mod_addmetadata(mp, MODINFOMD_KLDDEP, dsize, kdeps); + free(kdeps); + } + return(0); +} + +#if 0 +/************************************************************/ +/* XXX Arbitrary symbol lookup - unused at this point XXX */ +/* */ +/* Code heavily borrowed from kern/link_aout.c (c) DFR */ +/************************************************************/ + +static long +symbol_hash_value(struct _dynamic *dynamic, const char* name) +{ + long hashval; + const char* p; + + hashval = '_'; /* fake a starting '_' for C symbols */ + for (p = name; *p; p++) + hashval = (hashval << 1) + *p; + + return (hashval & 0x7fffffff) % LD_BUCKETS(dynamic); +} + +/* + * Locate the symbol (name) in the a.out object associated with (mp), + * return a vm_offset_t containing the value of the symbol. + */ +static vm_offset_t +aout_findsym(char *name, struct loaded_module *mp) +{ + struct module_metadata *md; + struct exec *ehdr; + struct _dynamic dynamic; + struct section_dispatch_table sdt; + vm_offset_t hashbase, symbolbase, stringbase, hp, np, cp; + struct rrs_hash hash; + struct nzlist nzl; + char *symbol, *asymbol; /* XXX symbol name limit? */ + long hashval; + vm_offset_t result; + + + symbol = NULL; + asymbol = NULL; + result = 0; + + /* Find the exec header */ + if ((md = mod_findmetadata(mp, MODINFOMD_AOUTEXEC)) == NULL) + goto out; + ehdr = (struct exec *)md->md_data; + + /* Get the _DYNAMIC object, which we assume is first in the data segment */ + archsw.arch_copyout(AOUT_RELOC(mp, ehdr->a_text), &dynamic, sizeof(dynamic)); + archsw.arch_copyout(AOUT_RELOC(mp, dynamic.d_un.d_sdt), &sdt, sizeof(struct section_dispatch_table)); + dynamic.d_un.d_sdt = &sdt; /* fix up SDT pointer */ + if ((dynamic.d_version != LD_VERSION_BSD) || + (LD_BUCKETS(&dynamic) == 0)) + goto out; + + hashbase = AOUT_RELOC(mp, LD_HASH(&dynamic)); + symbolbase = AOUT_RELOC(mp, LD_SYMBOL(&dynamic)); + stringbase = AOUT_RELOC(mp, LD_STRINGS(&dynamic)); + +restart: + hashval = symbol_hash_value(&dynamic, name); + hp = hashbase + (hashval * sizeof(struct rrs_hash)); + archsw.arch_copyout(hp, &hash, sizeof(struct rrs_hash)); + if (hash.rh_symbolnum == -1) + goto out; + + while (hp) { + np = symbolbase + (hash.rh_symbolnum * sizeof(struct nzlist)); + archsw.arch_copyout(np, &nzl, sizeof(struct nzlist)); + cp = stringbase + nzl.nz_strx; + if (symbol != NULL) + free(symbol); + symbol = strdupout(cp); + /* + * Note: we fake the leading '_' for C symbols. + */ + if (symbol[0] == '_' && !strcmp(symbol + 1, name)) + break; + + if (hash.rh_next == 0) { + hp = 0; + } else { + hp = hashbase + (hash.rh_next * sizeof(struct rrs_hash)); + archsw.arch_copyout(hp, &hash, sizeof(struct rrs_hash)); + } + } + /* Not found. */ + if (hp == 0) + goto out; + + /* + * Check for an aliased symbol, whatever that is. + */ + if (nzl.nz_type == N_INDR+N_EXT) { + np += sizeof(struct nzlist); + archsw.arch_copyout(np, &nzl, sizeof(struct nzlist)); + asymbol = strdupout(stringbase + nzl.nz_strx + 1); /* +1 for '_' */ + goto restart; + } + + /* + * Check this is an actual definition of the symbol. + */ + if (nzl.nz_value == 0) + goto out; + + if (nzl.nz_type == N_UNDF+N_EXT && nzl.nz_value != 0) + if (nzl.nz_other == AUX_FUNC) + /* weak function */ + goto out; + + /* Return a vm_offset_t pointing to the object itself */ + result = AOUT_RELOC(mp, nzl.nz_value); + + out: + if (symbol) + free(symbol); + if (asymbol) + free(asymbol); + return(result); + +} + +#endif diff --git a/sys/boot/common/ls.c b/sys/boot/common/ls.c index b777c5a771b1..962d4f740869 100644 --- a/sys/boot/common/ls.c +++ b/sys/boot/common/ls.c @@ -1,5 +1,5 @@ /* - * $Id$ + * $Id: ls.c,v 1.1.1.1 1998/08/21 03:17:41 msmith Exp $ * From: $NetBSD: ls.c,v 1.3 1997/06/13 13:48:47 drochner Exp $ */ @@ -57,9 +57,8 @@ command_ls(int argc, char *argv[]) int fd; struct stat sb; size_t size; - char dirbuf[DIRBLKSIZ]; - char pathbuf[128]; /* XXX path length constant? */ - char buf[128]; /* must be long enough for dir entry! */ + static char dirbuf[DIRBLKSIZ]; + static char buf[128]; /* must be long enough for full pathname */ char *path; int result, ch; #ifdef VERBOSE_LS @@ -138,10 +137,12 @@ command_ls(int argc, char *argv[]) if (verbose) { /* stat the file, if possible */ sb.st_size = 0; - sprintf(buf, "%s/%s", pathbuf, dp->d_name); + sprintf(buf, "%s/%s", path, dp->d_name); /* ignore return */ - if (stat(buf, &sb)) + if (stat(buf, &sb)) { + printf("stat(%s) failed: %s\n", buf, strerror(errno)); sb.st_size = -1; + } sprintf(buf, " %c %8d %s\n", typestr[dp->d_type], (int)sb.st_size, dp->d_name); #endif } else diff --git a/sys/boot/common/misc.c b/sys/boot/common/misc.c index 98ec3deb2c52..2999da5ba50f 100644 --- a/sys/boot/common/misc.c +++ b/sys/boot/common/misc.c @@ -23,11 +23,12 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id$ + * $Id: misc.c,v 1.1.1.1 1998/08/21 03:17:41 msmith Exp $ */ #include <string.h> #include <stand.h> +#include <bootstrap.h> /* * Concatenate the (argc) elements of (argv) into a single string, and return @@ -53,3 +54,36 @@ unargv(int argc, char *argv[]) return(cp); } +/* + * Get the length of a string in kernel space + */ +size_t +strlenout(vm_offset_t src) +{ + char c; + size_t len; + + for (len = 0; ; len++) { + archsw.arch_copyout(src++, &c, 1); + if (c == 0) + break; + } + return(len); +} + +/* + * Make a duplicate copy of a string in kernel space + */ +char * +strdupout(vm_offset_t str) +{ + char *result, *cp; + + result = malloc(strlenout(str) + 1); + for (cp = result; ;cp++) { + archsw.arch_copyout(str++, cp, 1); + if (*cp == 0) + break; + } + return(result); +} diff --git a/sys/boot/common/module.c b/sys/boot/common/module.c index 28c10dc71ebb..f10fe3bafeaf 100644 --- a/sys/boot/common/module.c +++ b/sys/boot/common/module.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: module.c,v 1.1.1.1 1998/08/21 03:17:41 msmith Exp $ + * $Id: module.c,v 1.2 1998/08/31 21:10:42 msmith Exp $ */ /* @@ -38,16 +38,68 @@ #include "bootstrap.h" +static struct loaded_module *mod_loadmodule(char *name, int argc, char *argv[]); +static char *mod_searchdep(struct loaded_module *mp); +static char *mod_searchmodule(char *name); +static void mod_append(struct loaded_module *mp); + /* XXX load address should be tweaked by first module loaded (kernel) */ static vm_offset_t loadaddr = 0; struct loaded_module *loaded_modules = NULL; +/* + * load an object, either a disk file or code module. + * + * To load a file, the syntax is: + * + * load -t <type> <path> + * + * code modules are loaded as: + * + * load <path> <options> + */ + COMMAND_SET(load, "load", "load a kernel or module", command_load); static int command_load(int argc, char *argv[]) { + char *typestr; + int dofile, ch; + + dofile = 0; + optind = 1; + typestr = NULL; + while ((ch = getopt(argc, argv, "t:")) != -1) { + switch(ch) { + case 't': + typestr = optarg; + dofile = 1; + break; + case '?': + default: + /* getopt has already reported an error */ + return(CMD_OK); + } + } + argv += (optind - 1); + argc -= (optind - 1); + + /* + * Request to load a raw file? + */ + if (dofile) { + if ((typestr == NULL) || (*typestr == 0)) { + command_errmsg = "invalid load type"; + return(CMD_ERROR); + } + return(mod_loadobj(typestr, argv[1])); + } + + /* + * Looks like a request for a module. + */ return(mod_load(argv[1], argc - 2, argv + 2)); } @@ -57,21 +109,11 @@ static int command_unload(int argc, char *argv[]) { struct loaded_module *mp; - struct module_metadata *md; while (loaded_modules != NULL) { mp = loaded_modules; loaded_modules = loaded_modules->m_next; - while (mp->m_metadata != NULL) { - md = mp->m_metadata; - mp->m_metadata = mp->m_metadata->md_next; - free(md); - } - free(mp->m_name); - free(mp->m_type); - if (mp->m_args != NULL) - free(mp->m_args); - free(mp); + mod_discard(mp); } loadaddr = 0; return(CMD_OK); @@ -83,8 +125,24 @@ static int command_lsmod(int argc, char *argv[]) { struct loaded_module *am; + struct module_metadata *md; char lbuf[80]; - + int ch, verbose; + + verbose = 0; + optind = 1; + while ((ch = getopt(argc, argv, "v")) != -1) { + switch(ch) { + case 'v': + verbose = 1; + break; + case '?': + default: + /* getopt has already reported an error */ + return(CMD_OK); + } + } + pager_open(); for (am = loaded_modules; (am != NULL); am = am->m_next) { sprintf(lbuf, " %x: %s (%s, 0x%x)\n", @@ -95,20 +153,141 @@ command_lsmod(int argc, char *argv[]) pager_output(am->m_args); pager_output("\n"); } + if (verbose) + /* XXX could add some formatting smarts here to display some better */ + for (md = am->m_metadata; md != NULL; md = md->md_next) { + sprintf(lbuf, " 0x%04x, 0x%x\n", md->md_type, md->md_size); + pager_output(lbuf); + } } pager_close(); return(CMD_OK); } +/* + * We've been asked to load (name) and give it (argc),(argv). + * Start by trying to load it, and then attempt to load all of its + * dependancies. If we fail at any point, throw them all away and + * fail the entire load. + * + * XXX if a depended-on module requires arguments, it must be loaded + * explicitly first. + */ int mod_load(char *name, int argc, char *argv[]) { - struct loaded_module *am, *cm; - int i, err; + struct loaded_module *last_mod, *base_mod, *mp; + char *dep_name; + + /* remember previous last module on chain */ + for (last_mod = loaded_modules; + (last_mod != NULL) && (last_mod->m_next != NULL); + last_mod = last_mod->m_next) + ; - for (i = 0, am = NULL; (module_formats[i] != NULL) && (am == NULL); i++) { - /* XXX call searchmodule() to search for module (name) */ - if ((err = (module_formats[i]->l_load)(name, loadaddr, &am)) != 0) { + /* + * Load the first module; note that it's the only one that gets + * arguments explicitly. + */ + if ((base_mod = mod_loadmodule(name, argc, argv)) == NULL) + return(CMD_ERROR); + + /* + * Look for dependancies. + */ + while ((dep_name = mod_searchdep(base_mod)) != NULL) { + printf("loading required module '%s'\n", dep_name); + if ((mp = mod_loadmodule(dep_name, 0, NULL)) == NULL) { + /* Load failed; discard everything */ + while (base_mod != NULL) { + mp = base_mod; + base_mod = base_mod->m_next; + mod_discard(mp); + } + last_mod->m_next = NULL; + loadaddr = last_mod->m_addr + last_mod->m_size; + /* error message already set by mod_loadmodule */ + return(CMD_ERROR); + } + } + return(CMD_OK); +} + +/* + * We've been asked to load (name) as (type), so just suck it in, + * no arguments or anything. + */ +int +mod_loadobj(char *type, char *name) +{ + struct loaded_module *mp; + char *cp; + int fd, got; + vm_offset_t laddr; + + /* We can't load first */ + if ((mod_findmodule(NULL, NULL)) == NULL) { + command_errmsg = "can't load file before kernel"; + return(CMD_ERROR); + } + + /* Try to come up with a fully-qualified name if we don't have one */ + if ((cp = mod_searchmodule(name)) != NULL) + name = cp; + + if ((fd = open(name, O_RDONLY)) < 0) { + sprintf(command_errbuf, "can't open '%s': %s", name, strerror(errno)); + return(CMD_ERROR); + } + + laddr = loadaddr; + for (;;) { + /* read in 4k chunks; size is not really important */ + got = archsw.arch_readin(fd, laddr, 4096); + if (got == 0) /* end of file */ + break; + if (got < 0) { /* error */ + sprintf(command_errbuf, "error reading '%s': %s", name, strerror(errno)); + return(CMD_ERROR); + } + laddr += got; + } + + /* Looks OK so far; create & populate control structure */ + mp = malloc(sizeof(struct loaded_module)); + mp->m_name = strdup(name); + mp->m_type = strdup(type); + mp->m_args = NULL; + mp->m_metadata = NULL; + mp->m_loader = -1; + mp->m_addr = loadaddr; + mp->m_size = laddr - loadaddr; + + /* recognise space consumption */ + loadaddr = laddr; + + /* Add to the list of loaded modules */ + mod_append(mp); + return(CMD_OK); +} + +/* + * Load the module (name), pass it (argc),(argv). + * Don't do any dependancy checking. + */ +static struct loaded_module * +mod_loadmodule(char *name, int argc, char *argv[]) +{ + struct loaded_module *mp; + int i, err; + char *cp; + + /* Try to come up with a fully-qualified name if we don't have one */ + if ((cp = mod_searchmodule(name)) != NULL) + name = cp; + err = 0; + for (i = 0, mp = NULL; (module_formats[i] != NULL) && (mp == NULL); i++) { + if ((err = (module_formats[i]->l_load)(name, loadaddr, &mp)) != 0) { /* Unknown to this handler? */ if (err == EFTYPE) @@ -116,34 +295,87 @@ mod_load(char *name, int argc, char *argv[]) /* Fatal error */ sprintf(command_errbuf, "can't load module '%s': %s", name, strerror(err)); - return(CMD_ERROR); + return(NULL); } else { + + /* Load was OK, set args */ + mp->m_args = unargv(argc, argv); + + /* where can we put the next one? */ + loadaddr = mp->m_addr + mp->m_size; + /* remember the loader */ - am->m_loader = i; + mp->m_loader = i; + + /* Add to the list of loaded modules */ + mod_append(mp); + + break; } } - if (am == NULL) { - sprintf(command_errbuf, "can't work out what to do with '%s'", name); - return(CMD_ERROR); - } - /* where can we put the next one? */ - loadaddr = am->m_addr + am->m_size; - - /* Load was OK, set args */ - am->m_args = unargv(argc, argv); - - /* Append to list of loaded modules */ - am->m_next = NULL; - if (loaded_modules == NULL) { - loaded_modules = am; - } else { - for (cm = loaded_modules; cm->m_next != NULL; cm = cm->m_next) - ; - cm->m_next = am; - } - return(CMD_OK); + if (err == EFTYPE) + sprintf(command_errbuf, "don't know how to load module '%s'", name); + return(mp); } +/* + * Search the modules from (mp) onwards, and return the name of the + * first unresolved dependancy, or NULL if none were found. + */ +static char * +mod_searchdep(struct loaded_module *mp) +{ + struct kld_module_identifier *ident, *dident; + struct kld_module_dependancy *deps, *dp; + struct module_metadata *md; + struct loaded_module *dmp; + int dindex; + + for (; mp != NULL; mp = mp->m_next) { + + /* + * Get KLD module data + */ + ident = NULL; + deps = NULL; + if ((md = mod_findmetadata(mp, MODINFOMD_KLDIDENT)) != NULL) + ident = (struct kld_module_identifier *)md->md_data; + if ((md = mod_findmetadata(mp, MODINFOMD_KLDDEP)) != NULL) + deps = (struct kld_module_dependancy *)md->md_data; + + /* + * Both must exist for this module to depend on anything + */ + if ((ident != NULL) && (deps != NULL)) { + + /* Iterate over dependancies */ + for (dindex = 0; dindex < ident->ki_ndeps; dindex++) { + dp = KLD_GETDEP(ident, deps, dindex); + + /* + * Look for a module matching the dependancy; if we don't have it, + * we need it. + */ + if ((dmp = mod_findmodule(dp->kd_name, NULL)) == NULL) + return(dp->kd_name); + + /* Version check */ + if ((md = mod_findmetadata(dmp, MODINFOMD_KLDIDENT)) != NULL) { + dident = (struct kld_module_identifier *)md->md_data; + if (dp->kd_version != dident->ki_version) + printf("module '%s' requires '%s' version %d, but version %d is loaded\n", + mp->m_name, dp->kd_name, dp->kd_version, dident->ki_version); + } + } + } + } + return(NULL); +} + +/* + * Find a module matching (name) and (type). + * NULL may be passed as a wildcard to either. + */ struct loaded_module * mod_findmodule(char *name, char *type) { @@ -157,6 +389,10 @@ mod_findmodule(char *name, char *type) return(mp); } +/* + * Make a copy of (size) bytes of data from (p), and associate them as + * metadata of (type) to the module (mp). + */ void mod_addmetadata(struct loaded_module *mp, int type, size_t size, void *p) { @@ -170,6 +406,10 @@ mod_addmetadata(struct loaded_module *mp, int type, size_t size, void *p) mp->m_metadata = md; } +/* + * Find a metadata object of (type) associated with the module + * (mp) + */ struct module_metadata * mod_findmetadata(struct loaded_module *mp, int type) { @@ -180,3 +420,101 @@ mod_findmetadata(struct loaded_module *mp, int type) break; return(md); } + +/* + * Attempt to locate a kernel module file for the module (name). + * If (name) is qualified in any way, we simply check it and + * return it or NULL. If it is not qualified, then we attempt + * to construct a path using entries in the environment variable + * module_path. + * + * The path we return a pointer to need never be freed, as we manage + * it internally. + */ +static char * +mod_searchmodule(char *name) +{ + static char *result = NULL; + static char *defpath = "/boot", *path; + char *cp, *sp; + struct stat sb; + + /* Don't look for nothing */ + if ((name == NULL) || (*name == 0)) + return(name); + + /* + * See if there's a device on the front, or a directory name. + */ + archsw.arch_getdev(NULL, name, &cp); + if ((cp != name) || (strchr(name, '/') != NULL)) { + /* Qualified, so just see if it exists */ + if (stat(name, &sb) == 0) + return(name); + return(NULL); + } + + /* + * Get the module path + */ + if ((cp = getenv("module_path")) == NULL) + cp = defpath; + sp = path = strdup(cp); + + /* + * Traverse the path, splitting off ';'-delimited components. + */ + if (result != NULL) + free(result); + while((cp = strsep(&path, ";")) != NULL) { + result = malloc(strlen(cp) + strlen(name) + 2); + sprintf(result, "%s/%s", cp, name); + if (stat(result, &sb) == 0) + break; + free(result); + result = NULL; + } + free(sp); + return(result); +} + +/* + * Throw a module away + */ +void +mod_discard(struct loaded_module *mp) +{ + struct module_metadata *md; + + while (mp->m_metadata != NULL) { + md = mp->m_metadata; + mp->m_metadata = mp->m_metadata->md_next; + free(md); + } + if (mp->m_name != NULL) + free(mp->m_name); + if (mp->m_type != NULL) + free(mp->m_type); + if (mp->m_args != NULL) + free(mp->m_args); + free(mp); +} + +/* + * Add a module to the chain + */ +static void +mod_append(struct loaded_module *mp) +{ + struct loaded_module *cm; + + /* Append to list of loaded modules */ + mp->m_next = NULL; + if (loaded_modules == NULL) { + loaded_modules = mp; + } else { + for (cm = loaded_modules; cm->m_next != NULL; cm = cm->m_next) + ; + cm->m_next = mp; + } +} diff --git a/sys/boot/i386/installboot/installboot.c b/sys/boot/i386/installboot/installboot.c index a5bfd3b5b6da..12e75bc89883 100644 --- a/sys/boot/i386/installboot/installboot.c +++ b/sys/boot/i386/installboot/installboot.c @@ -59,7 +59,7 @@ #include "bbinfo.h" -#define DEFBBLKNAME "boot" +#define DEFBBLKNAME "loader" struct fraglist *fraglist; diff --git a/sys/boot/i386/libi386/bootinfo.c b/sys/boot/i386/libi386/bootinfo.c index 8554f2a83dc7..041ccb81f6f8 100644 --- a/sys/boot/i386/libi386/bootinfo.c +++ b/sys/boot/i386/libi386/bootinfo.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id$ + * $Id: bootinfo.c,v 1.1.1.1 1998/08/21 03:17:41 msmith Exp $ */ #include <sys/reboot.h> @@ -191,7 +191,8 @@ bi_copymodules(vm_offset_t addr) MOD_ADDR(addr, mp->m_addr); MOD_SIZE(addr, mp->m_size); for (md = mp->m_metadata; md != NULL; md = md->md_next) - MOD_METADATA(addr, md); + if (!(md->md_type & MODINFOMD_NOCOPY)) + MOD_METADATA(addr, md); } return(addr); } diff --git a/sys/boot/i386/libi386/bootinfo32.c b/sys/boot/i386/libi386/bootinfo32.c index 8554f2a83dc7..041ccb81f6f8 100644 --- a/sys/boot/i386/libi386/bootinfo32.c +++ b/sys/boot/i386/libi386/bootinfo32.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id$ + * $Id: bootinfo.c,v 1.1.1.1 1998/08/21 03:17:41 msmith Exp $ */ #include <sys/reboot.h> @@ -191,7 +191,8 @@ bi_copymodules(vm_offset_t addr) MOD_ADDR(addr, mp->m_addr); MOD_SIZE(addr, mp->m_size); for (md = mp->m_metadata; md != NULL; md = md->md_next) - MOD_METADATA(addr, md); + if (!(md->md_type & MODINFOMD_NOCOPY)) + MOD_METADATA(addr, md); } return(addr); } diff --git a/sys/boot/i386/libi386/bootinfo64.c b/sys/boot/i386/libi386/bootinfo64.c index 8554f2a83dc7..041ccb81f6f8 100644 --- a/sys/boot/i386/libi386/bootinfo64.c +++ b/sys/boot/i386/libi386/bootinfo64.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id$ + * $Id: bootinfo.c,v 1.1.1.1 1998/08/21 03:17:41 msmith Exp $ */ #include <sys/reboot.h> @@ -191,7 +191,8 @@ bi_copymodules(vm_offset_t addr) MOD_ADDR(addr, mp->m_addr); MOD_SIZE(addr, mp->m_size); for (md = mp->m_metadata; md != NULL; md = md->md_next) - MOD_METADATA(addr, md); + if (!(md->md_type & MODINFOMD_NOCOPY)) + MOD_METADATA(addr, md); } return(addr); } diff --git a/sys/boot/i386/libi386/i386_copy.c b/sys/boot/i386/libi386/i386_copy.c index c6ddf240e5f0..8f614204681c 100644 --- a/sys/boot/i386/libi386/i386_copy.c +++ b/sys/boot/i386/libi386/i386_copy.c @@ -19,6 +19,14 @@ i386_copyin(void *src, vm_offset_t dest, size_t len) return(len); } +int +i386_copyout(vm_offset_t src, void *dest, size_t len) +{ + pvbcopy(src, dest, len); + return(len); +} + + int i386_readin(int fd, vm_offset_t dest, size_t len) { diff --git a/sys/boot/i386/libi386/libi386.h b/sys/boot/i386/libi386/libi386.h index 8d489f840651..abecb349dfdc 100644 --- a/sys/boot/i386/libi386/libi386.h +++ b/sys/boot/i386/libi386/libi386.h @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: libi386.h,v 1.1.1.1 1998/08/21 03:17:41 msmith Exp $ + * $Id: libi386.h,v 1.2 1998/08/31 21:10:43 msmith Exp $ */ @@ -64,20 +64,18 @@ extern struct devdesc currdev; /* our current device */ extern struct devsw biosdisk; /* from crt module */ -extern void vpbcopy(void*, vm_offset_t, int); -extern void pvbcopy(vm_offset_t, void*, int); -extern void pbzero(vm_offset_t, int); -extern vm_offset_t vtophys(void*); +extern void vpbcopy(void *src, vm_offset_t dest, size_t size); +extern void pvbcopy(vm_offset_t src, void *dest, size_t size); +extern void pbzero(vm_offset_t dest, size_t size); +extern vm_offset_t vtophys(void *addr); extern int i386_copyin(void *src, vm_offset_t dest, size_t len); +extern int i386_copyout(vm_offset_t src, void *dest, size_t len); extern int i386_readin(int fd, vm_offset_t dest, size_t len); -/* XXX pread deprecated */ -extern int pread(int, vm_offset_t, int); +extern void startprog(vm_offset_t entry, int argc, u_int32_t *argv, vm_offset_t stack); -extern void startprog(vm_offset_t, int, u_int32_t *, vm_offset_t); - -extern void delay(int); +extern void delay(int delay); extern int getbasemem(void); extern int getextmem(void); diff --git a/sys/boot/i386/loader/main.c b/sys/boot/i386/loader/main.c index ded0d5a6af33..ee7d5752498f 100644 --- a/sys/boot/i386/loader/main.c +++ b/sys/boot/i386/loader/main.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: main.c,v 1.1.1.1 1998/08/21 03:17:41 msmith Exp $ + * $Id: main.c,v 1.2 1998/08/31 21:10:43 msmith Exp $ */ /* @@ -102,19 +102,14 @@ main(void) archsw.arch_autoload = i386_autoload; archsw.arch_getdev = i386_getdev; archsw.arch_copyin = i386_copyin; + archsw.arch_copyout = i386_copyout; archsw.arch_readin = i386_readin; /* * XXX should these be in the MI source? */ - source("/boot/boot.conf"); #if 0 legacy_config(); /* read old /boot.config file */ #endif - printf("\n"); - autoboot(10, NULL); /* try to boot automatically */ - printf("\nType '?' for a list of commands, 'help' for more detailed help.\n"); - setenv("prompt", "$currdev>", 1); - interact(); /* doesn't return */ } diff --git a/sys/boot/ofw/libofw/ofw_copy.c b/sys/boot/ofw/libofw/ofw_copy.c index 9e164de0dbad..250c41692dc6 100644 --- a/sys/boot/ofw/libofw/ofw_copy.c +++ b/sys/boot/ofw/libofw/ofw_copy.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id$ + * $Id: alpha_copy.c,v 1.1 1998/08/31 21:10:40 msmith Exp $ */ /* * MD primitives supporting placement of module data @@ -41,6 +41,13 @@ alpha_copyin(void *src, vm_offset_t dest, size_t len) return(len); } +int +alpha_copyout(void *src, vm_offset_t dest, size_t len) +{ + bcopy(src, dest, len); + return(len); +} + int alpha_readin(int fd, vm_offset_t dest, size_t len) {