Index: mkheaders.c =================================================================== --- mkheaders.c (.../vendor/netbsd/current-20080118) (revision 51) +++ mkheaders.c (.../tags/patch-1-rc1) (revision 51) @@ -162,6 +162,7 @@ struct nvlist *nv; FILE *fp; + (void)snprintf(nfname, sizeof(nfname), "%s.h", head->nv_name); (void)snprintf(tfname, sizeof(tfname), "tmp_%s", nfname); @@ -376,17 +377,31 @@ const char *tfname; FILE *tfp; struct devbase *d; + struct nvlist *nv; + struct nvlist *lkmlist = NULL; /* to remember LKM devices */ tfname = "tmp_ioconf.h"; if ((tfp = fopen(tfname, "w")) == NULL) return (herr("open", tfname, NULL)); TAILQ_FOREACH(d, &allbases, d_next) { - if (!devbase_has_instances(d, WILD)) - continue; - fprintf(tfp, "extern struct cfdriver %s_cd;\n", d->d_name); + if (devbase_has_instances(d, WILD)) + fprintf(tfp, "extern struct cfdriver %s_cd;\n", d->d_name); + else if (devbase_has_any_instance(d, WILD, DEVI_MODULE, 0)) + lkmlist = newnv(d->d_name, NULL, d, 0, lkmlist); } + if (lkmlist) { + fprintf(tfp, "\n/* for LKMs */\n"); + for (nv = lkmlist; nv; nv = nv->nv_next) { + d = nv->nv_ptr; + fprintf(tfp, "extern struct cfdriver %s_cd;\n", + d->d_name); + } + nvfreel(lkmlist); + lkmlist = NULL; + } + fflush(tfp); if (ferror(tfp)) return herr("writ", tfname, tfp); Index: mkmakefile.c =================================================================== --- mkmakefile.c (.../vendor/netbsd/current-20080118) (revision 51) +++ mkmakefile.c (.../tags/patch-1-rc1) (revision 51) @@ -64,52 +64,103 @@ static const char *filetype_prologue(struct filetype *); -static void emitdefs(FILE *); +static void emitdefs(FILE *, const char *); static void emitfiles(FILE *, int, int); -static void emitobjs(FILE *); -static void emitcfiles(FILE *); -static void emitsfiles(FILE *); -static void emitrules(FILE *); -static void emitload(FILE *); -static void emitincludes(FILE *); -static void emitappmkoptions(FILE *); +static void emitobjs(FILE *, void *); +static void emitcfiles(FILE *, void *); +static void emitsfiles(FILE *, void *); +static void emitrules(FILE *, void *); +static void emitload(FILE *, void *); +static void emitincludes(FILE *, void *); +static void emitappmkoptions(FILE *, void *); int mkmakefile(void) { + static const struct makefile_constructs c[] = { + { "OBJS", emitobjs }, + { "CFILES", emitcfiles }, + { "SFILES", emitsfiles }, + { "RULES", emitrules }, + { "LOAD", emitload }, + { "INCLUDES", emitincludes }, + { "MAKEOPTIONSAPPEND", emitappmkoptions }, + { "KMOD", emitkmod }, + { NULL, NULL } + }; + + return mkmakefile_common(c, "", ".", NULL); +} + +int +mkmakefile_common(const struct makefile_constructs *cset, + const char *template_suffix, + const char *output_dir, + void *aux) +{ FILE *ifp, *ofp; int lineno; - void (*fn)(FILE *); char *ifname; - char line[BUFSIZ], buf[200]; + char line[BUFSIZ]; + char buf[MAXPATHLEN]; + char makefilename[MAXPATHLEN], tempfilename[MAXPATHLEN]; + const char *srcdirprepend = ""; + int i; + int lkm = aux != NULL; /* Try a makefile for the port first. */ - (void)snprintf(buf, sizeof(buf), "arch/%s/conf/Makefile.%s", - machine, machine); + (void)snprintf(buf, sizeof(buf), "arch/%s/conf/Makefile%s.%s", + machine, template_suffix, machine); ifname = sourcepath(buf); if ((ifp = fopen(ifname, "r")) == NULL) { /* Try a makefile for the architecture second. */ - (void)snprintf(buf, sizeof(buf), "arch/%s/conf/Makefile.%s", - machinearch, machinearch); + (void)snprintf(buf, sizeof(buf), "arch/%s/conf/Makefile%s.%s", + machinearch, template_suffix, machinearch); free(ifname); ifname = sourcepath(buf); ifp = fopen(ifname, "r"); } + if (ifp == NULL && lkm) { + /* for LKM makefile, try MI template */ + (void)snprintf(buf, sizeof buf, "conf/Makefile%s", + template_suffix); + ifname = sourcepath(buf); + ifp = fopen(ifname, "r"); + } if (ifp == NULL) { warn("cannot read %s", ifname); goto bad2; } - if ((ofp = fopen("Makefile.tmp", "w")) == NULL) { - warn("cannot write Makefile"); + + snprintf(makefilename, sizeof buf, "%s/Makefile", output_dir); + snprintf(tempfilename, sizeof tempfilename, "%s.tmp", makefilename); + + if ((ofp = fopen(tempfilename, "w")) == NULL) { + warn("cannot write %s", tempfilename); goto bad1; } - emitdefs(ofp); + if (*srcdir == '/') + srcdirprepend = ""; + else if (lkm) + srcdirprepend = "../../"; + else { + /* + * libkern and libcompat "Makefile.inc"s want relative S + * specification to begin with '.'. + */ + if (*srcdir == '.') + srcdirprepend = ""; + else + srcdirprepend = "./"; + } + emitdefs(ofp, srcdirprepend); + lineno = 0; while (fgets(line, sizeof(line), ifp) != NULL) { lineno++; @@ -117,26 +168,21 @@ fputs(line, ofp); continue; } - if (strcmp(line, "%OBJS\n") == 0) - fn = emitobjs; - else if (strcmp(line, "%CFILES\n") == 0) - fn = emitcfiles; - else if (strcmp(line, "%SFILES\n") == 0) - fn = emitsfiles; - else if (strcmp(line, "%RULES\n") == 0) - fn = emitrules; - else if (strcmp(line, "%LOAD\n") == 0) - fn = emitload; - else if (strcmp(line, "%INCLUDES\n") == 0) - fn = emitincludes; - else if (strcmp(line, "%MAKEOPTIONSAPPEND\n") == 0) - fn = emitappmkoptions; - else { + for (i=0; cset[i].str != NULL; ++i) { + /* chomp line */ + char *p = strchr(line+1, '\n'); + if (p) + *p = '\0'; + + if (strcmp(line+1, cset[i].str) == 0) { + cset[i].func(ofp, aux); + break; + } + } + if (cset[i].str == NULL) { cfgxerror(ifname, lineno, "unknown %% construct ignored: %s", line); - continue; } - (*fn)(ofp); } fflush(ofp); @@ -154,21 +200,21 @@ } (void)fclose(ifp); - if (moveifchanged("Makefile.tmp", "Makefile") != 0) { - warn("error renaming Makefile"); + if (moveifchanged(tempfilename, makefilename) != 0) { + warn("error renaming %s", makefilename); goto bad2; } free(ifname); return (0); wrerror: - warn("error writing Makefile"); + warn("error writing %s", makefilename); bad: if (ofp != NULL) (void)fclose(ofp); bad1: (void)fclose(ifp); - /* (void)unlink("Makefile.tmp"); */ + /* (void)unlink(tempfilename); */ bad2: free(ifname); return (1); @@ -219,7 +265,7 @@ } static void -emitdefs(FILE *fp) +emitdefs(FILE *fp, const char *srcdirprepend) { struct nvlist *nv; char *sp; @@ -240,21 +286,14 @@ putc('\n', fp); fprintf(fp, "PARAM=-DMAXUSERS=%d\n", maxusers); fprintf(fp, "MACHINE=%s\n", machine); - if (*srcdir == '/' || *srcdir == '.') { - fprintf(fp, "S=\t%s\n", srcdir); - } else { - /* - * libkern and libcompat "Makefile.inc"s want relative S - * specification to begin with '.'. - */ - fprintf(fp, "S=\t./%s\n", srcdir); - } + fprintf(fp, "S=\t%s%s\n", srcdirprepend, srcdir); for (nv = mkoptions; nv != NULL; nv = nv->nv_next) fprintf(fp, "%s=%s\n", nv->nv_name, nv->nv_str); } static void -emitobjs(FILE *fp) +/*ARGSUSED*/ +emitobjs(FILE *fp, void *aux) { struct files *fi; struct objects *oi; @@ -314,14 +353,16 @@ } static void -emitcfiles(FILE *fp) +/*ARGSUSED*/ +emitcfiles(FILE *fp, void *aux) { emitfiles(fp, 'c', 0); } static void -emitsfiles(FILE *fp) +/*ARGSUSED*/ +emitsfiles(FILE *fp, void *aux) { emitfiles(fp, 's', 'S'); @@ -402,7 +443,8 @@ * Emit the make-rules. */ static void -emitrules(FILE *fp) +/*ARGSUSED*/ +emitrules(FILE *fp, void *aux) { struct files *fi; const char *cp, *fpath; @@ -445,7 +487,8 @@ * This function is not to be called `spurt'. */ static void -emitload(FILE *fp) +/*ARGSUSED*/ +emitload(FILE *fp, void *aux) { struct config *cf; const char *nm, *swname; @@ -475,7 +518,8 @@ * Emit include headers (for any prefixes encountered) */ static void -emitincludes(FILE *fp) +/*ARGSUSED*/ +emitincludes(FILE *fp, void *aux) { struct prefix *pf; @@ -504,7 +548,8 @@ * Emit appending makeoptions. */ static void -emitappmkoptions(FILE *fp) +/*ARGSUSED*/ +emitappmkoptions(FILE *fp, void *aux) { struct nvlist *nv; Index: mkioconf.c =================================================================== --- mkioconf.c (.../vendor/netbsd/current-20080118) (revision 51) +++ mkioconf.c (.../tags/patch-1-rc1) (revision 51) @@ -61,7 +61,7 @@ static void emitcfdrivers(FILE *); static void emitexterns(FILE *); static void emitcfattachinit(FILE *); -static void emithdr(FILE *); +//static void emithdr(FILE *); static void emitloc(FILE *); static void emitpseudo(FILE *); static void emitparents(FILE *); @@ -89,7 +89,7 @@ return (1); } - emithdr(fp); + ioconf_emithdr(fp, "ioconf.c"); emitcfdrivers(fp); emitexterns(fp); emitcfattachinit(fp); @@ -129,15 +129,15 @@ return (n1 - n2); } -static void -emithdr(FILE *ofp) +void +ioconf_emithdr(FILE *ofp, const char *filename) { FILE *ifp; int n; char ifnbuf[200], buf[BUFSIZ]; char *ifn; - autogen_comment(ofp, "ioconf.c"); + autogen_comment(ofp, filename); (void)snprintf(ifnbuf, sizeof(ifnbuf), "arch/%s/conf/ioconf.incl.%s", machine, machine); @@ -174,7 +174,7 @@ if (a->a_locs) { fprintf(fp, - "static const struct cfiattrdata %scf_iattrdata = {\n", + "const struct cfiattrdata %scf_iattrdata = {\n", name); fprintf(fp, "\t\"%s\", %d,\n\t{\n", name, a->a_loclen); for (nv = a->a_locs; nv; nv = nv->nv_next) @@ -185,7 +185,7 @@ fprintf(fp, "\t}\n};\n"); } else { fprintf(fp, - "static const struct cfiattrdata %scf_iattrdata = {\n" + "const struct cfiattrdata %scf_iattrdata = {\n" "\t\"%s\", 0, {\n\t\t{ NULL, NULL, 0 },\n\t}\n};\n", name, name); } @@ -197,9 +197,6 @@ emitcfdrivers(FILE *fp) { struct devbase *d; - struct nvlist *nv; - struct attr *a; - int has_iattrs; NEWLINE; ht_enumerate(attrtab, cf_locators_print, fp); @@ -208,28 +205,7 @@ TAILQ_FOREACH(d, &allbases, d_next) { if (!devbase_has_instances(d, WILD)) continue; - has_iattrs = 0; - for (nv = d->d_attrs; nv != NULL; nv = nv->nv_next) { - a = nv->nv_ptr; - if (a->a_iattr == 0) - continue; - if (has_iattrs == 0) - fprintf(fp, - "static const struct cfiattrdata * const %s_attrs[] = { ", - d->d_name); - has_iattrs = 1; - fprintf(fp, "&%scf_iattrdata, ", a->a_name); - } - if (has_iattrs) - fprintf(fp, "NULL };\n"); - fprintf(fp, "CFDRIVER_DECL(%s, %s, ", d->d_name, /* ) */ - d->d_classattr != NULL ? d->d_classattr->a_devclass - : "DV_DULL"); - if (has_iattrs) - fprintf(fp, "%s_attrs", d->d_name); - else - fprintf(fp, "NULL"); - fprintf(fp, /* ( */ ");\n\n"); + ioconf_emit_cfdriver(d, fp); } NEWLINE; @@ -242,6 +218,63 @@ fprintf(fp, "\tNULL\n};\n"); } + +/* This function is used for LKM ioconf */ +void +ioconf_emit_ref_iattrs(struct devbase *d, FILE *fp) +{ + struct nvlist *nv; + struct attr *a; + + for (nv = d->d_attrs; nv != NULL; nv = nv->nv_next) { + a = nv->nv_ptr; + if (a->a_iattr == 0) + continue; + + a = nv->nv_ptr; + fprintf(fp, + "extern const struct cfiattrdata %scf_iattrdata;\n", + a->a_name); + } +} + +void +ioconf_emit_cfdriver(struct devbase *d, FILE *fp) +{ + struct nvlist *nv; + struct attr *a; + int has_iattrs; + + has_iattrs = 0; + for (nv = d->d_attrs; nv != NULL; nv = nv->nv_next) { + a = nv->nv_ptr; + if (a->a_iattr == 0) + continue; + if (!has_iattrs) { + fprintf(fp, + "const struct cfiattrdata * const %s_attrs[] = { ", + d->d_name); + } + + a = nv->nv_ptr; + fprintf(fp, "&%scf_iattrdata, ", a->a_name); + has_iattrs = 1; + } + + if (has_iattrs) + fprintf(fp, "NULL };\n"); + + fprintf(fp, "CFDRIVER_DECL(%s, %s, ", d->d_name, /* ) */ + d->d_classattr != NULL ? d->d_classattr->a_devclass + : "DV_DULL"); + if (has_iattrs) + fprintf(fp, "%s_attrs", d->d_name); + else + fprintf(fp, "NULL"); + fprintf(fp, /* ( */ ");\n\n"); +} + + static void emitexterns(FILE *fp) { @@ -324,23 +357,32 @@ NEWLINE; TAILQ_FOREACH(p, &allpspecs, p_list) { - if (p->p_devs == NULL || p->p_active != DEVI_ACTIVE) - continue; - fprintf(fp, - "static const struct cfparent pspec%d = {\n", p->p_inst); - fprintf(fp, "\t\"%s\", ", p->p_iattr->a_name); - if (p->p_atdev != NULL) { - fprintf(fp, "\"%s\", ", p->p_atdev->d_name); - if (p->p_atunit == WILD) - fprintf(fp, "DVUNIT_ANY"); - else - fprintf(fp, "%d", p->p_atunit); - } else - fprintf(fp, "NULL, 0"); - fprintf(fp, "\n};\n"); + ioconf_emit_pspec(fp, p, 0); } } +void +ioconf_emit_pspec(FILE *fp, struct pspec *p, int force) +{ + /* force==1 when creating _MODULE_ioconf.c */ + if (!force && + (p->p_devs == NULL || p->p_active != DEVI_ACTIVE)) + return; + + fprintf(fp, + "static const struct cfparent pspec%d = {\n", p->p_inst); + fprintf(fp, "\t\"%s\", ", p->p_iattr->a_name); + if (p->p_atdev != NULL) { + fprintf(fp, "\"%s\", ", p->p_atdev->d_name); + if (p->p_atunit == WILD) + fprintf(fp, "DVUNIT_ANY"); + else + fprintf(fp, "%d", p->p_atunit); + } else + fprintf(fp, "NULL, 0"); + fprintf(fp, "\n};\n"); +} + /* * Emit the cfdata array. */ @@ -348,6 +390,32 @@ emitcfdata(FILE *fp) { struct devi **p, *i; + const char *dataname = "cfdata"; + + ioconf_cfdata_start(fp, dataname); + for (p = packed; (i = *p) != NULL; p++) { + /* the description */ + ioconf_cfdata_entry(fp, i); + } + + ioconf_cfdata_end(fp, dataname); +} + +void +ioconf_cfdata_start(FILE *fp, const char *array_name) +{ + fprintf(fp, "\n" + "#define NORM FSTATE_NOTFOUND\n" + "#define STAR FSTATE_STAR\n" + "\n" + "struct cfdata %s[] = {\n" + " /* driver attachment unit state " + "loc flags pspec */\n", array_name); +} + +void +ioconf_cfdata_entry(FILE *fp, struct devi *i) +{ struct pspec *ps; int unit, v; const char *state, *basename, *attachment; @@ -357,78 +425,75 @@ char locbuf[20]; const char *lastname = ""; - fprintf(fp, "\n" - "#define NORM FSTATE_NOTFOUND\n" - "#define STAR FSTATE_STAR\n" - "\n" - "struct cfdata cfdata[] = {\n" - " /* driver attachment unit state " - "loc flags pspec */\n"); - for (p = packed; (i = *p) != NULL; p++) { - /* the description */ - fprintf(fp, "/*%3d: %s at ", i->i_cfindex, i->i_name); - if ((ps = i->i_pspec) != NULL) { - if (ps->p_atdev != NULL && - ps->p_atunit != WILD) { - fprintf(fp, "%s%d", ps->p_atdev->d_name, - ps->p_atunit); - } else if (ps->p_atdev != NULL) { - fprintf(fp, "%s?", ps->p_atdev->d_name); + fprintf(fp, "/*%3d: %s at ", i->i_cfindex, i->i_name); + if ((ps = i->i_pspec) != NULL) { + if (ps->p_atdev != NULL && + ps->p_atunit != WILD) { + fprintf(fp, "%s%d", ps->p_atdev->d_name, + ps->p_atunit); + } else if (ps->p_atdev != NULL) { + fprintf(fp, "%s?", ps->p_atdev->d_name); + } else { + fprintf(fp, "%s?", ps->p_iattr->a_name); + } + + a = ps->p_iattr; + for (nv = a->a_locs, v = 0; nv != NULL; + nv = nv->nv_next, v++) { + if (ARRNAME(nv->nv_name, lastname)) { + fprintf(fp, " %s %s", + nv->nv_name, i->i_locs[v]); } else { - fprintf(fp, "%s?", ps->p_iattr->a_name); + fprintf(fp, " %s %s", + nv->nv_name, + i->i_locs[v]); + lastname = nv->nv_name; } - - a = ps->p_iattr; - for (nv = a->a_locs, v = 0; nv != NULL; - nv = nv->nv_next, v++) { - if (ARRNAME(nv->nv_name, lastname)) { - fprintf(fp, " %s %s", - nv->nv_name, i->i_locs[v]); - } else { - fprintf(fp, " %s %s", - nv->nv_name, - i->i_locs[v]); - lastname = nv->nv_name; - } - } - } else { - a = NULL; - fputs("root", fp); } + } else { + a = NULL; + fputs("root", fp); + } - fputs(" */\n", fp); + fputs(" */\n", fp); - /* then the actual defining line */ - basename = i->i_base->d_name; - attachment = i->i_atdeva->d_name; - if (i->i_unit == STAR) { - unit = i->i_base->d_umax; - state = "STAR"; - } else { - unit = i->i_unit; - state = "NORM"; - } - if (i->i_locoff >= 0) { - (void)snprintf(locbuf, sizeof(locbuf), "loc+%3d", - i->i_locoff); - loc = locbuf; - } else - loc = "loc"; - fprintf(fp, " {\"%s\",%s\"%s\",%s%2d, %s, %7s, %#6x, ", - basename, strlen(basename) < 8 ? "\t\t" - : "\t", - attachment, strlen(attachment) < 5 ? "\t\t" - : "\t", - unit, state, loc, i->i_cfflags); - if (ps != NULL) - fprintf(fp, "&pspec%d},\n", ps->p_inst); - else - fputs("NULL},\n", fp); + /* then the actual defining line */ + basename = i->i_base->d_name; + attachment = i->i_atdeva->d_name; + if (i->i_unit == STAR) { + unit = i->i_base->d_umax; + state = "STAR"; + } else { + unit = i->i_unit; + state = "NORM"; } + if (i->i_locoff >= 0) { + (void)snprintf(locbuf, sizeof(locbuf), "loc+%3d", + i->i_locoff); + loc = locbuf; + } else + loc = "loc"; + fprintf(fp, " {\"%s\",%s\"%s\",%s%2d, %s, %7s, %#6x, ", + basename, strlen(basename) < 8 ? "\t\t" + : "\t", + attachment, strlen(attachment) < 5 ? "\t\t" + : "\t", + unit, state, loc, i->i_cfflags); + if (ps != NULL) + fprintf(fp, "&pspec%d},\n", ps->p_inst); + else + fputs("NULL},\n", fp); +} + +void +/*ARGSUSED*/ +ioconf_cfdata_end(FILE *fp, const char *array_name) +{ fprintf(fp, " {%s,%s%s,%s%2d, %s, %7s, %#6x, %s}\n};\n", "NULL", "\t\t", "NULL", "\t\t", 0, "0", "NULL", 0, "NULL"); } + /* * Emit the table of potential roots. */ @@ -461,11 +526,15 @@ fputs("\n/* pseudo-devices */\n", fp); TAILQ_FOREACH(i, &allpseudo, i_next) { + if (i->i_module) + continue; fprintf(fp, "void %sattach(int);\n", i->i_base->d_name); } fputs("\nstruct pdevinit pdevinit[] = {\n", fp); TAILQ_FOREACH(i, &allpseudo, i_next) { + if (i->i_module) + continue; d = i->i_base; fprintf(fp, "\t{ %sattach, %d },\n", d->d_name, d->d_umax); Index: gram.y =================================================================== --- gram.y (.../vendor/netbsd/current-20080118) (revision 51) +++ gram.y (.../tags/patch-1-rc1) (revision 51) @@ -108,7 +108,7 @@ %token ENDFILE %token XFILE FILE_SYSTEM FLAGS %token IDENT -%token XMACHINE MAJOR MAKEOPTIONS MAXUSERS MAXPARTITIONS MINOR +%token XMACHINE MAJOR MAKEOPTIONS MAXUSERS MAXPARTITIONS MINOR MODULE %token NEEDS_COUNT NEEDS_FLAG NO %token XOBJECT OBSOLETE ON OPTIONS %token PACKAGE PLUSEQ PREFIX PSEUDO_DEVICE @@ -453,7 +453,8 @@ config_spec: one_def | - NO FILE_SYSTEM no_fs_list | + NO opt_module FILE_SYSTEM no_fs_list | + MODULE FILE_SYSTEM mod_fs_list | FILE_SYSTEM fs_list | NO MAKEOPTIONS no_mkopt_list | MAKEOPTIONS mkopt_list | @@ -464,22 +465,34 @@ CONFIG conf root_spec sysparam_list { addconf(&conf); } | NO CONFIG WORD { delconf($3); } | - NO PSEUDO_DEVICE WORD { delpseudo($3); } | - PSEUDO_DEVICE WORD npseudo { addpseudo($2, $3); } | - NO device_instance AT attachment - { deldevi($2, $4); } | + NO opt_module PSEUDO_DEVICE WORD { delpseudo($4); } | + PSEUDO_DEVICE WORD npseudo + { addpseudo($2, $3, 0); } | + MODULE PSEUDO_DEVICE WORD npseudo + { addpseudo($3, $4, 1); } | + NO opt_module device_instance AT attachment + { deldevi($3, $5); } | NO DEVICE AT attachment { deldeva($4); } | - NO device_instance { deldev($2); } | + NO opt_module device_instance { deldev($3); } | device_instance AT attachment locators flags_opt - { adddev($1, $3, $4, $5); }; + { adddev($1, $3, $4, $5, 0); } | + MODULE device_instance AT attachment locators flags_opt + { adddev($2, $4, $5, $6, 1); }; fs_list: fs_list ',' fsoption | fsoption; fsoption: - WORD { addfsoption($1); }; + WORD { addfsoption($1, 0); }; +mod_fs_list: + mod_fs_list ',' mod_fsoption | + mod_fsoption; + +mod_fsoption: + WORD { addfsoption($1, 1); }; + no_fs_list: no_fs_list ',' no_fsoption | no_fsoption; @@ -590,6 +603,9 @@ FLAGS NUMBER { $$ = $2.val; } | /* empty */ { $$ = 0; }; +opt_module: + MODULE | /* empty */; + %% void Index: util.c =================================================================== --- util.c (.../vendor/netbsd/current-20080118) (revision 51) +++ util.c (.../tags/patch-1-rc1) (revision 51) @@ -45,6 +45,7 @@ #endif #include +#include #include #include #include @@ -52,6 +53,7 @@ #include #include #include +#include #include "defs.h" static void cfgvxerror(const char *, int, const char *, va_list) @@ -295,3 +297,21 @@ " */\n\n", targetfile, conffile); } + +/* + * Create a directory if not exists. Die when fails. + */ +void +make_directory(const char *path) +{ + struct stat st; + + if (stat(path, &st) == -1) { + if (errno != ENOENT) + warn("can't find %s", path); + if (mkdir(path, 0777) == -1) + err(EXIT_FAILURE, "cannot create %s", path); + } else if (!S_ISDIR(st.st_mode)) + errx(EXIT_FAILURE, "%s is not a directory", path); +} + Index: mkdevsw.c =================================================================== --- mkdevsw.c (.../vendor/netbsd/current-20080118) (revision 51) +++ mkdevsw.c (.../tags/patch-1-rc1) (revision 51) @@ -109,7 +109,8 @@ for (i = 0 ; i <= maxbdevm ; i++) { (void)snprintf(mstr, sizeof(mstr), "%d", i); - if ((dm = ht_lookup(bdevmtab, intern(mstr))) == NULL) + if ((dm = ht_lookup(bdevmtab, intern(mstr))) == NULL || + dm->dm_active != DEVM_INKERNEL) continue; fprintf(fp, "extern const struct bdevsw %s_bdevsw;\n", @@ -120,7 +121,8 @@ for (i = 0 ; i <= maxbdevm ; i++) { (void)snprintf(mstr, sizeof(mstr), "%d", i); - if ((dm = ht_lookup(bdevmtab, intern(mstr))) == NULL) { + if ((dm = ht_lookup(bdevmtab, intern(mstr))) == NULL || + dm->dm_active != DEVM_INKERNEL) { fprintf(fp, "\tNULL,\n"); } else { fprintf(fp, "\t&%s_bdevsw,\n", dm->dm_name); @@ -136,7 +138,8 @@ for (i = 0 ; i <= maxcdevm ; i++) { (void)snprintf(mstr, sizeof(mstr), "%d", i); - if ((dm = ht_lookup(cdevmtab, intern(mstr))) == NULL) + if ((dm = ht_lookup(cdevmtab, intern(mstr))) == NULL || + dm->dm_active != DEVM_INKERNEL) continue; fprintf(fp, "extern const struct cdevsw %s_cdevsw;\n", @@ -147,7 +150,8 @@ for (i = 0 ; i <= maxcdevm ; i++) { (void)snprintf(mstr, sizeof(mstr), "%d", i); - if ((dm = ht_lookup(cdevmtab, intern(mstr))) == NULL) { + if ((dm = ht_lookup(cdevmtab, intern(mstr))) == NULL || + dm->dm_active != DEVM_INKERNEL) { fprintf(fp, "\tNULL,\n"); } else { fprintf(fp, "\t&%s_cdevsw,\n", dm->dm_name); Index: lkm.c =================================================================== --- lkm.c (.../vendor/netbsd/current-20080118) (revision 0) +++ lkm.c (.../tags/patch-1-rc1) (revision 51) @@ -0,0 +1,1573 @@ +/*- + * Copyright (c) 2007, 2008 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Hiroyuki Bessho. + * + * 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. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#ifndef MAKE_BOOTSTRAP +#include +#define COPYRIGHT(x) __COPYRIGHT(x) +#else +#define COPYRIGHT(x) static const char copyright[] = x +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "defs.h" +#include "sem.h" /* for expandattr */ + +#define KMODDIR "modules" +#define KMODWORK_SUFFIX ".work" + +static int fixlkm_devbase(struct devbase *); +static int fixlkm_deva(struct deva *); +static int fixlkm_devi(struct devi *); +static struct module *newmodule(const char *, enum module_type); +static struct module *getmodule(const char *, enum module_type); +static int lkm_select_device(struct module *, void (*)(struct attr *, void *)); +static int lkm_select_cb(const char *, void *, void *); +static void lkm_select_attr(struct attr *, void *); +static void lkm_record_require(struct attr *, void *); +//static int for_all_module_files(struct module *, int (* )(struct files *, struct module *, void *), void *); +static int lkm_fixfile_cb(const char *, void *, void *); +static int lkm_fixsel(const char *, void *); +static void lkm_emit_parents(struct module *, FILE *fp); +static int lkm_emit_modulelist_cb(const char *, void *, void *); +//static int lkm_emit_moduledefs_cb(const char *, void *, void *); +static int lkm_make_files_cb(const char *, void *, void *); +static int lkm_make_makefile(struct module *, const char *); +static int lkm_make_lkmfile(struct module *, const char *); +static void lkm_emit_loc(struct module *, FILE *); +static int add_lkm_file_cb(const char *, void *, void *); +static int lkm_emit_ioconf(struct module *, struct files *, FILE *); +static int lkm_emit_ioconf_pseudo(struct module *, struct files *, FILE *, char **); +struct emit_require_args { + FILE *fp; + struct module *cur_module; +}; +static int lkm_emitrequire_cb(const char *, void *, void *); +static int lkm_emitprovide_cb(const char *, void *, void *); + +static void lkm_emitsrcs(FILE *, void *); +static void lkm_emitobjs(FILE *, void *); +static void lkm_emitkmod(FILE *, void *); + +int merge_modules(struct module *, struct module *); + +#ifndef STAILQ_APPEND +#define STAILQ_APPEND(q0, q1, field) do { \ + if (!STAILQ_EMPTY(q1)) { \ + *(q0)->stqh_last = STAILQ_FIRST(q1); \ + (q0)->stqh_last = (q1)->stqh_last; \ + } \ +} while (/*CONSTCOND*/0) +#endif + + +int +fixlkmdevs(void) +{ + struct devbase *d; + struct deva *da; + struct devi *i, *j; + + TAILQ_FOREACH(d, &allbases, d_next) { + + if (fixlkm_devbase(d)) + return -1; + + for (da = d->d_ahead; da != NULL; da = da->d_bsame) { + if (da->d_name == d->d_name) { + /* the device doesn't have separate + attachment attribute. */ + continue; + } + + if (fixlkm_deva(da)) + return -1; + } + + for (i = d->d_ihead; i != NULL; i = i->i_bsame) { + for (j=i; j != NULL; j = j->i_alias) { + if (fixlkm_devi(j)) + return -1; + } + } + } + + /* select new modules required by already selected modules */ + ht_enumerate(moduletab, lkm_select_cb, lkm_select_attr); + /* and record dependencies between selected modules */ + ht_enumerate(moduletab, lkm_select_cb, lkm_record_require); + + return 0; +} + +static int +fixlkm_devbase(struct devbase *d) +{ + struct devi *i, *j; + struct module *m; + int d_module = 0; + + /* if it's in the kernel, don't make an LKM for it */ + if (ht_lookup(selecttab, d->d_name) != NULL) + return 0; + + /* if device instance is in the module, we also need its base */ + for (i = d->d_ihead; i != NULL; i = i->i_bsame) + for (j = i; j != NULL; j = j->i_alias) { + if (j->i_active == DEVI_MODULE) { + ++d_module; + /* break; */ + } + } + + if (d_module == 0) + return 0; + + /* make a module for this devbase + the name of the module is device name */ + m = getmodule(d->d_name, + d->d_ispseudo ? M_PSEUDO: M_DEVICE); + if (m == NULL) + return -1; + STAILQ_INSERT_TAIL(&m->m_base, d, d_mnext); + d->d_module = m; + + return 0; +} + + +/* + */ +static int +fixlkm_deva(struct deva *a) +{ + struct devi *i; + struct devbase *base; + struct module *m; + int a_module = 0; + + /* if it's in the kernel, don't make LKM */ + if (ht_lookup(selecttab, a->d_name) != NULL) + return 0; + + /* if device instance is in the module, we also need its attachment */ + for (i = a->d_ihead; i != NULL; i = i->i_asame) { + if (i->i_active == DEVI_MODULE) { + ++a_module; + } + } + + if (!a_module) + return 0; + + /* this device attachment is compiled as LKM */ + + m = getmodule(a->d_name, M_DEVICE); + if (m == NULL) + return -1; + + a->d_module = m; + STAILQ_INSERT_TAIL(&m->m_deva, a, d_mnext); + + base = a->d_devbase; + if (base && base->d_module) + ht_insert(m->m_require, base->d_name, base->d_module); + + return 0; +} + +static int +fixlkm_devi(struct devi *i) +{ + struct module *m = NULL; + struct devbase *b; + struct deva *a; + char *instname; + + if (i->i_active != DEVI_MODULE) + return 0; + + a = i->i_atdeva; + b = i->i_base; + if (a && a->d_module) + m = a->d_module; + else if (b && b->d_module) + m = b->d_module; + + + if (m) { + STAILQ_INSERT_TAIL(&m->m_devi, i, i_mnext); + } + else { + /* This instance has its base and attachment in the + * kernel */ +#if 0 + /* make one module for each device instance */ + m = getmodule(i->i_name, M_DEVICE); +#else + /* pack those device instances into one module */ + char devi_modname[100]; + + snprintf(devi_modname, sizeof devi_modname, "%s_", + i->i_base->d_name); + m = getmodule(intern(devi_modname), M_DEVICE); +#endif + if (m == NULL) + return -1; + + STAILQ_INSERT_TAIL(&m->m_devi, i, i_mnext); + } + i->i_module = m; + + /* for lkm.provide */ + if (m->m_type == M_DEVICE) { + if (i->i_at) + asprintf(&instname, "%s@%s", i->i_name, i->i_at); + else + instname = __UNCONST(i->i_name); + ht_insert(m->m_selecttab, instname, i); + } + + + return 0; +} + +static struct module * +newmodule(const char *name, enum module_type type) +{ + struct module *m; + + m = ecalloc(1, sizeof *m); + m->m_name = name; + m->m_type = type; + STAILQ_INIT(&m->m_base); + STAILQ_INIT(&m->m_devi); + STAILQ_INIT(&m->m_deva); + STAILQ_INIT(&m->m_files); + m->m_selecttab = ht_new(); + m->m_require = ht_new(); + return m; +} + +static struct module * +getmodule(const char *name, enum module_type type) +{ + struct module *m = NULL; + static int anonymous_modules = 0; + + if (name != NULL) + m = ht_lookup(moduletab, name); + else { + char *n; + asprintf(&n, "M%03d", anonymous_modules++); + name = n; + } + + if (m == NULL) { + m = newmodule(name, type); + ht_insert(moduletab, name, m); + return m; + } + + if (m->m_type != type) { + cfgerror("%s: duplicate module", name); + return (NULL); + } + + return m; +} + + +static void +lkm_select_attr(struct attr *a, void *context) +{ + struct module *cur_module = context; + struct module *m; + + if (ht_lookup(selecttab, a->a_name)) { + /* it's in the kernel. skip */ + return; + } + + /* We need this attribute for cur_module. */ +#if 0 + printf("%s: %s -> %s\n", __FUNCTION__, + cur_module->m_name, a->a_name); +#endif + + m = ht_lookup(moduletab, a->a_name); + if (m == NULL) { + m = getmodule(a->a_name, M_ATTRIBUTE); + ht_insert(m->m_selecttab, a->a_name, __UNCONST(a->a_name)); + m->u.m_attr = a; + } + else if (m == cur_module) { + /* no need to record dependency */ + return; + } +} + +static void +lkm_record_require(struct attr *a, void *context) +{ + struct module *cur_module = context; + + if (ht_lookup(selecttab, a->a_name)) { + /* it's in the kernel. skip */ + return; + } + +#if 0 + printf("%s: %s -> %s\n", __FUNCTION__, + cur_module->m_name, a->a_name); +#endif + + ht_insert(cur_module->m_require, a->a_name, a); +} + + +static int +/*ARGSUSED*/ +lkm_select_cb(const char *key, void *value, void *aux) +{ + struct module *m = (struct module *)value; + + switch (m->m_type) { + case M_DEVICE: + case M_PSEUDO: + return lkm_select_device(m, aux); + default: + if (m->u.m_attr) + expandattr(m->u.m_attr, m, aux); + } + + return 0; +} + + + +static int +lkm_select_device(struct module *m, void (* attr_func)(struct attr *, void *)) +{ + struct devbase *d; + struct deva *da; + struct attr *a; + struct nvlist *nv; + + STAILQ_FOREACH(d, &m->m_base, d_mnext) { + if (ht_lookup(selecttab, d->d_name) != NULL) + continue; + + ht_insert(m->m_selecttab, d->d_name, __UNCONST(d->d_name)); + for (nv = d->d_attrs; nv != NULL; nv = nv->nv_next) { + a = nv->nv_ptr; + expandattr(a, m, attr_func); + } + } + + STAILQ_FOREACH(da, &m->m_deva, d_mnext) { + if (ht_lookup(selecttab, da->d_name) != NULL) + continue; + ht_insert(m->m_selecttab, da->d_name, __UNCONST(da->d_name)); + for (nv = da->d_attrs; nv != NULL; nv = nv->nv_next) { + a = nv->nv_ptr; + expandattr(a, m, attr_func); + } + } + return 0; +} + +static void +fixlkmfiles2(struct filetype *ft, struct nvlist *expr) +{ + struct module *m; + struct nvlist *p; + + if (ft->fit_nmods == 0) { + /* not for modules */ + } + else if (ft->fit_nmods == 1) { + /* required by just one module. This file simply + * becomes a part of the modules. */ + m = ft->fit_modules->nv_ptr; + STAILQ_INSERT_TAIL(&m->m_files, ft, fit_msame); + + nvfree(ft->fit_modules); + ft->fit_modules = NULL; + } + else { + /* This file is required by multiple modules. */ +#if 1 + /* Merge those modules that share this file into one module */ + struct module *mmod; + + mmod = getmodule(NULL, M_MERGE); + mmod->m_modules = NULL; + mmod->u.m_attr = NULL; + + for (p = ft->fit_modules; p; p = p->nv_next) { + m = p->nv_ptr; + while (m->m_merged) + m = m->m_merged; + if (m == mmod) + continue; + + mmod->m_modules = + newnv(m->m_name, NULL, m, 0, mmod->m_modules); + m->m_merged = mmod; + } + + /* add this file to the merged module */ + STAILQ_INSERT_TAIL(&mmod->m_files, ft, fit_msame); + ft->fit_flags |= FI_MODULE; +#else + /* This is an another way to handle files shared by + multiple modules: Create a new module to have + shared files. */ + + char *expr_str = expr_canonstr(expr); + struct module *fg, *m; + + /* make a group of files which are turned on/off by + * the same expression. */ + + fg = ht_lookup(moduletab, expr_str); + if (fg) { + free(expr_str); + assert(fg->m_type == M_FILEGROUP); + } + else { + /* create a new filegroup */ + fg = newmodule(expr_str, M_FILEGROUP); + assert(fg != NULL); + ht_insert(moduletab, expr_str, fg); + } + + /* add this file to the filegroup */ + STAILQ_INSERT_TAIL(&fg->m_files, ft, fit_msame); + ft->fit_flags |= FI_MODULE; + + for (p = ft->fit_modules; p; p = p->nv_next) { + m = p->nv_ptr; + ht_insert(m->m_require, fg->m_name, fg); + } +#endif + } +} + +#if 0 +static int +/*ARGSUSED*/ +fix_filegroup_cb(const char *key, void *value, void *aux) +{ + struct module *m = (struct module *)value; + char buf[MAXPATHLEN]; + struct filetype *ft; + + if (m->m_type != M_FILEGROUP) + return 0; + + /* currently, this module has a name generated from an + * expression. rename it to a normal module name based on the + * files included in this filegroup */ + + buf[0] = '\0'; + + STAILQ_FOREACH(ft, &m->m_files, fit_msame) { + /* XXX .o */ + struct files *fi = (struct files *)ft; + + /* XXX: I know you can optimize this...*/ + strlcat(buf, "_", sizeof buf); + strlcat(buf, fi->fi_base, sizeof buf); + } + + m->m_name = estrdup(buf); + + /* Now this module has a new name, but the key in moduletab is + * unchanged. + */ + return 0; +} +#endif + +static int +/*ARGSUSED*/ +mark_empty_attr_cb(const char *key, void *value, void *aux) +{ + struct module *m = (struct module *)value; + + if (m->m_merged == NULL && + m->m_type == M_ATTRIBUTE && m->u.m_attr != NULL && + STAILQ_EMPTY(&m->m_files)) { +#if 0 + printf("%s is empty\n", m->u.m_attr->a_name); +#endif + ht_insert(emptyattrtab, m->u.m_attr->a_name, + m->u.m_attr); + } + return 0; +} + +static int +/*ARGSUSED*/ +fix_merged_cb(const char *key, void *value, void *aux) +{ + struct nvlist *p; + struct module *m = (struct module *)value; + struct module *devmod = NULL; + int device = 0; + + if (m->m_type != M_MERGE) + return 0; + + if (m->m_merged != NULL) + return 0; + + for (p=m->m_modules; p; p = p->nv_next) { + struct module *n = p->nv_ptr; + if (n->m_type == M_DEVICE) { + ++device; + devmod = n; + } + else if (n->m_type == M_MERGE) { + struct nvlist *q0, *q1; + /* insert module list from *n */ + q0 = p->nv_next; + p->nv_next = q1 = n->m_modules; + while (q1->nv_next) + q1 = q1->nv_next; + q1->nv_next = q0; + } + + merge_modules(m, n); + } + + /* name the merged module */ + /* if there is only one device in the merged module, use the + * device name for the module. */ + if (device == 1) { + m->m_name = devmod->m_name; + } + /* if the merged module has only one file, use it for + * the module's name */ + else if (!STAILQ_EMPTY(&m->m_files) && + STAILQ_NEXT(STAILQ_FIRST(&m->m_files), fit_msame) == NULL) { + /* XXX */ + struct files *f = (struct files *)STAILQ_FIRST(&m->m_files); + m->m_name = f->fi_base; + } + else { + /* Otherwise, keep autogenerated name such as "M001". + FIXME: Maybe better to use the first file name? + or, append all file names? + */ + } + + if (device) + m->m_type = M_DEVICE; + else + m->m_type = M_ATTRIBUTE; + + return 0; +} + +/* + * Check which file is needed by which modules. + */ +int +fixlkmfiles(void) +{ + struct files *fi; + + if (ht_enumerate(moduletab, lkm_fixfile_cb, NULL)) + return -1; + + TAILQ_FOREACH(fi, &allfiles, fi_next) { + fixlkmfiles2(&fi->fi_fit, fi->fi_optx); + } + +#if 0 + /* fix filegroup modules */ + if (ht_enumerate(moduletab, fix_filegroup_cb, NULL)) + return -1; +#endif + + if (ht_enumerate(moduletab, fix_merged_cb, NULL)) + return -1; + + if (ht_enumerate(moduletab, mark_empty_attr_cb, NULL)) + return -1; + + if (ht_enumerate(moduletab, add_lkm_file_cb, NULL)) + return -1; + + return 0; +} + +static void +add_module_for_file(struct filetype *ft, struct module *m) +{ + ft->fit_modules = newnv(m->m_name, NULL, m, 0, ft->fit_modules); + ft->fit_nmods++; +} + +static int +/*ARGSUSED*/ +lkm_fixfile_cb(const char *key, void *value, void *aux) +{ + struct module *m = (struct module *)value; + struct files *fi; + struct objects *oi; + + TAILQ_FOREACH(fi, &allfiles, fi_next) { + if (fi->fi_flags & (FI_HIDDEN|FI_SEL)) { + /* if the files is in the kernel, skip it */ + continue; + } + + if (expr_eval(fi->fi_optx, lkm_fixsel, m)) { + /* Mark this file is required by modules */ + + add_module_for_file(&fi->fi_fit, m); + } + } + + TAILQ_FOREACH(oi, &allobjects, oi_next) { + if (oi->oi_flags & (FI_HIDDEN|FI_SEL)) { + /* if the files is in the kernel, skip it */ + continue; + } + if (oi->oi_flags & FI_MODULE) { + /* We already know about this file */ + continue; + } + if (expr_eval(oi->oi_optx, lkm_fixsel, m)) { + /* Mark this file is required by modules */ + oi->oi_flags |= FI_MODULE; + + STAILQ_INSERT_HEAD(&m->m_files, &oi->oi_fit, fit_msame); + } + } + + return 0; +} + +static int +lkm_fixsel(const char *name, void *context) +{ + struct module *m = context; + return ht_lookup(selecttab, name) != NULL || + ht_lookup(m->m_selecttab, name) != NULL; +} + +static int +/*ARGSUSED*/ +add_lkm_file_cb(const char *key, void *value, void *aux) +{ + struct module *m = (struct module *)value; + struct files *fi; + char *pathname; + + assert(m->m_lkmfile == NULL); + + if (m->m_merged != NULL) { + /* This module has been merged into the other module. */ + return 0; + } + + switch (m->m_type) { + case M_DEVICE: + if (STAILQ_EMPTY(&m->m_files)) { + if (!STAILQ_EMPTY(&m->m_devi)) { + /* devi only module */ + } + else if (!STAILQ_EMPTY(&m->m_base)) { + /* config staff only */ + } + else { + /* we won't create this module if this + * module is empty. */ + return 0; + } + } + break; + case M_ATTRIBUTE: + default: + if (STAILQ_EMPTY(&m->m_files)) + return 0; + } + + /* add _MODULE_lkm.c */ + asprintf(&pathname, "%s/%s/%s%s/_%s_lkm.c", + builddir, KMODDIR, + m->m_name, KMODWORK_SUFFIX, m->m_name); + + fi = addfile(pathname, NULL, FI_MODULE, NULL); + if (fi == NULL) { + cfgerror("can't create file %s", pathname); + return -1; + } + + m->m_lkmfile = fi; + + return 0; +} + +/* + * Try to reduce the number of LKMs by packing many modules into one. + * This routine is called if option -G is given. + */ +int +packlkms(void) +{ + /* not yet */ + return 0; +} + +/* + * merge module m1 into module m0 + */ +int +merge_modules(struct module *m0, struct module *m1) +{ + if (m1->m_type == M_DEVICE) { + + STAILQ_APPEND(&m0->m_base, &m1->m_base, d_mnext); + STAILQ_INIT(&m1->m_base); + STAILQ_APPEND(&m0->m_deva, &m1->m_deva, d_mnext); + STAILQ_INIT(&m1->m_deva); + STAILQ_APPEND(&m0->m_devi, &m1->m_devi, i_mnext); + STAILQ_INIT(&m1->m_devi); + } + + ht_concat(m0->m_selecttab, m1->m_selecttab, 0); + ht_concat(m0->m_require, m1->m_require, 0); + + /* append file list */ + STAILQ_APPEND(&m0->m_files, &m1->m_files, fit_msame); + STAILQ_INIT(&m1->m_files); + + m1->m_merged = m0; + return 0; +} + +/* + * check device major numbers for LKMs + */ +int +fixlkmdevsw(void) +{ + int er = 0; + + /* XXX: CodeMe! */ + + return er; +} + +/* + * + */ +int +mklkms(void) +{ + char moddir[MAXPATHLEN]; + + if (ht_isempty(moduletab)) { + return 0; + } + + snprintf(moddir, sizeof moddir, "%s/%s", builddir, KMODDIR); + make_directory(moddir); + return ht_enumerate(moduletab, lkm_make_files_cb, NULL); +} + +static int +/*ARGSUSED*/ +lkm_make_files_cb(const char *key, void *value, void *aux) +{ + struct module *m = value; + char moddir[MAXPATHLEN]; + + if (m->m_lkmfile == NULL) + return 0; + + snprintf(moddir, sizeof moddir, "%s/%s/%s%s", + builddir, KMODDIR, m->m_name, KMODWORK_SUFFIX); + make_directory(moddir); + + return lkm_make_makefile(m, moddir) || lkm_make_lkmfile(m, moddir); +} + +static int +lkm_make_makefile(struct module *m, const char *moddir) +{ + static const struct makefile_constructs c[] = { + { "OBJS", lkm_emitobjs }, + { "SRCS", lkm_emitsrcs }, + { "KMOD", lkm_emitkmod }, + { NULL, NULL } + }; + + return mkmakefile_common(c, ".lkm", moddir, m); +} + +static void +lkm_lkmfile_header(struct module *m, struct files *f, + const char *conffile, FILE *fp) +{ + fprintf(fp, "/*\n" + " * MACHINE GENERATED: DO NOT EDIT\n" + " *\n" + " * %s, from \"%s\"\n" + " */\n\n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "\n\n", + + f->fi_base, conffile); +} + + +static void +lkm_devsw(struct module *m, FILE *fp, char **entry_func_name) +{ + struct devbase *d; + struct devm *dm; + int bmaj, cmaj; + int count = 0; + char bdevbuf[30], cdevbuf[30]; + char *bdev, *cdev; + + STAILQ_FOREACH(d, &m->m_base, d_mnext) { + bmaj = cmaj = -1; + + dm = ht_lookup(bdevmtab, d->d_name); + if (dm && dm->dm_active != DEVM_INKERNEL) + bmaj = dm->dm_bmajor; + + dm = ht_lookup(cdevmtab, d->d_name); + if (dm && dm->dm_active != DEVM_INKERNEL) + cmaj = dm->dm_cmajor; + + if (bmaj < 0 && cmaj < 0) + continue; + + if (count++ <= 0) { + asprintf(entry_func_name, "%s_devsw", dm->dm_name); + fprintf(fp, + "\nstatic int\n" + "%s(struct lkm_table *lkmtp, int cmd)\n" + "{\n" + "\tint b, c, er;\n", + *entry_func_name); + } + + if (cmaj < 0) + cdev = "NULL"; + else { + snprintf(cdevbuf, sizeof cdevbuf, "&%s_cdevsw", + d->d_name); + fprintf(fp, "\textern struct cdevsw %s;\n", cdevbuf+1); + cdev = cdevbuf; + } + + if (bmaj < 0) + bdev = "NULL"; + else { + snprintf(bdevbuf, sizeof bdevbuf, "&%s_bdevsw", + d->d_name); + fprintf(fp, "\textern struct bdevsw %s;\n", bdevbuf+1); + bdev = bdevbuf; + } + + fprintf(fp, "\tswitch(cmd) {\n\tcase LKM_E_LOAD:\n"); + + fprintf(fp, + "\t\tb = %d; c = %d;\n" + "\t\ter = devsw_attach(\"%s\", %s, &b, %s, &c);\n" + "\t\tif (er) return er;\n" + "\t\tbreak;\n" + "\tcase LKM_E_UNLOAD:\n" + "\t\tdevsw_detach(%s, %s);\n" + "\t\tbreak;\n" + "\t}\n", + bmaj, cmaj, d->d_name, bdev, cdev, + bdev, cdev); + } + + if (count > 0) { + fprintf(fp, "\n\treturn 0;\n}\n\n"); + } + +} + +static int +lkm_make_lkmfile(struct module *m, const char *moddir) +{ + FILE *fp; + char tmpname[MAXPATHLEN]; + struct files *f = m->m_lkmfile; + char *entry_func = "lkm_nofunc"; + struct emit_require_args args; + + if (f == NULL) + return 0; + +#if 0 + if (m->m_type == M_DEVICE && + (STAILQ_EMPTY(&m->m_devi) && STAILQ_EMPTY(&m->m_base)) ) + return 0; +#endif + + snprintf(tmpname, sizeof tmpname, "%s/tmp_lkm.c", moddir); + + if ((fp = fopen(tmpname, "w")) == NULL) { + warn("cannot write %s", tmpname); + return 1; + } + + switch (m->m_type) { + case M_DEVICE: + lkm_emit_ioconf(m, f, fp); + lkm_devsw(m, fp, &entry_func); + break; + case M_PSEUDO: + lkm_emit_ioconf_pseudo(m, f, fp, &entry_func); + break; + default: + lkm_lkmfile_header(m, f, conffile, fp); + + fprintf(fp, "MOD_MISC(\"%s\");\n", m->m_name); + } + + fprintf(fp, + "int __%s_lkmentry(struct lkm_table*, int, int);\n" + "int\n" + "__%s_lkmentry(struct lkm_table *lkmtp, int cmd, int ver)\n" + "{ DISPATCH(lkmtp, cmd, ver, %s, lkm_nofunc, lkm_nofunc); }\n" + "__weak_alias(%s_lkmentry, __%s_lkmentry);\n", + + m->m_name, + m->m_name, + entry_func, + m->m_name, m->m_name); + + /* emit required module list */ + fprintf(fp, + "\n\nasm(\" .section \\\".note.netbsd.lkm.require\\\",\\\"\\\"\\n\"\n"); + args.fp = fp; + args.cur_module = m; + ht_enumerate(m->m_require, lkm_emitrequire_cb, &args); + fprintf(fp, " \" .byte 0\\n\");\n"); + + /* emit provided attributes */ + fprintf(fp, + "\n\nasm(\" .section \\\".note.netbsd.lkm.provide\\\",\\\"\\\"\\n\"\n"); + ht_enumerate(m->m_selecttab, lkm_emitprovide_cb, fp); + fprintf(fp, " \" .byte 0\\n\");\n"); + + fclose(fp); + + return (moveifchanged(tmpname, f->fi_path)); +} + +static int +lkm_emit_ioconf(struct module *m, struct files *f, FILE *fp) +{ + char cfdataname[80]; + struct devi *i; + struct devbase *d = NULL; + struct deva *da; + struct devi *di; + struct nvlist *att_list = NULL; + struct nvlist *nv; + + ioconf_emithdr(fp, f->fi_tail); + + fprintf(fp, "#include \n\n"); + + STAILQ_FOREACH(d, &m->m_base, d_mnext) { + /* This module has the devbase */ + ioconf_emit_ref_iattrs(d, fp); + ioconf_emit_cfdriver(d, fp); + + for (da = d->d_ahead; da != NULL; da = da->d_bsame) { + if (da->d_name == d->d_name) { + /* the devbase is also an attachment */ + att_list = newnv(da->d_name, NULL, da, 0, + att_list); + + fprintf(fp, "extern struct cfattach %s_ca;\n", + da->d_name); + } + } + } + + STAILQ_FOREACH(da, &m->m_deva, d_mnext) { + att_list = newnv(da->d_name, NULL, da, 0, att_list); + } + fprintf(fp, "\n\n"); + + if (!STAILQ_EMPTY(&m->m_devi)) { + lkm_emit_parents(m, fp); + fprintf(fp, "\n"); + lkm_emit_loc(m, fp); + fprintf(fp, "\n"); + } + + snprintf(cfdataname, sizeof cfdataname, "%s_cfdata", m->m_name); + ioconf_cfdata_start(fp, cfdataname); + + STAILQ_FOREACH(i, &m->m_devi, i_mnext) { + ioconf_cfdata_entry(fp, i); + } + + ioconf_cfdata_end(fp, cfdataname); + + fprintf(fp, "static struct cfdriver *%s_cfdrivers[] = {\n", + m->m_name); + STAILQ_FOREACH(d, &m->m_base, d_mnext) + fprintf(fp, "\t&%s_cd,\n", d->d_name); + fprintf(fp, "\tNULL\n};\n"); + + if (att_list != NULL) { + for (nv = att_list; nv; nv = nv->nv_next) { + fprintf(fp, "extern struct cfattach %s_ca;\n", nv->nv_name); + } + fprintf(fp, "static struct cfattach *%s_cfattachs[] = {\n", + m->m_name); + for (nv = att_list; nv; nv = nv->nv_next) { + fprintf(fp, "\t&%s_ca,\n", nv->nv_name); + } + fprintf(fp, "\tNULL\n};\n"); + } + + /* We want devbase name for this module */ + d = STAILQ_FIRST(&m->m_base); + if (d == NULL) { + da = STAILQ_FIRST(&m->m_deva); + if (da) + d = da->d_devbase; + if (d == NULL) { + di = STAILQ_FIRST(&m->m_devi); + if (di) + d = di->i_base; + } + } + + if (d == NULL) { + cfgerror("can't get device base name for module %s", + m->m_name); + } + else { + fprintf(fp, + "static const struct cfattachlkminit %s_cfattachinit[] = {\n", + m->m_name); + if (att_list != NULL) { + fprintf(fp, + "\t{\"%s\", %s_cfattachs},\n", + d->d_name, m->m_name); + } + fprintf(fp, + "\t{NULL, NULL}\n" + "};\n"); + } + + fprintf(fp, + "int __%s_lkmentry(struct lkm_table*, int, int);\n" + "MOD_DRV(\"%s\", %s_cfdrivers, %s_cfattachinit, %s_cfdata);\n", + m->m_name, + m->m_name, m->m_name, m->m_name, m->m_name); + + if (att_list) + nvfreel(att_list); + + return 0; +} + +static int +lkm_emit_ioconf_pseudo(struct module *m, struct files *f, FILE *fp, char **entry_func_ret) +{ + char cfdataname[80]; + struct devbase *d = NULL; + + ioconf_emithdr(fp, f->fi_tail); + + fprintf(fp, "#include \n\n"); + + d = STAILQ_FIRST(&m->m_base); + assert(d != NULL); + + snprintf(cfdataname, sizeof cfdataname, "%s_cfdata", m->m_name); + + if (devbase_has_instances(d, WILD)) { + ioconf_emit_ref_iattrs(d, fp); + ioconf_emit_cfdriver(d, fp); + + fprintf(fp, "static struct cfdriver *%s_cfdrivers[] = {\n", + m->m_name); + fprintf(fp, "\t&%s_cd,\n", d->d_name); + fprintf(fp, "\tNULL\n};\n"); + + ioconf_cfdata_start(fp, cfdataname); + ioconf_cfdata_end(fp, cfdataname); + + fprintf(fp, + "static const struct cfattachlkminit %s_cfattachinit[] = {\n", + d->d_name); + fprintf(fp, + "\t{NULL, NULL}\n" + "};\n"); + + fprintf(fp, + "MOD_DRV(\"%s\", %s_cfdrivers, %s_cfattachinit, %s_cfdata);\n", + d->d_name, d->d_name, d->d_name, d->d_name); + } + else { + fprintf(fp, + "MOD_MISC(\"%s\");\n", + d->d_name); + } + + fprintf(fp, + "static int __%s_load(struct lkm_table *lkmtp, int cmd)\n" + "{\n" + "\textern void %sattach(int);\n" + "\t%sattach(%d);\n" + "\treturn 0;\n" + "}\n\n", + d->d_name, + d->d_name, d->d_name, d->d_umax); + + if (entry_func_ret) { + asprintf(entry_func_ret, "__%s_load", d->d_name); + } + + return 0; +} + + +static void +lkm_emit_parents(struct module *m, FILE *fp) +{ + struct devi *i; + struct nvlist *nv, *list = NULL; + struct pspec *ps; + + + STAILQ_FOREACH(i, &m->m_devi, i_mnext) { + ps = i->i_pspec; + if (ps == NULL) + continue; + /* Check if we already emit this pspec */ + + for (nv = list; nv; nv = nv->nv_next) + if (nv->nv_ptr == ps) + break; + + if (nv) + continue; + + ioconf_emit_pspec(fp, ps, 1); + + /* remember the pspec */ + list = newnv("", NULL, ps, 0, list); + } + + if (list) + nvfreel(list); +} + +static void +lkm_emit_loc(struct module *m, FILE *fp) +{ + struct pspec *ps; + struct devi *i; + int l, k; + int n = 0; + + fprintf(fp, "\nstatic int loc[] = {"); + + STAILQ_FOREACH(i, &m->m_devi, i_mnext) { + if ((ps = i->i_pspec) != NULL && + (l = ps->p_iattr->a_loclen) > 0) { + + if (n == 0) + fprintf(fp, "\n"); + fprintf(fp, "\t/* %d */\t", n); + for (k = 0; k < l; ++k) { + fprintf(fp, "%s, ", i->i_locs[k]); + } + fprintf(fp, "\n"); + + i->i_locoff = n; + n += l; + } + } + + if (n > 0) { + fprintf(fp, "}; /* %d */\n\n", n); + } + else { + fprintf(fp, " -1 };\n"); + } +} + +void +/*ARGSUSED*/ +emitkmod(FILE *fp, void *aux) +{ + if (ht_isempty(moduletab)) { + fprintf(fp, "# No LKMs\n"); + return; + } + + fprintf(fp, "MODULES= \\\n"); + ht_enumerate(moduletab, lkm_emit_modulelist_cb, fp); + fprintf(fp, "\n"); + +#if 0 + ht_enumerate(moduletab, lkm_emit_moduledefs_cb, fp); + + fprintf(fp, + "\n" + ".if exists(\"$S/arch/%s/conf/Makefile.kmod.inc.%s\")\n" + ".include \"$S/arch/%s/conf/Makefile.kmod.inc.%s\"\n" + ".elif exists(\"$S/arch/%s/conf/Makefile.kmod.inc.%s\")\n" + ".include \"$S/arch/%s/conf/Makefile.kmod.inc.%s\"\n" + ".else\n" + ".include \"$S/conf/Makefile.kmod.inc\"\n" + ".endif\n", + machine, machine, machine, machine, + machinearch, machinearch, machinearch, machinearch); +#endif +} + +static int +/*ARGSUSED*/ +lkm_emit_modulelist_cb(const char *key, void *value, void *aux) +{ + struct module *m = (struct module *)value; + FILE *fp = aux; + + if (m->m_merged != NULL) + return 0; + + if (m_empty(m)) + return 0; + + fprintf(fp, "\t%s \\\n", m->m_name); + + return 1; +} + +#if 0 +static int +/*ARGSUSED*/ +lkm_emit_moduledefs_cb(const char *key, void *value, void *aux) +{ + struct module *m = (struct module *)value; + FILE *fp = aux; + struct filetype *f; + int has_o = 0; + + if (m_empty(m)) { + fprintf(fp, "#MODULE.%s: no files for module %s\n", + m->m_name, m->m_name); + return 0; + } + + fprintf(fp, "MODULE.%s.SRCS=\t", m->m_name); + + STAILQ_FOREACH(f, &m->m_files, fit_msame) { + if (f->fit_path[0] == '/') + fprintf(fp, "%s ", f->fit_path); + else + fprintf(fp, "${S}/%s ", f->fit_path); + + if (f->fit_lastc == 'o') + ++has_o; + } + if (m->m_lkmfile) + fprintf(fp, "%s", m->m_lkmfile->fi_path); + fprintf(fp, "\n"); + + if (!has_o) + return 0; + + STAILQ_FOREACH(f, &m->m_files, fit_msame) { + if (f->fit_lastc != 'o') + continue; + fprintf(fp, "OBJFILE_%s_MODULE=%s\n", + f->fit_path, m->m_name); + } + + return 0; +} +#endif + +static void +lkm_emitkmod(FILE *fp, void *aux) +{ + struct module *m = aux; + + /* .LKM is appended to module name to avoid conflict in case + we have MODULE.c */ + fprintf(fp, "KMOD=\t%s\n", m->m_name); +} + +static void +lkm_emitobjs(FILE *fp, void *aux) +{ + struct module *m = aux; + struct filetype *ft; + const char *sep; + + if (m_empty(m)) { + fprintf(fp, "# no files for module %s\n", + m->m_name); + return; + } + + fprintf(fp, "OBJS=\t"); + sep = ""; + STAILQ_FOREACH(ft, &m->m_files, fit_msame) { + if (ft->fit_lastc != 'o') + continue; + fprintf(fp, "%s%s", sep, ft->fit_path); + sep = "\t\\\n\t"; + } + fprintf(fp, "\n"); +} + +static int +lkm_emitpath_cb(const char *key, void *value, void *aux) +{ + FILE *fp = aux; + if (*key == '/') + fprintf(fp, "%s ", key); + else + fprintf(fp, "${S}/%s ", key); + return 0; +} + +static void +lkm_emitsrcs(FILE *fp, void *aux) +{ + struct module *m = aux; + struct filetype *ft; + struct files *f; + const char *sep; + struct hashtab *ht; + + if (m_empty(m)) { + fprintf(fp, "# no files for module %s\n", + m->m_name); + return; + } + + /* set .PATH for sources */ + ht = ht_new(); + STAILQ_FOREACH(ft, &m->m_files, fit_msame) { + f = (struct files *)ft; + char buf[MAXPATHLEN]; + + if (ft->fit_lastc == 'o') + continue; + + if (f->fi_path == f->fi_tail) { + /* No directory part */ + continue; + } + strlcpy(buf, f->fi_path, + MIN(sizeof buf, f->fi_tail - f->fi_path)); + ht_insert(ht, intern(buf), f); + } + if (!ht_isempty(ht)) { + fprintf(fp, ".PATH: "); + ht_enumerate(ht, lkm_emitpath_cb, fp); + fprintf(fp, "\n"); + } + ht_free(ht); + + fprintf(fp, "SRCS=\t"); + sep = ""; + STAILQ_FOREACH(ft, &m->m_files, fit_msame) { + if (ft->fit_lastc == 'o') + continue; + f = (struct files *)ft; + fprintf(fp, "%s%s", sep, f->fi_tail); + sep = "\t\\\n\t"; + } + + if (m->m_lkmfile) + fprintf(fp, "%s%s", sep, m->m_lkmfile->fi_tail); + fprintf(fp, "\n"); +} + + + +static int +/*ARGSUSED*/ +lkm_emitrequire_cb(const char *key, void *value, void *aux) +{ + struct emit_require_args *args = aux; + struct module *m = value; + +#if 0 + printf("%s: %s -> %s\n", __FUNCTION__, args->cur_module->m_name, m->m_name); +#endif + + if (!ht_lookup(emptyattrtab, m->m_name) && + !ht_lookup(args->cur_module->m_selecttab, m->m_name)) + fprintf(args->fp, " \"\t.asciz \\\"%s\\\"\\n\"\n", m->m_name); + return 0; +} + +static int +/*ARGSUSED*/ +lkm_emitprovide_cb(const char *key, void *value, void *aux) +{ + FILE *fp = aux; + + fprintf(fp, " \"\t.asciz \\\"%s\\\"\\n\"\n", key); + return 0; +} + + +#if 0 +static int +for_all_module_files(struct module *m, + int (* fn)(struct files *, struct module *, void *), + void *arg) +{ + struct files *fi; + struct module *m2; + + TAILQ_FOREACH(fi, &allfiles, fi_next) { + if (STAILQ_EMPTY(&fi->fi_modules)) + continue; + STAILQ_FOREACH(m2, &fi->fi_modules, m_filenext) { + if (m2 == m) { + if (fn(fi, m, arg) != 0) + return 1; + break; + } + } + } + return 0; +} +#endif + +static int +/*ARGSUSED*/ +dump_module_cb2(const char *key, void *value, void *aux) +{ + printf("%s=%p ", key, value); + return 0; +} + +static int +/*ARGSUSED*/ +dump_module_cb(const char *key, void *value, void *aux) +{ + struct module *m = (struct module *)value; + struct devbase *d; + struct devi *i; + struct deva *a; + struct filetype *f; + + printf("module %p %s type=%d\n", m, m->m_name, m->m_type); + printf(" base="); + STAILQ_FOREACH(d, &m->m_base, d_mnext) + printf("%p(%s) ", d, d->d_name); + printf(" deva="); + STAILQ_FOREACH(a, &m->m_deva, d_mnext) { + printf("%p(%s) ", a, a->d_name); + } + printf(" devis="); + STAILQ_FOREACH(i, &m->m_devi, i_mnext) { + printf("%p(%s) ", i, i->i_name); + } + printf("\n selections: "); + + ht_enumerate(m->m_selecttab, dump_module_cb2, NULL); + printf("\n files: "); + + STAILQ_FOREACH(f, &m->m_files, fit_msame) { + printf("%s ", f->fit_path); + } + printf("\n requires: "); + + ht_enumerate(m->m_require, dump_module_cb2, NULL); + printf("\n"); + return 0; +} + +void +dump_module_devis(void) +{ + struct devi *i; + + printf("================\n"); + TAILQ_FOREACH(i, &alldevi, i_next) { + if (i->i_module || i->i_active == DEVI_MODULE) { + printf("devi %p %s i_module=%p i_active=%d\n", + i, i->i_name, i->i_module, i->i_active); + } + else { + printf("devi %s is not module\n", i->i_name); + } + } + + ht_enumerate(moduletab, dump_module_cb, NULL); +} Index: hash.c =================================================================== --- hash.c (.../vendor/netbsd/current-20080118) (revision 51) +++ hash.c (.../tags/patch-1-rc1) (revision 51) @@ -315,3 +315,37 @@ } return rval; } + +/* + * return 1 if the hash table is empty. + */ +int +ht_isempty(struct hashtab *ht) +{ + return ht->ht_used == 0; +} + +/* + * concat two hash tables + */ +struct concat_arg { + struct hashtab *ht; + int replace; +}; + +static int +concat_cb(const char *name, void *value, void *arg) +{ + struct concat_arg *a = arg; + + return ht_insrep(a->ht, name, value, a->replace); +} + +int +ht_concat(struct hashtab *ht0, struct hashtab *ht1, int replace) +{ + struct concat_arg a; + a.replace = replace; + a.ht = ht0; + return ht_enumerate(ht1, concat_cb, &a); +} Index: main.c =================================================================== --- main.c (.../vendor/netbsd/current-20080118) (revision 51) +++ main.c (.../tags/patch-1-rc1) (revision 51) @@ -82,6 +82,7 @@ int vflag; /* verbose output */ int Pflag; /* pack locators */ int Lflag; /* lint config generation */ +int Gflag; /* reduce the number of LKMs */ int yyparse(void); @@ -110,7 +111,6 @@ static int mksymlinks(void); static int mkident(void); static int devbase_has_dead_instances(const char *, void *, void *); -static int devbase_has_any_instance(struct devbase *, int, int, int); static int check_dead_devi(const char *, void *, void *); static void kill_orphans(void); static void do_kill_orphans(struct devbase *, struct attr *, @@ -120,7 +120,6 @@ static const char *strtolower(const char *); void defopt(struct hashtab *ht, const char *fname, struct nvlist *opts, struct nvlist *deps, int obs); - #define LOGCONFIG_LARGE "INCLUDE_CONFIG_FILE" #define LOGCONFIG_SMALL "INCLUDE_JUST_CONFIG" @@ -147,7 +146,7 @@ pflag = 0; xflag = 0; - while ((ch = getopt(argc, argv, "DLPgpvb:s:x")) != -1) { + while ((ch = getopt(argc, argv, "DGLPgpvb:s:x")) != -1) { switch (ch) { #ifndef MAKE_BOOTSTRAP @@ -156,6 +155,9 @@ break; #endif + case 'G': + Gflag = 1; + break; case 'L': Lflag = 1; break; @@ -280,6 +282,8 @@ nextmkopt = &mkoptions; nextappmkopt = &appmkoptions; nextfsopt = &fsoptions; + moduletab = ht_new(); + emptyattrtab = ht_new(); /* * Handle profiling (must do this before we try to create any @@ -363,7 +367,7 @@ /* * Select devices and pseudo devices and their attributes */ - if (fixdevis()) + if (fixdevis() || fixlkmdevs()) stop(); /* @@ -384,9 +388,20 @@ stop(); /* + * Fix files for LKMs, then group the files into modules. + */ + if (fixlkmfiles()) + stop(); + + if (Gflag) { + if (packlkms()) + stop(); + } + + /* * Fix device-majors. */ - if (fixdevsw()) + if (fixdevsw() || fixlkmdevsw()) stop(); /* @@ -421,7 +436,8 @@ * Ready to go. Build all the various files. */ if (mksymlinks() || mkmakefile() || mkheaders() || mkswap() || - mkioconf() || (do_devsw ? mkdevsw() : 0) || mkident()) + mkioconf() || (do_devsw ? mkdevsw() : 0) || mkident() || + mklkms()) stop(); (void)printf("Build directory is %s\n", builddir); (void)printf("Don't forget to run \"make depend\"\n"); @@ -481,7 +497,7 @@ if (a->a_iattr) panic("do_depend(%s): dep `%s' is an iattr", nv->nv_name, a->a_name); - expandattr(a, selectattr); + expandattr(a, NULL, selectattr); } else { if (ht_lookup(opttab, nv->nv_name) == NULL) addoption(nv->nv_name, NULL); @@ -878,7 +894,7 @@ * file system type. The name is then treated like a standard option. */ void -addfsoption(const char *name) +addfsoption(const char *name, int module) { const char *n; @@ -888,6 +904,12 @@ return; } + /* XXX */ + if (module) { + cfgerror("module for file-system %s: not supported yet", name); + return; + } + /* * Convert to lower case. This will be used in the select * table, to verify root file systems. @@ -1206,11 +1228,7 @@ if (builddir == NULL) builddir = defbuilddir; - if (stat(builddir, &st) == -1) { - if (mkdir(builddir, 0777) == -1) - errx(EXIT_FAILURE, "cannot create %s", builddir); - } else if (!S_ISDIR(st.st_mode)) - errx(EXIT_FAILURE, "%s is not a directory", builddir); + make_directory(builddir); if (chdir(builddir) == -1) err(EXIT_FAILURE, "cannot change to %s", builddir); if (stat(srcdir, &st) == -1) @@ -1519,16 +1537,22 @@ * may have special considerations regarding ignored instances. */ -static int +int devbase_has_any_instance(struct devbase *dev, int unit, int state, int level) { struct deva *da; struct devi *i; if (dev->d_ispseudo) { - if (dev->d_ihead != NULL) - return 1; - else if (state != DEVI_IGNORED) + if (dev->d_ihead != NULL) { + i = dev->d_ihead; + if (state == DEVI_MODULE && i->i_module) + return 1; + if (state == DEVI_ACTIVE && i->i_module == NULL) + return 1; + } + + if (state != DEVI_IGNORED) return 0; if ((i = ht_lookup(deaddevitab, dev->d_name)) == NULL) return 0; @@ -1538,6 +1562,7 @@ for (da = dev->d_ahead; da != NULL; da = da->d_bsame) for (i = da->d_ihead; i != NULL; i = i->i_asame) if ((i->i_active == DEVI_ACTIVE || + i->i_active == DEVI_MODULE || i->i_active == state) && (unit == WILD || unit == i->i_unit || i->i_unit == STAR)) @@ -1613,7 +1638,9 @@ */ if (d->d_ispseudo) { if (d->d_ihead != NULL) - d->d_ihead->i_active = active = DEVI_ACTIVE; + d->d_ihead->i_active = active = + d->d_ihead->i_module != NULL ? + DEVI_MODULE : DEVI_ACTIVE; else { if (ht_lookup(deaddevitab, d->d_name) != NULL) active = DEVI_IGNORED; @@ -1623,41 +1650,84 @@ } else { int seen = 0; - for (i = d->d_ihead; i != NULL; i = i->i_bsame) { - for (j = i; j != NULL; j = j->i_alias) { - p = j->i_pspec; - if ((p == NULL && at == NULL) || - (p != NULL && p->p_iattr == at && - (p->p_atdev == NULL || - p->p_atdev == parent))) { - if (p != NULL && - !devbase_has_any_instance(parent, - p->p_atunit, state, j->i_level)) - continue; +#define FOR_ALL_ALIASES(i, j, d) \ + for (i = d->d_ihead; i != NULL; i = i->i_bsame) \ + for (j = i; j != NULL; j = j->i_alias) + + FOR_ALL_ALIASES(i, j, d) { + p = j->i_pspec; + if ((p == NULL && at == NULL) || + (p != NULL && p->p_iattr == at && + (p->p_atdev == NULL || + p->p_atdev == parent))) { + if (p != NULL && + !devbase_has_any_instance(parent, + p->p_atunit, state, j->i_level)) + continue; + /* + * There are Fry-like devices which can + * be their own grand-parent (or even + * parent, like uhub). We don't want + * to loop, so if we've already reached + * an instance for one reason or + * another, stop there. + */ + if (j->i_active == DEVI_ACTIVE || + j->i_active == DEVI_MODULE || + j->i_active == state) { /* - * There are Fry-like devices which can - * be their own grand-parent (or even - * parent, like uhub). We don't want - * to loop, so if we've already reached - * an instance for one reason or - * another, stop there. + * Device has already been + * seen. However it might + * have siblings who still + * have to be activated or + * orphaned. */ - if (j->i_active == DEVI_ACTIVE || - j->i_active == state) { - /* - * Device has already been - * seen. However it might - * have siblings who still - * have to be activated or - * orphaned. - */ - seen = 1; - continue; - } + seen = 1; + continue; + } + + if (state == DEVI_MODULE && + j->i_module == NULL) { + + /* We are looking at children + of a LKM device. leave + this non-LKM device as + orphan. + */ + printf("Leave as orphan %s\n", + j->i_name); + continue; + } + + if (j->i_module) { + j->i_active = + state == DEVI_ACTIVE ? + DEVI_MODULE : state; + if (active != DEVI_ACTIVE) + active = j->i_active; + } + else { j->i_active = active = state; - if (p != NULL) - p->p_active = state; } + + if (p == NULL) + continue; + + /* change p->p_active: + ORPHAN->ACTIVE or MODULE + ACTIVE->MODULE */ + + if (p->p_active == DEVI_ORPHAN) + p->p_active = active; + else { +#if 0 + printf("%s: p_active: %d %d\n", + p->p_iattr->a_name, + p->p_active, active); +#endif + if (active == DEVI_ACTIVE) + p->p_active = active; + } } } /* @@ -1686,10 +1756,19 @@ } } + if (active == DEVI_MODULE) + active = DEVI_ACTIVE; + for (nv = d->d_attrs; nv != NULL; nv = nv->nv_next) { a = nv->nv_ptr; - for (nv1 = a->a_devs; nv1 != NULL; nv1 = nv1->nv_next) + for (nv1 = a->a_devs; nv1 != NULL; nv1 = nv1->nv_next) { +#if 0 + struct devbase *b = nv1->nv_ptr; + printf(" attr %s=>dev %s state/active=%d/%d\n", + a->a_name, b->d_name, state, active); +#endif do_kill_orphans(nv1->nv_ptr, a, d, active); + } } } @@ -1704,5 +1783,31 @@ static void kill_orphans(void) { + ht_enumerate(devroottab, kill_orphans_cb, NULL); } + + +#if 0 +/*----------------------------------------------------------------*/ +static void +find_orphan_modules(void) +{ + struct devi *i; + + TAILQ_FOREACH(i, &alldevi, i_next){ + if (i->i_active == DEVI_ORPHAN && + i->i_module != NULL) { + printf("%s is orphan module. pspec=%p\n", + i->i_name, i->i_pspec); + if (i->i_pspec) { + printf(" p_iattr=%p p_atdev=%p\n", + i->i_pspec->p_iattr, + i->i_pspec->p_atdev); + } + } + } + +} +#endif + Index: sem.c =================================================================== --- sem.c (.../vendor/netbsd/current-20080118) (revision 51) +++ sem.c (.../tags/patch-1-rc1) (revision 51) @@ -265,7 +265,7 @@ a->a_expanding = 0; /* Expand the attribute to check for cycles in the graph. */ - expandattr(a, NULL); + expandattr(a, NULL, NULL); return (0); } @@ -592,7 +592,7 @@ * cycles, and invoking a callback for each attribute found. */ void -expandattr(struct attr *a, void (*callback)(struct attr *)) +expandattr(struct attr *a, void *data, void (*callback)(struct attr *, void *)) { struct nvlist *nv; struct attr *dep; @@ -607,12 +607,12 @@ /* First expand all of this attribute's dependencies. */ for (nv = a->a_deps; nv != NULL; nv = nv->nv_next) { dep = nv->nv_ptr; - expandattr(dep, callback); + expandattr(dep, data, callback); } /* ...and now invoke the callback for ourself. */ if (callback != NULL) - (*callback)(a); + (*callback)(a, data); a->a_expanding = 0; } @@ -907,6 +907,7 @@ i->i_atdeva = NULL; i->i_locs = NULL; i->i_cfflags = 0; + i->i_module = NULL; i->i_lineno = currentline(); i->i_srcfile = yyfile; i->i_active = DEVI_ORPHAN; /* Proper analysis comes later */ @@ -921,7 +922,8 @@ * another device instead) plus unit number. */ void -adddev(const char *name, const char *at, struct nvlist *loclist, int flags) +adddev(const char *name, const char *at, struct nvlist *loclist, int flags, + int module_flag) { struct devi *i; /* the new instance */ struct pspec *p; /* and its pspec */ @@ -1055,6 +1057,7 @@ i->i_pspec = p; i->i_atdeva = iba; i->i_cfflags = flags; + i->i_module = module_flag ? module_mark : NULL; *iba->d_ipp = i; iba->d_ipp = &i->i_asame; @@ -1396,12 +1399,21 @@ } void -addpseudo(const char *name, int number) +addpseudo(const char *name, int number, int module_flag) { struct devbase *d; struct devi *i; d = ht_lookup(devbasetab, name); + +#if 1 + if (module_flag) { /* XXX */ + cfgerror("module for pseudo-device %s: not supported yet", + name); + return; + } +#endif + if (d == NULL) { cfgerror("undefined pseudo-device %s", name); return; @@ -1419,7 +1431,15 @@ panic("addpseudo(%s)", name); /* Useful to retrieve the instance from the devbase */ d->d_ihead = i; - i->i_active = DEVI_ACTIVE; + + if (module_flag) { + i->i_active = DEVI_MODULE; + i->i_module = module_mark; + } + else { + i->i_active = DEVI_ACTIVE; + i->i_module = NULL; + } TAILQ_INSERT_TAIL(&allpseudo, i, i_next); } @@ -1655,7 +1675,7 @@ } void -selectattr(struct attr *a) +selectattr(struct attr *a, void *context) { (void)ht_insert(selecttab, a->a_name, __UNCONST(a->a_name)); @@ -1674,13 +1694,13 @@ (void)ht_insert(selecttab, d->d_name, __UNCONST(d->d_name)); for (nv = d->d_attrs; nv != NULL; nv = nv->nv_next) { a = nv->nv_ptr; - expandattr(a, selectattr); + expandattr(a, NULL, selectattr); } if (da != NULL) { (void)ht_insert(selecttab, da->d_name, __UNCONST(da->d_name)); for (nv = da->d_attrs; nv != NULL; nv = nv->nv_next) { a = nv->nv_ptr; - expandattr(a, selectattr); + expandattr(a, NULL, selectattr); } } } Index: modload.py =================================================================== --- modload.py (.../vendor/netbsd/current-20080118) (revision 0) +++ modload.py (.../tags/patch-1-rc1) (revision 51) @@ -0,0 +1,252 @@ +#!/usr/bin/env python +"""Wrapper for /sbin/modload + +Usage: modload.py [-Mpath1:path2...] [-Adinvs] [-o output] files ... + + -A automatically load required LKMs. + -d passed to /sbin/modload. + -i print dependencies for LKM files. + -M path module search path. + -n don't run. print what to do. + -n don't run. print what to do. + -o output passed to /sbin/modload. + -s passed to /sbin/modload. + -v be verbose. +""" + +import sys, getopt, os, re +from sys import stderr +from os.path import basename, dirname + +def usage_and_exit(r): + "print usage to stderr, then exit" + print >> stderr, """\ +Usage: %(program)s [-Ainvs] [-M path1:path2...] [-o output] files...""" % \ + {"program": sys.argv[0]} + sys.exit(r) + + +#modload_prog = "/bin/echo" +modload_prog = "/sbin/modload" + +options = {} +lkm_pool = None +module_path = ['.', "/usr/lkm"] + +class LkmPool: + def __init__(self): + self.all_lkms = {} + self.features = {} + + def add(self, lkm): + if self.all_lkms.has_key(lkm.basename): + # print >> stderr, "LKM file " + lkm.basename + " is ignored." + pass + else: + self.all_lkms[lkm.basename] = lkm + for f in lkm.provide: + self.features[f] = lkm + + def find(self, req): + "Find an LKM that provides required feature" + try: + return self.features[req] + except KeyError: + return None + + def scan_dir(self, dir): + print >> stderr, "Scanning", dir + files = os.listdir(dir) + for f in files: + ff = os.path.join(dir,f) + if os.path.splitext(f)[1] == ".o" and \ + not os.path.isdir(ff): + self.add(LoadableKernelModule(ff)) + + def get(self, fname): + base = basename(fname) + if self.all_lkms.has_key(base): + return self.all_lkms[base] + new_lkm = LoadableKernelModule(fname) + self.all_lkms[base] = new_lkm + return new_lkm + +class LoadableKernelModule: + "A class to represent LKM" + + def read_dependencies(self, offset, size): + f = open(self.filename,"r") + f.seek(offset) + data = f.read(size) + f.close() + data = data.rstrip('\x00') + if len(data) == 0: # We need this because + return [] # "".split('\x00') returns [''] + return data.split('\x00') + + def __init__(self,fname): + self.filename = fname + self.basename = basename(fname) + self.dirname = dirname(fname) + self.follows = {} + self.provide = self.require = {} + + objdump = os.popen("objdump -h %(fname)s" % {"fname": fname}, + "r"); + for line in objdump: + m = re.search(r"^\s*\d+\s+.note.netbsd.lkm.(require|provide)\s*", + line) + if m: + reqpro = m.group(1) + postmatch = line[m.end():] + size, vma, lma, fileoff, align = postmatch.split() + a = self.read_dependencies(int(fileoff,16), + int(size, 16)) + if reqpro == "require": + self.require = a + else: + self.provide = a + + objdump.close() + + + def __str__(self): + return "LKM<" + self.filename + ">" + + + def print_info(self): + print self.filename, "requires:" + for a in self.require: + print "\t", a + print self.filename, "provides:" + for a in self.provide: + print "\t", a + +# +# for modload -i files... +# +def list_provide_and_require(fname): + "print LKM depedency informations for `filename'" + lkm = lkm_pool.get(fname) + lkm.print_info() + +def resolve(files): + """find all LKMs required by ones in `files', + and sort all LKMs in loading order""" + + dir_searched = False + lkms_to_load = {} + + for f in files: + lkm = LoadableKernelModule(f) + lkms_to_load[lkm] = True + lkm_pool.add(lkm) + + def scan_dirs(dirs): + for dir in dirs: + if dir == "": + dir = "." + lkm_pool.scan_dir(dir) + + changed = True + while changed: + changed = False + for o in lkms_to_load.keys(): + # print >> stderr, "Checking for", o + for d in o.require: + # print >> stderr, " requires", d + lkm = lkm_pool.find(d) + if lkm: + # print >> stderr, " provided by", lkm + if lkms_to_load.has_key(lkm): + pass # already in the list + else: + lkms_to_load[lkm] = o + changed = True + o.follows[lkm] = True + else: + if not dir_searched: + scan_dirs( module_path ) + dir_searched = True + changed = True + else: + print >> stderr, "No modules for feature", d + +# for k, v in lkms_to_load.iteritems(): +# print k, "<-", v +# print k.require + + order = [] + while len(lkms_to_load) > 0: + a = lkms_to_load.keys() + for lkm in a: + leaf = True + for p in lkm.follows.keys(): + if lkms_to_load.has_key(p): + leaf = False + if leaf: + order.append(lkm) + del lkms_to_load[lkm] + return order + +def run_modload(file): + args = [modload_prog] + for o in ["-o", "-v", "-d"]: + if options.has_key(o): args.append(o + options[o]) + if options.has_key("-s") or options.has_key("-A"): args.append("-s") + args.append(file) + + if options.has_key("-n"): + if options.has_key("-v"): print "Loading", file, "..." + print " ".join(args) + status = 0 + else: + if options.has_key("-v"): print >> stderr, "Loading", file + "..." + status = os.spawnv(os.P_WAIT, modload_prog, args) + return status + + +def main(): + global lkm_pool + global options + global module_path + + try: + opts, args = getopt.getopt(sys.argv[1:], "AdiM:nvso:") + except getopt.GetoptError, errmsg: + print >> stderr, "%(program)s: %(errmsg)s" %\ + {"program": sys.argv[0], "errmsg": errmsg} + usage_and_exit(2) + + lkm_pool = LkmPool() + + for o, a in opts: + options[o] = a + + if len(args) == 0: + print >> stderr, "Too few arguments" + usage_and_exit(2) + + if options.has_key("-i"): + for f in args: + list_provide_and_require(f) + sys.exit(0) + + if options.has_key("-M"): + module_path = options["-M"].split(":") + else: + module_path = [ dirname(args[0]), "/usr/lkm" ] + + if not options.has_key("-A"): + err = 0 + for f in args: + if run_modload(f) != 0: err += 1 + sys.exit(err) + + load_order = resolve(args) + + for lkm in load_order: + run_modload(lkm.filename) + +if __name__ == "__main__": + main() Property changes on: modload.py ___________________________________________________________________ Name: svn:executable + * Index: defs.h =================================================================== --- defs.h (.../vendor/netbsd/current-20080118) (revision 51) +++ defs.h (.../tags/patch-1-rc1) (revision 51) @@ -208,6 +208,8 @@ struct deva *d_ahead; /* first attachment, if any */ struct deva **d_app; /* used for tacking on attachments */ struct attr *d_classattr; /* device class attribute (if any) */ + struct module *d_module; /* this device is compiled in the LKM */ + STAILQ_ENTRY(devbase) d_mnext; /* devices in the same LKM */ }; struct deva { @@ -220,6 +222,9 @@ struct nvlist *d_attrs; /* attributes, if any */ struct devi *d_ihead; /* first instance, if any */ struct devi **d_ipp; /* used for tacking on more instances */ + struct module *d_module; /* this device is compiled in the LKM */ + STAILQ_ENTRY(deva) d_mnext; /* devices in the same LKM */ + }; /* @@ -241,6 +246,8 @@ struct devi *i_bsame; /* list on same base */ struct devi *i_asame; /* list on same base attachment */ struct devi *i_alias; /* other aliases of this instance */ + struct module *i_module; /* this device is compiled in the LKM */ + STAILQ_ENTRY(devi) i_mnext; /* devices in the same LKM */ const char *i_at; /* where this is "at" (NULL if at root) */ struct pspec *i_pspec; /* parent spec (NULL if at root) */ struct deva *i_atdeva; @@ -254,6 +261,7 @@ #define DEVI_ACTIVE 1 /* instance has an active parent */ #define DEVI_IGNORED 2 /* instance's parent has been removed */ #define DEVI_BROKEN 3 /* instance is broken (syntax error) */ +#define DEVI_MODULE 4 /* instance is compiled as LKM */ /* created during packing or ioconf.c generation */ short i_collapsed; /* set => this alias no longer needed */ @@ -277,6 +285,10 @@ char fit_lastc; /* last char from path */ const char *fit_path; /* full file path */ const char *fit_prefix; /* any file prefix */ + + STAILQ_ENTRY(filetype) fit_msame; /* list of files in the same module */ + struct nvlist *fit_modules; /* list of modules which need this file */ + int fit_nmods; /* the number of modules which need this file */ }; /* Anything less than 0x10 is sub-type specific */ #define FIT_NOPROLOGUE 0x10 /* Don't prepend $S/ */ @@ -310,12 +322,14 @@ #define fi_lastc fi_fit.fit_lastc #define fi_path fi_fit.fit_path #define fi_prefix fi_fit.fit_prefix +#define fi_msame fi_fit.fit_msame /* flags */ #define FI_SEL 0x01 /* selected */ #define FI_NEEDSCOUNT 0x02 /* needs-count */ #define FI_NEEDSFLAG 0x04 /* needs-flag */ #define FI_HIDDEN 0x08 /* obscured by other(s), base names overlap */ +#define FI_MODULE 0x10 /* Used only for modules */ /* * Objects and libraries. This allows precompiled object and library @@ -324,8 +338,8 @@ struct objects { struct filetype oi_fit; TAILQ_ENTRY(objects) oi_next; - struct nvlist *oi_optx;/* options expression */ - struct nvlist *oi_optf;/* flattened version of above, if needed */ + struct nvlist *oi_optx; /* options expression */ + struct nvlist *oi_optf; /* flattened version of above, if needed */ }; #define oi_srcfile oi_fit.fit_srcfile @@ -334,6 +348,7 @@ #define oi_lastc oi_fit.fit_lastc #define oi_path oi_fit.fit_path #define oi_prefix oi_fit.fit_prefix +#define oi_msame oi_fit.fit_msame /* flags */ #define OI_SEL 0x01 /* selected */ @@ -364,9 +379,64 @@ int dm_cmajor; /* character major */ int dm_bmajor; /* block major */ struct nvlist *dm_opts; /* options */ + enum { DEVM_IDLE, DEVM_MODULE, DEVM_INKERNEL } dm_active; }; /* + * Modules. + */ +struct module { + const char *m_name; + struct hashtab *m_selecttab; /* selects things that goes to + * this module */ + struct hashtab *m_require; /* modules this module needs */ + + enum module_type { + M_DEVICE, + M_PSEUDO, + M_FILESYSTEM, + M_ATTRIBUTE, +#if 1 + M_MERGE +#else + M_FILEGROUP +#endif + } m_type; + + union { + /* for M_DEVICE */ + struct { + STAILQ_HEAD(, devbase) md_base; + STAILQ_HEAD(, deva) md_deva; + STAILQ_HEAD(, devi) md_devi; + } m_dev; + + /* M_ATTRIBUTE */ + struct attr *m_attr; + } u; + + struct files *m_lkmfile; /* _MODULE_lkm.c */ + STAILQ_HEAD(, filetype) m_files; + + struct nvlist *m_modules; /* M_MERGE */ + struct module *m_merged; /* merged into the other module */ +}; + +#define m_base u.m_dev.md_base +#define m_deva u.m_dev.md_deva +#define m_devi u.m_dev.md_devi + +/* No files for the module. */ +#define m_empty(m) ((m)->m_lkmfile == NULL && STAILQ_EMPTY(&(m)->m_files)) + +/* + * Used to indicate a device is compiled as an LKM. + * struct devi.i_module is first set to this value, then + * changed to a correct struct module object. + */ +#define module_mark ((struct module *)0x00000001) + +/* * Hash tables look up name=value pairs. The pointer value of the name * is assumed to be constant forever; this can be arranged by interning * the name. (This is fairly convenient since our lexer does this for @@ -415,6 +485,8 @@ struct hashtab *attrtab; /* attributes (locators, etc.) */ struct hashtab *bdevmtab; /* block devm lookup */ struct hashtab *cdevmtab; /* character devm lookup */ +struct hashtab *moduletab; /* LKM lookup */ +struct hashtab *emptyattrtab; /* attributes with no codes */ TAILQ_HEAD(, devbase) allbases; /* list of all devbase structures */ TAILQ_HEAD(, deva) alldevas; /* list of all devbase attachments */ @@ -458,8 +530,10 @@ int fixfiles(void); /* finalize */ int fixobjects(void); int fixdevsw(void); -void addfile(const char *, struct nvlist *, int, const char *); +struct files *addfile(const char *, struct nvlist *, int, const char *); void addobject(const char *, struct nvlist *, int); +int expr_eval(struct nvlist *, int (*)(const char *, void *), void *); +char *expr_canonstr(struct nvlist *); /* hash.c */ struct hashtab *ht_new(void); @@ -473,6 +547,8 @@ const char *intern(const char *); typedef int (*ht_callback)(const char *, void *, void *); int ht_enumerate(struct hashtab *, ht_callback, void *); +int ht_isempty(struct hashtab *); +int ht_concat(struct hashtab *, struct hashtab *, int); /* lint.c */ void emit_instances(void); @@ -481,7 +557,7 @@ /* main.c */ void addoption(const char *, const char *); -void addfsoption(const char *); +void addfsoption(const char *, int); void addmkoption(const char *, const char *); void appendmkoption(const char *, const char *); void appendcondmkoption(const char *, const char *, const char *); @@ -493,6 +569,8 @@ void delfsoption(const char *); void delmkoption(const char *); int devbase_has_instances(struct devbase *, int); +int devbase_has_any_instance(struct devbase *, int, int, int); + struct nvlist * find_declared_option(const char *); int deva_has_instances(struct deva *, int); void setupdirs(void); @@ -517,9 +595,22 @@ /* mkioconf.c */ int mkioconf(void); +void ioconf_emithdr(FILE *, const char *); +void ioconf_cfdata_start(FILE *, const char *); +void ioconf_cfdata_entry(FILE *, struct devi *); +void ioconf_cfdata_end(FILE *, const char *); +void ioconf_emit_pspec(FILE *, struct pspec *, int); +void ioconf_emit_cfdriver(struct devbase *, FILE *); +void ioconf_emit_ref_iattrs(struct devbase *d, FILE *fp); /* mkmakefile.c */ int mkmakefile(void); +struct makefile_constructs { + const char *str; + void (* func)(FILE *, void *); +}; +int mkmakefile_common(const struct makefile_constructs *, + const char *, const char *, void *); /* mkswap.c */ int mkswap(void); @@ -527,6 +618,15 @@ /* pack.c */ void pack(void); +/* lkm.c */ +int fixlkmdevs(void); +int fixlkmfiles(void); +int packlkms(void); +int mklkms(void); +void emitkmod(FILE *, void *); +void dump_module_devis(void); +int fixlkmdevsw(void); + /* scan.l */ int currentline(void); int firstfile(const char *); @@ -556,6 +656,7 @@ void nvfreel(struct nvlist *); struct nvlist *nvcat(struct nvlist *, struct nvlist *); void autogen_comment(FILE *, const char *); +void make_directory(const char *); /* liby */ void yyerror(const char *); Index: moddep =================================================================== --- moddep (.../vendor/netbsd/current-20080118) (revision 0) +++ moddep (.../tags/patch-1-rc1) (revision 51) @@ -0,0 +1,32 @@ +#!/usr/pkg/bin/perl + +use English; + +for $f (@ARGV) { + die "can't find $f" unless -r $f; + + open(SECTION, "objdump -h $f|") || die "$!"; + while (
) { + + if (/^\s*\d+\s+.note.netbsd.lkm.(require|provide)\s*/) { + $reqpro = $1; + ($size, $vma, $lma, $fileoff, $align) = split(/\s+/, $POSTMATCH); + $D{$reqpro}->{OFF} = hex $fileoff; + $D{$reqpro}->{SIZE} = hex $size; + } + } + close(SECTION); + + open(LKM, $f) || die "$!"; + for $k (keys %D) { + + seek LKM, $D{$k}->{OFF}, 0; + read LKM, $_, $D{$k}->{SIZE}; + $D{$k}->{DATA} = $_; + + print "$f ${k}s:\n"; + map {print "\t$_\n";} split(/\000/, $_); + } + + +} Property changes on: moddep ___________________________________________________________________ Name: svn:executable + * Index: sem.h =================================================================== --- sem.h (.../vendor/netbsd/current-20080118) (revision 51) +++ sem.h (.../tags/patch-1-rc1) (revision 51) @@ -53,18 +53,18 @@ struct devbase *getdevbase(const char *); struct deva *getdevattach(const char *); struct attr *getattr(const char *); -void expandattr(struct attr *, void (*)(struct attr *)); -void selectattr(struct attr *); +void expandattr(struct attr *, void *, void (*)(struct attr *, void *)); +void selectattr(struct attr *, void *); void setmajor(struct devbase *, int); void addconf(struct config *); void setconf(struct nvlist **, const char *, struct nvlist *); void delconf(const char *); void setfstype(const char **, const char *); -void adddev(const char *, const char *, struct nvlist *, int); +void adddev(const char *, const char *, struct nvlist *, int, int); void deldevi(const char *, const char *); void deldeva(const char *); void deldev(const char *); -void addpseudo(const char *, int); +void addpseudo(const char *, int, int); void delpseudo(const char *); void adddevm(const char *, int, int, struct nvlist *); int fixdevis(void); Index: Makefile =================================================================== --- Makefile (.../vendor/netbsd/current-20080118) (revision 51) +++ Makefile (.../tags/patch-1-rc1) (revision 51) @@ -5,7 +5,7 @@ PROG= config SRCS= files.c gram.y hash.c lint.c main.c mkdevsw.c mkheaders.c mkioconf.c \ - mkmakefile.c mkswap.c pack.c scan.l sem.c util.c + mkmakefile.c mkswap.c pack.c lkm.c scan.l sem.c util.c .PATH: ${NETBSDSRCDIR}/usr.bin/cksum SRCS+= crc.c Index: scan.l =================================================================== --- scan.l (.../vendor/netbsd/current-20080118) (revision 51) +++ scan.l (.../tags/patch-1-rc1) (revision 51) @@ -149,6 +149,7 @@ maxpartitions return MAXPARTITIONS; maxusers return MAXUSERS; minor return MINOR; +module return MODULE; needs-count return NEEDS_COUNT; needs-flag return NEEDS_FLAG; no return NO; Property changes on: . ___________________________________________________________________ Name: svn:ignore + TAGS obj.* Index: files.c =================================================================== --- files.c (.../vendor/netbsd/current-20080118) (revision 51) +++ files.c (.../tags/patch-1-rc1) (revision 51) @@ -69,9 +69,10 @@ static int fixcount(const char *, void *); static int fixfsel(const char *, void *); static int fixsel(const char *, void *); -static int expr_eval(struct nvlist *, - int (*)(const char *, void *), void *); static void expr_free(struct nvlist *); +//static char *expr_canonstr_sub(struct nvlist *, char *, size_t); +static int getlastc(const char *); +static int fixdevmtab_sub(int, struct hashtab *, struct devm *); void initfiles(void) @@ -84,7 +85,7 @@ TAILQ_INIT(&allobjects); } -void +struct files * addfile(const char *path, struct nvlist *optx, int flags, const char *rule) { struct files *fi; @@ -140,7 +141,7 @@ if (rule != NULL && optx == NULL && flags == 0 && yyfile != fi->fi_srcfile) { fi->fi_mkrule = rule; - return; + return NULL; } cfgerror("duplicate file %s", path); cfgxerror(fi->fi_srcfile, fi->fi_srcline, @@ -161,9 +162,10 @@ fi->fi_optf = NULL; fi->fi_mkrule = rule; TAILQ_INSERT_TAIL(&allfiles, fi, fi_next); - return; + return fi; bad: expr_free(optx); + return NULL; } void @@ -188,6 +190,7 @@ oi->oi_srcline = currentline(); oi->oi_flags = flags; oi->oi_path = path; + oi->oi_lastc = getlastc(path); oi->oi_prefix = SLIST_EMPTY(&prefixes) ? NULL : SLIST_FIRST(&prefixes)->pf_prefix; oi->oi_optx = optx; @@ -251,8 +254,9 @@ err = 0; TAILQ_FOREACH(fi, &allfiles, fi_next) { - /* Skip files that generated counted-device complaints. */ - if (fi->fi_flags & FI_HIDDEN) + /* Skip files that generated counted-device complaints. + or that are only for modules (ex. _MOD_lkm.c) */ + if (fi->fi_flags & (FI_HIDDEN|FI_MODULE)) continue; /* Optional: see if it is to be included. */ @@ -343,7 +347,7 @@ int error; struct devm *dm, *res; struct hashtab *fixdevmtab; - char mstr[16]; + struct devbase *d; error = 0; fixdevmtab = ht_new(); @@ -378,53 +382,39 @@ dm->dm_name, dm->dm_cmajor, dm->dm_bmajor); } - if (dm->dm_opts != NULL && - !expr_eval(dm->dm_opts, fixsel, NULL)) + if (dm->dm_opts == NULL || + expr_eval(dm->dm_opts, fixsel, NULL)) { +#if 0 + printf("devm %s bmajor=%d cmajor=%d\n", + dm->dm_name, dm->dm_bmajor, dm->dm_cmajor); +#endif + dm->dm_active = DEVM_INKERNEL; + } + else if ((d = ht_lookup(devbasetab, dm->dm_name)) != NULL && + d->d_module != NULL) { +#if 0 + printf("devm %s base=%s bmajor=%d cmajor=%d\n", + dm->dm_name, d->d_name, + dm->dm_bmajor, dm->dm_cmajor); +#endif + dm->dm_active = DEVM_MODULE; + } + else { continue; + } + if (dm->dm_cmajor != -1) { - if (ht_lookup(cdevmtab, intern(dm->dm_name)) != NULL) { - cfgxerror(dm->dm_srcfile, dm->dm_srcline, - "device-major of character device '%s' " - "is already defined", dm->dm_name); + if (fixdevmtab_sub(0, cdevmtab, dm)) { error = 1; goto out; } - (void)snprintf(mstr, sizeof(mstr), "%d", dm->dm_cmajor); - if (ht_lookup(cdevmtab, intern(mstr)) != NULL) { - cfgxerror(dm->dm_srcfile, dm->dm_srcline, - "device-major of character major '%d' " - "is already defined", dm->dm_cmajor); - error = 1; - goto out; - } - if (ht_insert(cdevmtab, intern(dm->dm_name), dm) || - ht_insert(cdevmtab, intern(mstr), dm)) { - panic("fixdevsw: %s character major %d", - dm->dm_name, dm->dm_cmajor); - } } if (dm->dm_bmajor != -1) { - if (ht_lookup(bdevmtab, intern(dm->dm_name)) != NULL) { - cfgxerror(dm->dm_srcfile, dm->dm_srcline, - "device-major of block device '%s' " - "is already defined", dm->dm_name); + if (fixdevmtab_sub(1, bdevmtab, dm)) { error = 1; goto out; } - (void)snprintf(mstr, sizeof(mstr), "%d", dm->dm_bmajor); - if (ht_lookup(bdevmtab, intern(mstr)) != NULL) { - cfgxerror(dm->dm_srcfile, dm->dm_srcline, - "device-major of block major '%d' " - "is already defined", dm->dm_bmajor); - error = 1; - goto out; - } - if (ht_insert(bdevmtab, intern(dm->dm_name), dm) || - ht_insert(bdevmtab, intern(mstr), dm)) { - panic("fixdevsw: %s block major %d", - dm->dm_name, dm->dm_bmajor); - } } } @@ -433,6 +423,57 @@ return (error); } +static int +fixdevmtab_sub(int block, struct hashtab *ht, struct devm *dm) +{ + char mstrbuf[16]; + const char *mstr; + const char *type = block ? "block" : "character"; + int maj = block ? dm->dm_bmajor : dm->dm_cmajor; + struct devm *dm2; + const char *name = intern(dm->dm_name); + + dm2 = ht_lookup(ht, name); + if (dm2 == NULL) { + if (ht_insert(ht, name, dm)) + goto bad; + } + else if (dm->dm_active == DEVM_INKERNEL || + dm2->dm_active == DEVM_INKERNEL) { + cfgxerror(dm->dm_srcfile, dm->dm_srcline, + "device-major of %s device '%s' is already defined", + type, dm->dm_name); + return -1; + } + + (void)snprintf(mstrbuf, sizeof(mstrbuf), "%d", maj); + mstr = intern(mstrbuf); + dm2 = ht_lookup(ht, mstr); + if (dm2 == NULL) { + if (ht_insert(ht, mstr, dm)) + goto bad; + } + else if (dm2->dm_active == DEVM_INKERNEL || + dm->dm_active == DEVM_INKERNEL) { + cfgxerror(dm->dm_srcfile, dm->dm_srcline, + "device-major of %s major '%d' is already defined" + ": %s, %s", + type, maj, dm2->dm_name, dm->dm_name); + return -1; + } + +#if 0 + printf("%s: %s: bmajor=%d cmajor=%d\n", + __FUNCTION__, + dm->dm_name, dm->dm_bmajor, dm->dm_cmajor); +#endif + return 0; + bad: + panic("fixdevsw: ht_insert FAILED: %s %s major %d", dm->dm_name, type, maj); + /*NOTREACHED*/ + return -1; /* this is bogus */ +} + /* * Called when evaluating a needs-count expression. Make sure the * atom is a countable device. The expression succeeds iff there @@ -496,7 +537,7 @@ * No short circuiting ever occurs. fn must return 0 or 1 (otherwise * our mixing of C's bitwise & boolean here may give surprises). */ -static int +int expr_eval(struct nvlist *expr, int (*fn)(const char *, void *), void *context) { int lhs, rhs; @@ -555,15 +596,95 @@ } } +#if 0 +#define EXPR_STR_LEN 256 +/* + * Generate string form of expr. + * Returns the same string for logically equiverent exprs. ex: + * both a | b & c and c & b | a make "a|(b&c)". + * XXX: + * but it doesn't canonicalize !(a&b) and !a|!b to the same string. + */ +char * +expr_canonstr(struct nvlist *expr) +{ + char buf[EXPR_STR_LEN]; + + return estrdup(expr_canonstr_sub(expr, buf, sizeof buf)); +} + + +static char * +expr_canonstr_sub(struct nvlist *expr, char *buf, size_t buflen) +{ + char buf_r[EXPR_STR_LEN], buf_l[EXPR_STR_LEN]; + int op; + const char *lo, *lc, *ro, *rc; + + switch (expr->nv_int) { + case FX_ATOM: + snprintf(buf, buflen, "%s", expr->nv_name); + break; + case FX_NOT: + snprintf(buf, buflen, "!%s", expr_canonstr_sub(expr->nv_next, + buf_r, + sizeof buf_r)); + break; + case FX_AND: + case FX_OR: + lo = ro = ""; /* open */ + lc = rc = ""; /* close */ + + expr_canonstr_sub(expr->nv_ptr, buf_l, sizeof buf_l); + if (expr->nv_int < ((struct nvlist *)(expr->nv_ptr))->nv_int) { + lo = "("; lc = ")"; + } + + expr_canonstr_sub(expr->nv_next, buf_r, sizeof buf_r); + if (expr->nv_int < expr->nv_next->nv_int) { + ro = "("; rc = ")"; + } + + op = expr->nv_int == FX_AND ? '&' : '|'; + + if (strcmp(buf_l, buf_r) <= 0) + snprintf(buf, buflen, "%s%s%s%c%s%s%s", + lo, buf_l, lc, + op, + ro, buf_r, rc); + else + snprintf(buf, buflen, "%s%s%s%c%s%s%s", + ro, buf_r, rc, + op, + lo, buf_l, lc); + break; + default: + panic("expr_canonstr %d", expr->nv_int); + } + + return buf; +} +#endif + +static int +getlastc(const char *path) +{ + int len; + len = strlen(path); + if (len <= 0) + return '\0'; + return path[len-1]; +} + #ifdef DEBUG +static void pr0(); + /* * Print expression tree. */ void prexpr(struct nvlist *expr) { - static void pr0(); - printf("expr ="); pr0(expr); printf("\n");